diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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; 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; -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; +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>, DefaultIgnore; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/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()) - 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 a definition 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); } } } @@ -15053,29 +15023,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()) - 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. diff --git a/clang/test/C/drs/dr0xx.c b/clang/test/C/drs/dr0xx.c --- a/clang/test/C/drs/dr0xx.c +++ b/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; { } diff --git a/clang/test/CodeGen/2009-06-01-addrofknr.c b/clang/test/CodeGen/2009-06-01-addrofknr.c --- a/clang/test/CodeGen/2009-06-01-addrofknr.c +++ b/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; diff --git a/clang/test/Parser/declarators.c b/clang/test/Parser/declarators.c --- a/clang/test/Parser/declarators.c +++ b/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) { diff --git a/clang/test/Sema/arg-duplicate.c b/clang/test/Sema/arg-duplicate.c --- a/clang/test/Sema/arg-duplicate.c +++ b/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}} diff --git a/clang/test/Sema/knr-def-call.c b/clang/test/Sema/knr-def-call.c --- a/clang/test/Sema/knr-def-call.c +++ b/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}} {} diff --git a/clang/test/Sema/knr-variadic-def.c b/clang/test/Sema/knr-variadic-def.c --- a/clang/test/Sema/knr-variadic-def.c +++ b/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)); diff --git a/clang/test/Sema/warn-deprecated-non-prototype.c b/clang/test/Sema/warn-deprecated-non-prototype.c --- a/clang/test/Sema/warn-deprecated-non-prototype.c +++ b/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}} diff --git a/clang/test/Sema/warn-strict-prototypes.c b/clang/test/Sema/warn-strict-prototypes.c --- a/clang/test/Sema/warn-strict-prototypes.c +++ b/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; {}