aaron.ballman updated this revision to Diff 432020.
aaron.ballman added a comment.

Update based on review feedback.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125814/new/

https://reviews.llvm.org/D125814

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDecl.cpp
  clang/test/C/drs/dr0xx.c
  clang/test/CodeGen/2009-06-01-addrofknr.c
  clang/test/Parser/declarators.c
  clang/test/Sema/arg-duplicate.c
  clang/test/Sema/knr-def-call.c
  clang/test/Sema/knr-variadic-def.c
  clang/test/Sema/warn-deprecated-non-prototype.c
  clang/test/Sema/warn-strict-prototypes.c

Index: clang/test/Sema/warn-strict-prototypes.c
===================================================================
--- clang/test/Sema/warn-strict-prototypes.c
+++ clang/test/Sema/warn-strict-prototypes.c
@@ -48,7 +48,7 @@
 }
 
 // K&R function definition not preceded by full prototype
-int foo9(a, b) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+int foo9(a, b) // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
   int a, b;
 {
   return a + b;
@@ -56,17 +56,17 @@
 
 // Function declaration with no types
 void foo10(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
-                 expected-note {{a function declaration without a prototype is not supported in C2x}}
+                 expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C2x, conflicting with a subsequent definition}}
               // 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 {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} \
+void foo10(p, p2) void *p; {} // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}} \
                                  expected-warning {{parameter 'p2' was not declared, defaults to 'int'; ISO C99 and later do not support implicit int}}
 
 void foo11(int p, int p2);
-void foo11(p, p2) int p; int p2; {} // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void foo11(p, p2) int p; int p2; {} // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 
 // PR31020
-void __attribute__((cdecl)) foo12(d) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void __attribute__((cdecl)) foo12(d) // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
   short d;
 {}
 
Index: clang/test/Sema/warn-deprecated-non-prototype.c
===================================================================
--- clang/test/Sema/warn-deprecated-non-prototype.c
+++ clang/test/Sema/warn-deprecated-non-prototype.c
@@ -23,15 +23,14 @@
 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 {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} \
-                                strict-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
-                                strict-note {{a function declaration without a prototype is not supported in C2x}}
-void func(a, b) int a, b; {} // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void func();                 // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C2x, conflicting with a subsequent definition}} \
+                                strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+void func(a, b) int a, b; {} // both-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 
-void one_more(a, b) int a, b; {} // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void one_more(a, b) int a, b; {} // both-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 
 void sheesh(int a);
-void sheesh(a) int a; {} // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void sheesh(a) int a; {} // both-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 
 void another(); // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 
@@ -39,35 +38,26 @@
   another(1, 2);  // both-warning {{passing arguments to 'another' without a prototype is deprecated in all versions of C and is not supported in C2x}}
 }
 
-void order1();        // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} \
-                         strict-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
-                         strict-note {{a function declaration without a prototype is not supported in C2x}}
-void order1(int i);   // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void order1();        // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C2x, conflicting with a subsequent declaration}} \
+                         strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+void order1(int i);   // both-note {{conflicting prototype is here}}
 
-void order2(int i);
-void order2();        // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} \
+void order2(int i);   // both-note {{conflicting prototype is here}}
+void order2();        // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C2x, conflicting with a previous declaration}} \
                          strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 
-void order3();        // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} \
-                         strict-warning {{a function declaration without a prototype is deprecated in all versions of C}} \
-                         strict-note {{a function declaration without a prototype is not supported in C2x}}
-void order3(int i) {} // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void order3();        // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is treated as a zero-parameter prototype in C2x, conflicting with a subsequent definition}} \
+                         strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+void order3(int i) {} // both-note {{conflicting prototype is here}}
 
 // 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*,...);
-void test(fmt)        // both-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void test(fmt)        // both-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
         char*fmt;
 {
 }
 
-// FIXME: we get two diagnostics here when running in pedantic mode. The first
-// comes when forming the function type for the definition, and the second
-// comes from merging the function declarations together. The second is the
-// point at which we know the behavior has changed (because we can see the
-// previous declaration at that point), but we've already issued the type
-// error by that point. It's not ideal to be this chatty, but this situation
-// should be pretty rare.
 void blapp(int); // both-note {{previous declaration is here}}
 void blapp() { } // both-error {{conflicting types for 'blapp'}} \
                  // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
