aaron.ballman created this revision.
aaron.ballman added reviewers: jyknight, eli.friedman, hubert.reinterpretcast, 
erichkeane, clang-language-wg.
Herald added a subscriber: jdoerfert.
Herald added a project: All.
aaron.ballman requested review of this revision.
Herald added a project: clang.

Functions without prototypes in C (also known as K&R C functions) were 
introduced into C89 as a deprecated feature and C2x is now reclaiming that 
syntax space with different semantics. However, Clang's `-Wstrict-prototypes` 
diagnostic is off-by-default (even in pedantic mode) and does not suffice to 
warn users about issues in their code.

This patch changes the behavior of `-Wstrict-prototypes` to only diagnose 
declarations and definitions which are not going to change behavior in C2x 
mode, and enables the diagnostic in `-pedantic` mode. The diagnostic is now 
specifically about the fact that the feature is deprecated.

It also adds `-Wdeprecated-non-prototype`, which is grouped under 
`-Wstrict-prototypes` and diagnoses declarations or definitions which will 
change behavior in C2x mode. This diagnostic is enabled by default because the 
risk is higher for the user to continue to use the deprecated feature.

A few things to note:

- The RFC for this can be found at: 
https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c
- There is some awkward overlap between the diagnostics, but the best time to 
diagnose a function type without a prototype is when forming the function type, 
but we don't know whether the behavior will change in C2x at that point. So we 
alter the behavior sometimes depending on whether `-Wstrict-prototypes` is 
enabled in an effort to keep the diagnostics understandable and not too chatty.
- There will be another patch for handling call site behavior as a follow-up.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122895

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGen/2009-06-01-addrofknr.c
  clang/test/FixIt/fixit.c
  clang/test/Parser/declarators.c
  clang/test/Parser/knr_parameter_attributes.c
  clang/test/Parser/opencl-kernel.cl
  clang/test/Parser/traditional_arg_scope.c
  clang/test/Sema/arg-duplicate.c
  clang/test/Sema/block-return.c
  clang/test/Sema/implicit-decl.c
  clang/test/Sema/knr-def-call.c
  clang/test/Sema/knr-variadic-def.c
  clang/test/Sema/vfprintf-valid-redecl.c
  clang/test/Sema/warn-deprecated-non-prototype.c
  clang/test/Sema/warn-missing-prototypes.c
  clang/test/Sema/warn-strict-prototypes.c
  clang/test/Sema/warn-strict-prototypes.m
  clang/test/SemaOpenCL/address-spaces.cl
  clang/test/SemaOpenCL/cl20-device-side-enqueue.cl
  clang/test/SemaOpenCL/func.cl

Index: clang/test/SemaOpenCL/func.cl
===================================================================
--- clang/test/SemaOpenCL/func.cl
+++ clang/test/SemaOpenCL/func.cl
@@ -43,9 +43,9 @@
 #endif
 
 // Expect no diagnostics for an empty parameter list.
-void bar();
+void bar(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 
-void bar()
+void bar() // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 {
   // declaring a function pointer is an error
   void (*fptr)(int);
Index: clang/test/SemaOpenCL/cl20-device-side-enqueue.cl
===================================================================
--- clang/test/SemaOpenCL/cl20-device-side-enqueue.cl
+++ clang/test/SemaOpenCL/cl20-device-side-enqueue.cl
@@ -11,7 +11,7 @@
 
 typedef struct {int a;} ndrange_t;
 // Diagnostic tests for different overloads of enqueue_kernel from Table 6.13.17.1 of OpenCL 2.0 Spec.
-kernel void enqueue_kernel_tests() {
+kernel void enqueue_kernel_tests(void) {
   queue_t default_queue;
   unsigned flags = 0;
   QUALS ndrange_t ndrange;
@@ -169,7 +169,7 @@
 }
 
 // Diagnostic tests for get_kernel_work_group_size and allowed block parameter types in dynamic parallelism.
-kernel void work_group_size_tests() {
+kernel void work_group_size_tests(void) {
   void (^const block_A)(void) = ^{
     return;
   };
@@ -223,16 +223,22 @@
 kernel void foo(global unsigned int *buf)
 {
   ndrange_t n;
-  buf[0] = get_kernel_max_sub_group_size_for_ndrange(n, ^(){});
+  // FIXME: this should be diagnosed as a block instead of a function, but
+  // block literals don't track the ^ as part of their declarator.
+  buf[0] = get_kernel_max_sub_group_size_for_ndrange(n, ^(){}); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
   buf[0] = get_kernel_max_sub_group_size_for_ndrange(0, ^(){}); // expected-error{{illegal call to 'get_kernel_max_sub_group_size_for_ndrange', expected 'ndrange_t' argument type}}
+                                                                // expected-warning@-1 {{a function declaration without a prototype is deprecated in all versions of C}}
   buf[0] = get_kernel_max_sub_group_size_for_ndrange(n, 1); // expected-error{{illegal call to 'get_kernel_max_sub_group_size_for_ndrange', expected block argument type}}
 }
 
 kernel void bar(global unsigned int *buf)
 {
   __private ndrange_t n;
-  buf[0] = get_kernel_sub_group_count_for_ndrange(n, ^(){});
+  // FIXME: this should be diagnosed as a block instead of a function, but
+  // block literals don't track the ^ as part of their declarator.
+  buf[0] = get_kernel_sub_group_count_for_ndrange(n, ^(){}); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
   buf[0] = get_kernel_sub_group_count_for_ndrange(0, ^(){}); // expected-error{{illegal call to 'get_kernel_sub_group_count_for_ndrange', expected 'ndrange_t' argument type}}
+                                                             // expected-warning@-1 {{a function declaration without a prototype is deprecated in all versions of C}}
   buf[0] = get_kernel_sub_group_count_for_ndrange(n, 1); // expected-error{{illegal call to 'get_kernel_sub_group_count_for_ndrange', expected block argument type}}
 }
 
@@ -241,12 +247,18 @@
 kernel void foo1(global unsigned int *buf)
 {
   ndrange_t n;
+  // FIXME: this should be diagnosed as a block instead of a function, but
+  // block literals don't track the ^ as part of their declarator.
   buf[0] = get_kernel_max_sub_group_size_for_ndrange(n, ^(){}); // expected-error {{use of declaration 'get_kernel_max_sub_group_size_for_ndrange' requires cl_khr_subgroups or __opencl_c_subgroups support}}
+                                                                // expected-warning@-1 {{a function declaration without a prototype is deprecated in all versions of C}}
 }
 
 kernel void bar1(global unsigned int *buf)
 {
   ndrange_t n;
+  // FIXME: this should be diagnosed as a block instead of a function, but
+  // block literals don't track the ^ as part of their declarator.
   buf[0] = get_kernel_sub_group_count_for_ndrange(n, ^(){}); // expected-error {{use of declaration 'get_kernel_sub_group_count_for_ndrange' requires cl_khr_subgroups or __opencl_c_subgroups support}}
+                                                             // expected-warning@-1 {{a function declaration without a prototype is deprecated in all versions of C}}
 }
 #endif // ifdef cl_khr_subgroups
Index: clang/test/SemaOpenCL/address-spaces.cl
===================================================================
--- clang/test/SemaOpenCL/address-spaces.cl
+++ clang/test/SemaOpenCL/address-spaces.cl
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
-// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -pedantic -fsyntax-only
-// RUN: %clang_cc1 %s -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify=expected,c -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify=expected,c -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -verify=expected,c -pedantic -fsyntax-only
 // RUN: %clang_cc1 %s -cl-std=clc++1.0 -verify -pedantic -fsyntax-only
 // RUN: %clang_cc1 %s -cl-std=clc++2021 -cl-ext=+__opencl_c_generic_address_space -verify -pedantic -fsyntax-only
 
@@ -251,7 +251,7 @@
 
 void func_with_array_param(const unsigned data[16]);
 
-__kernel void k() {
+__kernel void k() { // c-warning {{a function declaration without a prototype is deprecated in all versions of C}}
   unsigned data[16];
   func_with_array_param(data);
 }
Index: clang/test/Sema/warn-strict-prototypes.m
===================================================================
--- clang/test/Sema/warn-strict-prototypes.m
+++ clang/test/Sema/warn-strict-prototypes.m
@@ -2,25 +2,28 @@
 
 @interface Foo
 
-@property (nonatomic, copy) void (^noProtoBlock)(); // expected-warning {{this block declaration is not a prototype}}
+@property (nonatomic, copy) void (^noProtoBlock)(); // expected-warning {{a block declaration without a prototype is deprecated}}
 @property (nonatomic, copy) void (^block)(void); // no warning
 
-- doStuff:(void (^)()) completionHandler; // expected-warning {{this block declaration is not a prototype}}
+- doStuff:(void (^)()) completionHandler; // expected-warning {{a block declaration without a prototype is deprecated}}
 - doOtherStuff:(void (^)(void)) completionHandler; // no warning
 
 @end
 
-void foo() { // expected-warning {{this old-style function definition is not preceded by a prototype}}
-  void (^block)() = // expected-warning {{this block declaration is not a prototype}}
+void foo() { // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+  void (^block)() = // expected-warning {{a block declaration without a prototype is deprecated}}
                     ^void(int arg) { // no warning
   };
-  void (^block2)(void) = ^void() { // no warning
+  // FIXME: this should say "a block declaration" instead, but block literal
+  // expressions do not track their full declarator information, so we don't
+  // know it's a block when diagnosing.
+  void (^block2)(void) = ^void() { // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
   };
   void (^block3)(void) = ^ { // no warning
   };
 }
 
-void (*(^(*(^block4)()) // expected-warning {{this block declaration is not a prototype}}
-     ()) // expected-warning {{this function declaration is not a prototype}}
-     ()) // expected-warning {{this block declaration is not a prototype}}
-     (); // expected-warning {{this function declaration is not a prototype}}
+void (*(^(*(^block4)()) // expected-warning {{a block declaration without a prototype is deprecated}}
+     ()) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+     ()) // expected-warning {{a block declaration without a prototype is deprecated}}
+     (); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
Index: clang/test/Sema/warn-strict-prototypes.c
===================================================================
--- clang/test/Sema/warn-strict-prototypes.c
+++ clang/test/Sema/warn-strict-prototypes.c
@@ -2,70 +2,70 @@
 // RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -Wstrict-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
 
 // function definition with 0 params, no prototype, no preceding declaration.
-void foo0() {} // expected-warning {{this old-style function definition is not preceded by a prototype}}
+void foo0() {} // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 
 // function declaration with unspecified params
-void foo1(); // expected-warning {{this function declaration is not a prototype}}
+void foo1(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
              // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:11}:"void"
 // function declaration with 0 params
 void foo2(void);
 
 // function definition with 0 params, no prototype.
-void foo1() {} // expected-warning {{this old-style function definition is not preceded by a prototype}}
+void foo1() {} // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 // function definition with 0 params, prototype.
 void foo2(void) {}
 
 // function type typedef unspecified params
-typedef void foo3(); // expected-warning {{this function declaration is not a prototype}}
+typedef void foo3(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
                      // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:19-[[@LINE-1]]:19}:"void"
 
 // global fp unspecified params
-void (*foo4)(); // expected-warning {{this function declaration is not a prototype}}
+void (*foo4)(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
                 // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"void"
 
 // struct member fp unspecified params
-struct { void (*foo5)(); } s; // expected-warning {{this function declaration is not a prototype}}
+struct { void (*foo5)(); } s; // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
                               // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:23-[[@LINE-1]]:23}:"void"
 
 // param fp unspecified params
-void bar2(void (*foo6)()) { // expected-warning {{this function declaration is not a prototype}}
+void bar2(void (*foo6)()) { // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
                             // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:24-[[@LINE-1]]:24}:"void"
   // local fp unspecified params
-  void (*foo7)() = 0; // expected-warning {{this function declaration is not a prototype}}
+  void (*foo7)() = 0; // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
                       // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"void"
   // array fp unspecified params
-  void (*foo8[2])() = {0}; // expected-warning {{this function declaration is not a prototype}}
+  void (*foo8[2])() = {0}; // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
                            // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:19-[[@LINE-1]]:19}:"void"
 }
 
 // function type cast using using an anonymous function declaration
 void bar3(void) {
   // casting function w/out prototype to unspecified params function type
-  (void)(void(*)()) foo1; // expected-warning {{this function declaration is not a prototype}}
+  (void)(void(*)()) foo1; // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
                           // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:18-[[@LINE-1]]:18}:"void"
   // .. specified params
   (void)(void(*)(void)) foo1;
 }
 
 // K&R function definition not preceded by full prototype
-int foo9(a, b) // expected-warning {{old-style function definition is not preceded by a prototype}}
+int foo9(a, b) // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
   int a, b;
 {
   return a + b;
 }
 
 // Function declaration with no types
-void foo10(); // expected-warning {{this function declaration is not a prototype}}
-              // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:12-[[@LINE-1]]:12}:"void"
+void foo10(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
+                 expected-note {{this function declaration without a prototype changes behavior in C2x}}
+              // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"void"
 // K&R function definition with incomplete param list declared
-void foo10(p, p2) void *p; {} // expected-warning {{old-style function definition is not preceded by a prototype}}
+void foo10(p, p2) void *p; {} // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 
-// K&R function definition with previous prototype declared is not diagnosed.
-void foo11(int p, int p2);
-void foo11(p, p2) int p; int p2; {}
+void foo11(int p, int p2);          // expected-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
+void foo11(p, p2) int p; int p2; {} // expected-note {{this function declaration without a prototype changes behavior in C2x}}
 
 // PR31020
-void __attribute__((cdecl)) foo12(d) // expected-warning {{this old-style function definition is not preceded by a prototype}}
+void __attribute__((cdecl)) foo12(d) // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
   short d;
 {}
 
Index: clang/test/Sema/warn-missing-prototypes.c
===================================================================
--- clang/test/Sema/warn-missing-prototypes.c
+++ clang/test/Sema/warn-missing-prototypes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wmissing-prototypes -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wmissing-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wmissing-prototypes -Wno-deprecated-non-prototype -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wmissing-prototypes -Wno-deprecated-non-prototype -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
 
 int f(); // expected-note{{this declaration is not a prototype; add parameter declarations to make it one}}
 // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:{{.*}}-[[@LINE-1]]:{{.*}}}:"{{.*}}"
Index: clang/test/Sema/warn-deprecated-non-prototype.c
===================================================================
--- /dev/null
+++ clang/test/Sema/warn-deprecated-non-prototype.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=both,expected %s
+// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -verify=both,strict %s
+
+// Test both with and without -Wstrict-prototypes because there are complicated
+// interactions between it and -Wdeprecated-non-prototype.
+
+// Off by default warnings, enabled by -pedantic or -Wstrict-prototypes
+void other_func();   // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+void other_func() {} // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+
+void never_defined(); // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+
+typedef void (*fp)(); // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+
+void blerp(
+  void (*func_ptr)() // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+);
+
+void whatever(void) {
+  extern void hoo_boy(); // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+}
+
+void again() {} // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+
+// On by default warnings
+void func();                 // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}} \
+                                strict-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
+                                strict-note {{this function declaration without a prototype changes behavior in C2x}}
+void func(a, b) int a, b; {} // both-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
+
+void one_more(a, b) int a, b; {} // both-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
+
+void sheesh(int a);      // both-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
+void sheesh(a) int a; {} // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}} \
+                            strict-note {{this function declaration without a prototype changes behavior in C2x}}
+
+void another(); // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+
+int main(void) {
+  another(1, 2); // OK for now
+}
+
+void order1();        // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}} \
+                         strict-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
+                         strict-note {{this function declaration without a prototype changes behavior in C2x}}
+void order1(int i);   // both-warning {{this function declaration with a prototype changes behavior in C2x because it is preceded by a function without a prototype}}
+
+void order2(int i);   // both-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
+void order2();        // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}} \
+                         strict-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
+                         strict-note {{this function declaration without a prototype changes behavior in C2x}}
+
+void order3();        // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}} \
+                         strict-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
+                         strict-note {{this function declaration without a prototype changes behavior in C2x}}
+void order3(int i) {} // both-warning {{this function declaration with a prototype changes behavior in C2x because it is preceded by a function without a prototype}}
+
+// Just because the prototype is variadic doesn't mean we shouldn't warn on the
+// K&R C function definition; this still changes behavior in C2x.
+void test(char*,...); // both-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
+void test(fmt)        // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}} \
+                         strict-note {{this function declaration without a prototype changes behavior in C2x}}
+        char*fmt;
+{
+}
+
Index: clang/test/Sema/vfprintf-valid-redecl.c
===================================================================
--- clang/test/Sema/vfprintf-valid-redecl.c
+++ clang/test/Sema/vfprintf-valid-redecl.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify
-// RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify -DPREDECLARE
+// RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify -std=c99
+// RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify -DPREDECLARE -std=c99
 
 #ifdef PREDECLARE
 // PR16344
@@ -12,7 +12,7 @@
 // PR4290
 // The following declaration is compatible with vfprintf, so we shouldn't
 // reject.
-int vfprintf();
+int vfprintf(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 #ifndef PREDECLARE
 // expected-warning@-2 {{requires inclusion of the header <stdio.h>}}
 #endif
Index: clang/test/Sema/knr-variadic-def.c
===================================================================
--- clang/test/Sema/knr-variadic-def.c
+++ clang/test/Sema/knr-variadic-def.c
@@ -1,12 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s -std=c99
 // PR4287
 
 #include <stdarg.h>
 char *foo = "test";
-int test(char*,...);
+int test(char*,...); // expected-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
 
-int test(fmt)
+int test(fmt) // expected-note {{this function declaration without a prototype changes behavior in C2x}}
         char*fmt;
 {
         va_list ap;
@@ -20,9 +19,12 @@
         return x;
 }
 
-void exit();
+// We get two diagnostics here because one comes from -Wstrict-prototypes and
+// the other comes from -Wdeprecated-non-prototype.
+void exit(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
+             // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 
-int main(argc,argv)
+int main(argc,argv) // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
         int argc;char**argv;
 {
         exit(test("",foo));
Index: clang/test/Sema/knr-def-call.c
===================================================================
--- clang/test/Sema/knr-def-call.c
+++ clang/test/Sema/knr-def-call.c
@@ -1,36 +1,38 @@
 // RUN: %clang_cc1 -triple i386-pc-unknown -Wconversion -Wliteral-conversion -fsyntax-only -verify %s
 
 // C DR #316, PR 3626.
-void f0(a, b, c, d) int a,b,c,d; {}
+void f0(a, b, c, d) int a,b,c,d; {} // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 void t0(void) {
   f0(1);  // expected-warning{{too few arguments}}
 }
 
-void f1(a, b) int a, b; {}
+void f1(a, b) int a, b; {} // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 void t1(void) {
   f1(1, 2, 3); // expected-warning{{too many arguments}}
 }
 
-void f2(float); // expected-note{{previous declaration is here}}
-void f2(x) float x; { } // expected-warning{{promoted type 'double' of K&R function parameter is not compatible with the parameter type 'float' declared in a previous prototype}}
+void f2(float); // expected-note{{previous declaration is here}} \
+                   expected-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
+void f2(x) float x; { } // expected-warning{{promoted type 'double' of K&R function parameter is not compatible with the parameter type 'float' declared in a previous prototype}} \
+                           expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 
 typedef void (*f3)(void);
 f3 t3(int b) { return b? f0 : f1; } // okay
 
 // <rdar://problem/8193107>
 void f4() {
-    char *rindex();
+    char *rindex(); // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 }
 
-char *rindex(s, c)
+char *rindex(s, c) // // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
      register char *s, c; // expected-warning{{promoted type 'char *' of K&R function parameter is not compatible with the parameter type 'const char *' declared in a previous prototype}}
 {
   return 0;
 }
 
 // PR8314
-void proto(int);
-void proto(x)
+void proto(int); // expected-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
+void proto(x) // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
      int x;
 {
 }
@@ -41,7 +43,8 @@
 }
 
 // PR31020
-void func(short d) __attribute__((cdecl)); // expected-note{{previous declaration is here}}
-void __attribute__((cdecl)) func(d)
+void func(short d) __attribute__((cdecl)); // expected-note{{previous declaration is here}} \
+                                              expected-warning {{this function declaration with a prototype changes behavior in C2x because it is followed by a function without a prototype}}
+void __attribute__((cdecl)) func(d) // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
   short d; // expected-warning{{promoted type 'int' of K&R function parameter is not compatible with the parameter type 'short' declared in a previous prototype}}
 {}
Index: clang/test/Sema/implicit-decl.c
===================================================================
--- clang/test/Sema/implicit-decl.c
+++ clang/test/Sema/implicit-decl.c
@@ -20,7 +20,9 @@
 
   __builtin_is_les(1, 3); // expected-error{{use of unknown builtin '__builtin_is_les'}}
 }
-Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error {{conflicting types}}
+// The implicit declaration for this has no prototype.
+Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error {{conflicting types}} \
+                                                                                                        // expected-warning {{this function declaration with a prototype changes behavior in C2x because it is preceded by a function without a prototype}}
  return 0;
 }
 
Index: clang/test/Sema/block-return.c
===================================================================
--- clang/test/Sema/block-return.c
+++ clang/test/Sema/block-return.c
@@ -99,6 +99,7 @@
 int (*funcptr3[5])(long);
 int sz8 = sizeof(^int (*[5])(long) {return funcptr3;}); // expected-error {{block cannot return array type}} expected-warning {{incompatible pointer to integer conversion}}
 int sz9 = sizeof(^int(*())()[3]{ }); // expected-error {{function cannot return array type}}
+                                     // expected-warning@-1 2 {{a function declaration without a prototype is deprecated in all versions of C}}
 
 void foo6(void) {
   int (^b)(int) __attribute__((noreturn));
Index: clang/test/Sema/arg-duplicate.c
===================================================================
--- clang/test/Sema/arg-duplicate.c
+++ clang/test/Sema/arg-duplicate.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c99
 
-int f3(y, x, 
+int f3(y, x,       // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
        x)          // expected-error {{redefinition of parameter}}
   int y, 
       x,           // expected-note {{previous declaration is here}}
Index: clang/test/Parser/traditional_arg_scope.c
===================================================================
--- clang/test/Parser/traditional_arg_scope.c
+++ clang/test/Parser/traditional_arg_scope.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -verify
+// RUN: %clang_cc1 -fsyntax-only %s -verify -Wno-deprecated-non-prototype -std=c99
 
 int x(a) int a; {return a;}
 int y(b) int b; {return a;} // expected-error {{use of undeclared identifier}}
Index: clang/test/Parser/opencl-kernel.cl
===================================================================
--- clang/test/Parser/opencl-kernel.cl
+++ clang/test/Parser/opencl-kernel.cl
@@ -1,10 +1,9 @@
 // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
-// expected-no-diagnostics
 
-__kernel void test()
+__kernel void test() // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 {
 }
 
-kernel void test1()
+kernel void test1() // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 {
 }
Index: clang/test/Parser/knr_parameter_attributes.c
===================================================================
--- clang/test/Parser/knr_parameter_attributes.c
+++ clang/test/Parser/knr_parameter_attributes.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -W -Wall -Werror -verify %s
+// RUN: %clang_cc1 -fsyntax-only -W -Wall -Wno-deprecated-non-prototype -Werror -verify %s -std=c99
 // expected-no-diagnostics
 
 int f(int i __attribute__((__unused__)))
Index: clang/test/Parser/declarators.c
===================================================================
--- clang/test/Parser/declarators.c
+++ clang/test/Parser/declarators.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -std=c99
 
 extern int a1[];
 
-void f0();
+void f0(); /* expected-warning {{a function declaration without a prototype is deprecated in all versions of C}} */
 void f1(int [*]);
 void f2(int [const *]);
 void f3(int [volatile const*]);
@@ -27,11 +27,12 @@
 }
 
 typedef int atype;
-void test3(x, 
+void test3(x,            /* expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}} */
            atype         /* expected-error {{unexpected type name 'atype': expected identifier}} */
           ) int x, atype; {}
 
-void test4(x, x) int x; {} /* expected-error {{redefinition of parameter 'x'}} */
+void test4(x, x) int x; {} // expected-error {{redefinition of parameter 'x'}} \
+                           // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 
 
 // PR3031
@@ -43,7 +44,9 @@
 
 foo_t *d;      // expected-error {{unknown type name 'foo_t'}}
 foo_t a;   // expected-error {{unknown type name 'foo_t'}}
-int test6() { return a; }  // a should be declared.
+int test6() { /* expected-warning {{a function declaration without a prototype is deprecated in all versions of C}} */
+  return a; // a should be declared.
+}
 
 // Use of tagged type without tag. rdar://6783347
 struct xyz { int y; };
@@ -51,13 +54,13 @@
 xyz b;         // expected-error {{must use 'struct' tag to refer to type 'xyz'}}
 myenum c;      // expected-error {{must use 'enum' tag to refer to type 'myenum'}}
 
-float *test7() {
+float *test7(void) {
   // We should recover 'b' by parsing it with a valid type of "struct xyz", which
   // allows us to diagnose other bad things done with y, such as this.
   return &b.y;   // expected-warning {{incompatible pointer types returning 'int *' from a function with result type 'float *'}}
 }
 
-struct xyz test8() { return a; }  // a should be be marked invalid, no diag.
+struct xyz test8(void) { return a; }  // a should be be marked invalid, no diag.
 
 
 // Verify that implicit int still works.
@@ -78,7 +81,7 @@
 struct test11 { int a; } const test11x;
 
 // PR6216
-void test12() {
+void test12(void) {
   (void)__builtin_offsetof(struct { char c; int i; }, i);
 }
 
@@ -91,21 +94,23 @@
 
 // PR7617 - error recovery on missing ;.
 
-void test14()  // expected-error {{expected ';' after top level declarator}}
+void test14(void)  // expected-error {{expected ';' after top level declarator}}
 
-void test14a();
+void test14a(void);
 void *test14b = (void*)test14a; // Make sure test14a didn't get skipped.
 
 // rdar://problem/8358508
-long struct X { int x; } test15(); // expected-error {{'long struct' is invalid}}
-
-void test16(i) int i j; { } // expected-error {{expected ';' at end of declaration}}
-void test17(i, j) int i, j k; { } // expected-error {{expected ';' at end of declaration}}
-void knrNoSemi(i) int i { } // expected-error {{expected ';' at end of declaration}}
+long struct X { int x; } test15(void); // expected-error {{'long struct' is invalid}}
 
+void test16(i) int i j; { } // expected-error {{expected ';' at end of declaration}} \
+                            // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
+void test17(i, j) int i, j k; { } // expected-error {{expected ';' at end of declaration}} \
+                                  // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
+void knrNoSemi(i) int i { } // expected-error {{expected ';' at end of declaration}} \
+                            // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
 
 // PR12595
-void test18() {
+void test18(void) {
   int x = 4+(5-12));  // expected-error {{extraneous ')' before ';'}}
 }
 
Index: clang/test/FixIt/fixit.c
===================================================================
--- clang/test/FixIt/fixit.c
+++ clang/test/FixIt/fixit.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -pedantic -Wunused-label -verify -x c %s
+// RUN: %clang_cc1 -pedantic -Wunused-label -Wno-deprecated-non-prototype -verify -x c %s
 // RUN: cp %s %t
 // RUN: not %clang_cc1 -pedantic -Wunused-label -fixit -x c %t
-// RUN: %clang_cc1 -pedantic -Wunused-label -Werror -x c %t
+// RUN: %clang_cc1 -pedantic -Wunused-label -Wno-deprecated-non-prototype -Werror -x c %t
 // RUN: grep -v CHECK %t | FileCheck %t
 
 /* This is a test of the various code modification hints that are
Index: clang/test/CodeGen/2009-06-01-addrofknr.c
===================================================================
--- clang/test/CodeGen/2009-06-01-addrofknr.c
+++ clang/test/CodeGen/2009-06-01-addrofknr.c
@@ -1,12 +1,11 @@
-// RUN: %clang_cc1 %s -o %t -emit-llvm -verify
-// expected-no-diagnostics
+// RUN: %clang_cc1 %s -o %t -emit-llvm -verify -std=c89
 // PR4289
 
 struct funcptr {
   int (*func)();
 };
 
-static int func(f)
+static int func(f) // expected-warning {{this function declaration without a prototype is deprecated in all versions of C and changes behavior in C2x}}
   void *f;
 {
   return 0;
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -5548,15 +5548,18 @@
            diag::warn_noderef_on_non_pointer_or_array);
 
   // GNU warning -Wstrict-prototypes
-  //   Warn if a function declaration is without a prototype.
+  //   Warn if a function declaration or definition is without a prototype.
   //   This warning is issued for all kinds of unprototyped function
   //   declarations (i.e. function type typedef, function pointer etc.)
   //   C99 6.7.5.3p14:
   //   The empty list in a function declarator that is not part of a definition
   //   of that function specifies that no information about the number or types
   //   of the parameters is supplied.
+  // See ActOnFinishFunctionBody() and MergeFunctionDecl() for handling of
+  // function declarations whose behavior changes in C2x.
   if (!LangOpts.CPlusPlus &&
-      D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration) {
+      (D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration ||
+       D.getFunctionDefinitionKind() == FunctionDefinitionKind::Definition)) {
     bool IsBlock = false;
     for (const DeclaratorChunk &DeclType : D.type_objects()) {
       switch (DeclType.Kind) {
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -3856,39 +3856,110 @@
 
   // C: Function types need to be compatible, not identical. This handles
   // duplicate function decls like "void f(int); void f(enum X);" properly.
-  if (!getLangOpts().CPlusPlus &&
-      Context.typesAreCompatible(OldQType, NewQType)) {
-    const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
-    const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
-    const FunctionProtoType *OldProto = nullptr;
-    if (MergeTypeWithOld && isa<FunctionNoProtoType>(NewFuncType) &&
-        (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
-      // The old declaration provided a function prototype, but the
-      // new declaration does not. Merge in the prototype.
-      assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
-      SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
-      NewQType =
-          Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
-                                  OldProto->getExtProtoInfo());
-      New->setType(NewQType);
-      New->setHasInheritedPrototype();
-
-      // Synthesize parameters with the same types.
-      SmallVector<ParmVarDecl*, 16> Params;
-      for (const auto &ParamType : OldProto->param_types()) {
-        ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(),
-                                                 SourceLocation(), nullptr,
-                                                 ParamType, /*TInfo=*/nullptr,
-                                                 SC_None, nullptr);
-        Param->setScopeInfo(0, Params.size());
-        Param->setImplicit();
-        Params.push_back(Param);
+  if (!getLangOpts().CPlusPlus) {
+    // If we are merging two functions where only one of them has a prototype,
+    // we may have enough information to decide to issue a diagnostic that the
+    // function without a protoype will change behavior in C2x. This handles
+    // cases like:
+    //   void i(); void i(int j);
+    //   void i(int j); void i();
+    //   void i(); void i(int j) {}
+    // See ActOnFinishFunctionBody() for other cases of the behavior change
+    // diagnostic. See GetFullTypeForDeclarator() for handling of a function
+    // type without a prototype.
+    if (New->hasWrittenPrototype() != Old->hasWrittenPrototype()) {
+      const FunctionDecl *WithProto, *WithoutProto;
+      if (New->hasWrittenPrototype()) {
+        WithProto = New;
+        WithoutProto = Old;
+      } else {
+        WithProto = Old;
+        WithoutProto = New;
       }
 
-      New->setParams(Params);
+      if (WithProto->getNumParams() != 0) {
+        // The function definition has parameters, so this will change
+        // behavior in C2x.
+        // FIXME: The declaration may have already been diagnosed as being
+        // deprecated in GetFullTypeForDeclarator() if it had no arguments,
+        // but there's no way to test for the "changes behavior" condition in
+        // SemaType.cpp when forming the declaration's function type. So, we
+        // do this awkward dance instead.
+        //
+        // If we already warned about about the function without a prototype
+        // being deprecated, add a note that it also changes behavior. If we
+        // didn't warn about it being deprecated (because the diagnostic is
+        // not enabled), warn now that it is deprecated and changes behavior.
+        bool AddNote = false;
+        if (Diags.isIgnored(diag::warn_strict_prototypes,
+                            WithoutProto->getLocation())) {
+          if (WithoutProto->getBuiltinID() == 0 &&
+              !WithoutProto->isImplicit()) {
+            PartialDiagnostic PD =
+                PDiag(diag::warn_non_prototype_changes_behavior);
+            if (TypeSourceInfo *TSI = WithoutProto->getTypeSourceInfo()) {
+              if (auto FTL = TSI->getTypeLoc().getAs<FunctionNoProtoTypeLoc>())
+                PD << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+            }
+            Diag(WithoutProto->getLocation(), PD);
+          }
+        } else {
+          AddNote = true;
+        }
+
+        // Because the function with a prototype has parameters but a previous
+        // declaration had none, the function with the prototype will also
+        // change behavior in C2x.
+        if (WithProto->getBuiltinID() == 0 && !WithProto->isImplicit()) {
+          Diag(WithProto->getLocation(), diag::warn_prototype_changes_behavior)
+              << SourceMgr.isBeforeInTranslationUnit(
+                     WithProto->getLocation(), WithoutProto->getLocation());
+          if (AddNote && WithoutProto->getBuiltinID() == 0)
+            Diag(WithoutProto->getLocation(),
+                 diag::note_func_decl_changes_behavior);
+        } else if (AddNote && WithoutProto->getBuiltinID() == 0 &&
+                   !WithoutProto->isImplicit()) {
+          // If we were supposed to add a note but the function with a
+          // prototype is a builtin, we have nothing to attach the note to, so
+          // we issue a warning instead.
+          Diag(WithoutProto->getLocation(),
+               diag::warn_non_prototype_changes_behavior);
+        }
+      }
     }
 
-    return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
+    if (Context.typesAreCompatible(OldQType, NewQType)) {
+      const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
+      const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
+      const FunctionProtoType *OldProto = nullptr;
+      if (MergeTypeWithOld && isa<FunctionNoProtoType>(NewFuncType) &&
+          (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
+        // The old declaration provided a function prototype, but the
+        // new declaration does not. Merge in the prototype.
+        assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
+        SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
+        NewQType =
+            Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
+                                    OldProto->getExtProtoInfo());
+        New->setType(NewQType);
+        New->setHasInheritedPrototype();
+
+        // Synthesize parameters with the same types.
+        SmallVector<ParmVarDecl *, 16> Params;
+        for (const auto &ParamType : OldProto->param_types()) {
+          ParmVarDecl *Param = ParmVarDecl::Create(
+              Context, New, SourceLocation(), SourceLocation(), nullptr,
+              ParamType, /*TInfo=*/nullptr, SC_None, nullptr);
+          Param->setScopeInfo(0, Params.size());
+          Param->setImplicit();
+          Params.push_back(Param);
+        }
+
+        New->setParams(Params);
+      }
+
+      return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
+    }
   }
 
   // Check if the function types are compatible when pointer size address
@@ -14815,18 +14886,63 @@
                       ? FixItHint::CreateInsertion(findBeginLoc(), "static ")
                       : FixItHint{});
         }
+      }
 
-        // GNU warning -Wstrict-prototypes
-        //   Warn if K&R function is defined without a previous declaration.
-        //   This warning is issued only if the definition itself does not
-        //   provide a prototype. Only K&R definitions do not provide a
-        //   prototype.
-        if (!FD->hasWrittenPrototype()) {
-          TypeSourceInfo *TI = FD->getTypeSourceInfo();
-          TypeLoc TL = TI->getTypeLoc();
-          FunctionTypeLoc FTL = TL.getAsAdjusted<FunctionTypeLoc>();
-          Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2;
+      // If the function being defined does not have a prototype, then we may
+      // need to diagnose it as changing behavior in C2x because we now know
+      // whether the function accepts arguments or not. This only handles the
+      // case where the definition has no prototype but does have parameters
+      // and either there is no previous potential prototype, or the previous
+      // potential prototype also has no actual prototype. This handles cases
+      // like:
+      //   void f(); void f(a) int a; {}
+      //   void g(a) int a; {}
+      // See MergeFunctionDecl() for other cases of the behavior change
+      // diagnostic. See GetFullTypeForDeclarator() for handling of a function
+      // type without a prototype.
+      if (!FD->hasWrittenPrototype() && FD->getNumParams() != 0 &&
+          (!PossiblePrototype || (!PossiblePrototype->hasWrittenPrototype() &&
+                                  !PossiblePrototype->isImplicit()))) {
+        // The function definition has parameters, so this will change behavior
+        // in C2x. If there is a possible prototype, it comes before the
+        // function definition.
+        // FIXME: The declaration may have already been diagnosed as being
+        // deprecated in GetFullTypeForDeclarator() if it had no arguments, but
+        // there's no way to test for the "changes behavior" condition in
+        // SemaType.cpp when forming the declaration's function type. So, we do
+        // this awkward dance instead.
+        //
+        // If we have a possible prototype and it declares a function with a
+        // prototype, we don't want to diagnose it; if we have a possible
+        // prototype and it has no prototype, it may have already been
+        // diagnosed in SemaType.cpp as deprecated depending on whether
+        // -Wstrict-prototypes is enabled. If we already warned about it being
+        // deprecated, add a note that it also changes behavior. If we didn't
+        // warn about it being deprecated (because the diagnostic is not
+        // enabled), warn now that it is deprecated and changes behavior.
+        bool AddNote = false;
+        if (PossiblePrototype) {
+          if (Diags.isIgnored(diag::warn_strict_prototypes,
+                              PossiblePrototype->getLocation())) {
+
+            PartialDiagnostic PD =
+                PDiag(diag::warn_non_prototype_changes_behavior);
+            if (TypeSourceInfo *TSI = PossiblePrototype->getTypeSourceInfo()) {
+              if (auto FTL = TSI->getTypeLoc().getAs<FunctionNoProtoTypeLoc>())
+                PD << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+            }
+            Diag(PossiblePrototype->getLocation(), PD);
+          } else {
+            AddNote = true;
+          }
         }
+
+        // Because this function definition has no prototype and it has
+        // parameters, it will definitely change behavior in C2x.
+        Diag(FD->getLocation(), diag::warn_non_prototype_changes_behavior);
+        if (AddNote)
+          Diag(PossiblePrototype->getLocation(),
+               diag::note_func_decl_changes_behavior);
       }
 
       // Warn on CPUDispatch with an actual body.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5557,10 +5557,20 @@
 def note_declaration_not_a_prototype : Note<
   "this declaration is not a prototype; add %select{'void'|parameter declarations}0 "
   "to make it %select{a prototype for a zero-parameter function|one}0">;
-def warn_strict_prototypes : Warning<
-  "this %select{function declaration is not|block declaration is not|"
-  "old-style function definition is not preceded by}0 a prototype">,
-  InGroup<DiagGroup<"strict-prototypes">>, DefaultIgnore;
+// This is not actually an extension, but we only want it to be enabled in
+// -pedantic mode and this is the most direct way of accomplishing that.
+def warn_strict_prototypes : Extension<
+  "a %select{function|block}0 declaration without a prototype is deprecated "
+  "%select{in all versions of C|}0">, InGroup<StrictPrototypes>;
+def warn_non_prototype_changes_behavior : Warning<
+  "this function declaration without a prototype is deprecated in all versions "
+  "of C and changes behavior in C2x">, InGroup<DeprecatedNonPrototype>;
+def warn_prototype_changes_behavior : Warning<
+  "this function declaration with a prototype changes behavior in C2x because "
+  "it is %select{preceded|followed}0 by a function without a prototype">,
+  InGroup<DeprecatedNonPrototype>;
+def note_func_decl_changes_behavior : Note<
+  "this function declaration without a prototype changes behavior in C2x">;
 def warn_missing_variable_declarations : Warning<
   "no previous extern declaration for non-static variable %0">,
   InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -444,6 +444,8 @@
 def InvalidNoreturn : DiagGroup<"invalid-noreturn">;
 def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">;
 def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
+def DeprecatedNonPrototype : DiagGroup<"deprecated-non-prototype">;
+def StrictPrototypes : DiagGroup<"strict-prototypes", [DeprecatedNonPrototype]>;
 def : DiagGroup<"init-self">;
 def : DiagGroup<"inline">;
 def : DiagGroup<"invalid-pch">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -110,7 +110,15 @@
   <https://github.com/llvm/llvm-project/issues/50794>`_.
 - ``-Wunused-but-set-variable`` now also warns if the variable is only used
   by unary operators.
-
+- Modified the behavior of ``-Wstrict-prototypes`` and added a new, related
+  diagnostic ``-Wdeprecated-non-prototype``. The strict prototypes warning will
+  now only diagnose deprecated declarations and definitions of functions
+  without a prototype where the behavior in C2x will remain correct. This
+  diagnostic remains off by default but is now enabled via ``-pedantic`` due to
+  it being a deprecation warning. ``-Wdeprecated-non-prototype`` will diagnose
+  cases where the deprecated declarations or definitions of a function without
+  a prototype will change behavior in C2x. This diagnostic is grouped under the
+  ``-Wstrict-prototypes`` warning group, but is enabled by default.
 - ``-Wmisexpect`` warns when the branch weights collected during profiling
   conflict with those added by ``llvm.expect``.
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to