Index: clang/test/Sema/knr-variadic-def.c
===================================================================
--- clang/test/Sema/knr-variadic-def.c
+++ clang/test/Sema/knr-variadic-def.c
@@ -5,7 +5,7 @@
 char *foo = "test";
 int test(char*,...);
 
-int test(fmt) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+int test(fmt) // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
         char*fmt;
 {
         va_list ap;
@@ -21,7 +21,7 @@
 
 void exit(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 
-int main(argc,argv) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+int main(argc,argv) // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported 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,19 +1,19 @@
 // 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; {} // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void f0(a, b, c, d) int a,b,c,d; {} // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 void t0(void) {
   f0(1);  // expected-warning{{too few arguments}}
 }
 
-void f1(a, b) int a, b; {} // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void f1(a, b) int a, b; {} // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported 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}} \
-                           expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+                           expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 
 typedef void (*f3)(void);
 f3 t3(int b) { return b? f0 : f1; } // okay
@@ -33,7 +33,7 @@
 
 // PR8314
 void proto(int);
-void proto(x) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void proto(x) // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
      int x;
 {
 }
@@ -45,6 +45,6 @@
 
 // PR31020
 void func(short d) __attribute__((cdecl)); // expected-note{{previous declaration is here}}
-void __attribute__((cdecl)) func(d) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+void __attribute__((cdecl)) func(d) // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported 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/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 -std=c99
 
-int f3(y, x,       // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+int f3(y, x,       // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
        x)          // expected-error {{redefinition of parameter}}
   int y, 
       x,           // expected-note {{previous declaration is here}}
Index: clang/test/Parser/declarators.c
===================================================================
--- clang/test/Parser/declarators.c
+++ clang/test/Parser/declarators.c
@@ -27,12 +27,12 @@
 }
 
 typedef int atype;
-void test3(x,            /* expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} */
+void test3(x,            /* expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported 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'}} \
-                           // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+                           // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 
 
 // PR3031
@@ -103,11 +103,11 @@
 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 {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+                            // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 void test17(i, j) int i, j k; { } // expected-error {{expected ';' at end of declaration}} \
-                                  // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+                                  // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 void knrNoSemi(i) int i { } // expected-error {{expected ';' at end of declaration}} \
-                            // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+                            // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
 
 // PR12595
 void test18(void) {
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
@@ -5,7 +5,7 @@
   int (*func)();
 };
 
-static int func(f) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}}
+static int func(f) // expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}}
   void *f;
 {
   return 0;
Index: clang/test/C/drs/dr0xx.c
===================================================================
--- clang/test/C/drs/dr0xx.c
+++ clang/test/C/drs/dr0xx.c
@@ -231,13 +231,13 @@
 /* WG14 DR035: partial
  * Questions about definition of functions without a prototype
  */
-void dr035_1(a, b) /* expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} */
+void dr035_1(a, b) /* expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}} */
   int a(enum b {x, y}); /* expected-warning {{declaration of 'enum b' will not be visible outside of this function}} */
   int b; {
   int test = x; /* expected-error {{use of undeclared identifier 'x'}} */
 }
 
-void dr035_2(c) /* expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} */
+void dr035_2(c) /* expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}} */
   enum m{q, r} c; { /* expected-warning {{declaration of 'enum m' will not be visible outside of this function}} */
   /* FIXME: This should be accepted because the scope of m, q, and r ends at
    * the closing brace of the function per C89 6.1.2.1.
@@ -391,7 +391,7 @@
  * a prototype causes implicit conversions rather than relying on default
  * argument promotion and warm thoughts.
  */
-void dr070_1(c) /* expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} */
+void dr070_1(c) /* expected-warning {{a function definition without a prototype is deprecated in all versions of C and is not supported in C2x}} */
   int c; {
 }
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -3940,59 +3940,29 @@
       }
 
       if (WithProto->getNumParams() != 0) {
-        // The function definition has parameters, so this will change
-        // behavior in C2x.
-        //
-        // 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() &&
-              SourceMgr.isBeforeInTranslationUnit(WithoutProto->getLocation(),
-                                                  WithProto->getLocation())) {
-            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()) {
-          if (SourceMgr.isBeforeInTranslationUnit(
-                  WithProto->getLocation(), WithoutProto->getLocation())) {
-            // If the function with the prototype comes before the function
-            // without the prototype, we only want to diagnose the one without
-            // the prototype.
-            Diag(WithoutProto->getLocation(),
-                 diag::warn_non_prototype_changes_behavior);
-          } else {
-            // Otherwise, diagnose the one with the prototype, and potentially
-            // attach a note to the one without a prototype if needed.
-            Diag(WithProto->getLocation(),
-                 diag::warn_non_prototype_changes_behavior);
-            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 or was implicitly declared, which means we
-          // have nothing to attach the note to, so we issue a warning instead.
+        if (WithoutProto->getBuiltinID() == 0 && !WithoutProto->isImplicit()) {
+          // The one without the prototype will be changing behavior in C2x, so
+          // warn about that one so long as it's a user-visible declaration.
+          bool IsWithoutProtoADef = false, IsWithProtoADef = false;
+          if (WithoutProto == New)
+            IsWithoutProtoADef = NewDeclIsDefn;
+          else
+            IsWithProtoADef = NewDeclIsDefn;
           Diag(WithoutProto->getLocation(),
-               diag::warn_non_prototype_changes_behavior);
+               diag::warn_non_prototype_changes_behavior)
+              << IsWithoutProtoADef << (WithoutProto->getNumParams() ? 0 : 1)
+              << (WithoutProto == Old) << IsWithProtoADef;
+
+          // The reason the one without the prototype will be changing behavior
+          // is because of the one with the prototype, so note that so long as
+          // it's a user-visible declaration. There is one exception to this:
+          // when the new declaration is one without a prototype, the old
+          // declaration with a prototype is not the cause of the issue, and
+          // that does not need to be noted because the one with a prototype
+          // will not change behavior in C2x.
+          if (WithProto->getBuiltinID() == 0 && !WithProto->isImplicit() &&
+              !IsWithoutProtoADef)
+            Diag(WithProto->getLocation(), diag::note_conflicting_prototype);
         }
       }
     }
@@ -15054,29 +15024,22 @@
         // 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)
+        // This K&R C function definition definitely changes behavior in C2x,
+        // so diagnose it.
+        Diag(FD->getLocation(), diag::warn_non_prototype_changes_behavior)
+            << /*definition*/ 1 << /* not supported in C2x */ 0;
+
+        // If we have a possible prototype for the function which is a user-
+        // visible declaration, we already tested that it has no prototype.
+        // This will change behavior in C2x. This gets a warning rather than a
+        // note because it's the same behavior-changing problem as with the
+        // definition.
+        if (PossiblePrototype)
           Diag(PossiblePrototype->getLocation(),
-               diag::note_func_decl_changes_behavior);
+               diag::warn_non_prototype_changes_behavior)
+              << /*declaration*/ 0 << /* conflicting */ 1 << /*subsequent*/ 1
+              << /*definition*/ 1;
       }
 
       // 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
@@ -5589,10 +5589,12 @@
   "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<
-  "a function declaration without a prototype is deprecated in all versions of "
-  "C and is not supported in C2x">, InGroup<DeprecatedNonPrototype>;
-def note_func_decl_changes_behavior : Note<
-  "a function declaration without a prototype is not supported in C2x">;
+  "a function %select{declaration|definition}0 without a prototype is "
+  "deprecated in all versions of C %select{and is not supported in C2x|and is "
+  "treated as a zero-parameter prototype in C2x, conflicting with a "
+  "%select{previous|subsequent}2 %select{declaration|definition}3}1">,
+  InGroup<DeprecatedNonPrototype>;
+def note_conflicting_prototype : Note<"conflicting prototype is here">;
 def warn_missing_variable_declarations : Warning<
   "no previous extern declaration for non-static variable %0">,
   InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to