diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -129,6 +129,15 @@ - ``-Wunused-variable`` no longer warn for references extending the lifetime of temporaries with side effects. This fixes `Issue 54489 `_. +- 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. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/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">; 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 @@ -5560,10 +5560,16 @@ 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>, 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; +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">; 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 @@ -3879,39 +3879,118 @@ // 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(); - const FunctionType *NewFuncType = NewQType->getAs(); - const FunctionProtoType *OldProto = nullptr; - if (MergeTypeWithOld && isa(NewFuncType) && - (OldProto = dyn_cast(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 ParamTypes(OldProto->param_types()); - NewQType = - Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes, - OldProto->getExtProtoInfo()); - New->setType(NewQType); - New->setHasInheritedPrototype(); - - // Synthesize parameters with the same types. - SmallVector 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() && + !New->isImplicit() && !Old->isImplicit()) { + 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. + // + // 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. + 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(); + const FunctionType *NewFuncType = NewQType->getAs(); + const FunctionProtoType *OldProto = nullptr; + if (MergeTypeWithOld && isa(NewFuncType) && + (OldProto = dyn_cast(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 ParamTypes(OldProto->param_types()); + NewQType = + Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes, + OldProto->getExtProtoInfo()); + New->setType(NewQType); + New->setHasInheritedPrototype(); + + // Synthesize parameters with the same types. + SmallVector 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 @@ -14838,18 +14917,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(); - 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()) + 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. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5548,15 +5548,16 @@ 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. - if (!LangOpts.CPlusPlus && - D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration) { + // See ActOnFinishFunctionBody() and MergeFunctionDecl() for handling of + // function declarations whose behavior changes in C2x. + if (!LangOpts.CPlusPlus) { bool IsBlock = false; for (const DeclaratorChunk &DeclType : D.type_objects()) { switch (DeclType.Kind) { 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 @@ -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 {{a function declaration 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/FixIt/fixit.c b/clang/test/FixIt/fixit.c --- a/clang/test/FixIt/fixit.c +++ b/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 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 @@ -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 {{a function declaration 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'}} */ +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}} // 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 {{a function declaration 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}} +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}} // PR12595 -void test18() { +void test18(void) { int x = 4+(5-12)); // expected-error {{extraneous ')' before ';'}} } diff --git a/clang/test/Parser/knr_parameter_attributes.c b/clang/test/Parser/knr_parameter_attributes.c --- a/clang/test/Parser/knr_parameter_attributes.c +++ b/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__))) diff --git a/clang/test/Parser/opencl-kernel.cl b/clang/test/Parser/opencl-kernel.cl --- a/clang/test/Parser/opencl-kernel.cl +++ b/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}} { } diff --git a/clang/test/Parser/traditional_arg_scope.c b/clang/test/Parser/traditional_arg_scope.c --- a/clang/test/Parser/traditional_arg_scope.c +++ b/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}} 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 +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c99 -int f3(y, x, +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}} x) // expected-error {{redefinition of parameter}} int y, x, // expected-note {{previous declaration is here}} diff --git a/clang/test/Sema/block-return.c b/clang/test/Sema/block-return.c --- a/clang/test/Sema/block-return.c +++ b/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)); 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,18 +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; {} +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 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 {{a function declaration 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}} +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}} typedef void (*f3)(void); f3 t3(int b) { return b? f0 : f1; } // okay @@ -22,6 +23,8 @@ char *rindex(); } +// FIXME: we should diagnose this case, but when merging function declarations, +// we don't diagnose it because the function is a builtin. char *rindex(s, c) 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}} { @@ -30,7 +33,7 @@ // PR8314 void proto(int); -void proto(x) +void proto(x) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} int x; { } @@ -42,6 +45,6 @@ // PR31020 void func(short d) __attribute__((cdecl)); // expected-note{{previous declaration is here}} -void __attribute__((cdecl)) func(d) +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}} 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 @@ -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 char *foo = "test"; int test(char*,...); -int test(fmt) +int test(fmt) // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} char*fmt; { va_list ap; @@ -20,9 +19,9 @@ return x; } -void exit(); +void exit(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C}} -int main(argc,argv) +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 argc;char**argv; { exit(test("",foo)); diff --git a/clang/test/Sema/vfprintf-valid-redecl.c b/clang/test/Sema/vfprintf-valid-redecl.c --- a/clang/test/Sema/vfprintf-valid-redecl.c +++ b/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 }} #endif diff --git a/clang/test/Sema/warn-deprecated-non-prototype.c b/clang/test/Sema/warn-deprecated-non-prototype.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/warn-deprecated-non-prototype.c @@ -0,0 +1,73 @@ +// 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 {{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 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 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 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 {{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 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}} \ + 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}} + +// 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}} + 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 +// warning by that point. It's not ideal to be this chatty, but this situation +// should be pretty rare. +void blapp(int); +void blapp() { } // both-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}} diff --git a/clang/test/Sema/warn-missing-prototypes.c b/clang/test/Sema/warn-missing-prototypes.c --- a/clang/test/Sema/warn-missing-prototypes.c +++ b/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]]:{{.*}}}:"{{.*}}" 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 @@ -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 {{a function declaration without a prototype is deprecated in all versions of C and is not supported 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 {{a function declaration without a prototype is not supported 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 {{a function declaration without a prototype is deprecated in all versions of C and is not supported 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(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}} // 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 {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} short d; {} diff --git a/clang/test/Sema/warn-strict-prototypes.m b/clang/test/Sema/warn-strict-prototypes.m --- a/clang/test/Sema/warn-strict-prototypes.m +++ b/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}} diff --git a/clang/test/SemaObjC/nonnull.m b/clang/test/SemaObjC/nonnull.m --- a/clang/test/SemaObjC/nonnull.m +++ b/clang/test/SemaObjC/nonnull.m @@ -2,7 +2,6 @@ // RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wno-objc-root-class %s // REQUIRES: LP64 - @class NSObject; NONNULL_ATTR @@ -23,7 +22,7 @@ extern void func4 (void (^block1)(), void (^block2)()) __attribute__((nonnull(1))) __attribute__((nonnull(2))); -void func6(); +void func6(); // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} void func7(); void @@ -63,7 +62,7 @@ __attribute__((nonnull)) void _dispatch_queue_push_list(dispatch_object_t _head); // no warning -void func6(dispatch_object_t _head) { +void func6(dispatch_object_t _head) { // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} _dispatch_queue_push_list(0); // expected-warning {{null passed to a callee that requires a non-null argument}} _dispatch_queue_push_list(_head._do); // no warning } diff --git a/clang/test/SemaOpenCL/address-spaces.cl b/clang/test/SemaOpenCL/address-spaces.cl --- a/clang/test/SemaOpenCL/address-spaces.cl +++ b/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); } diff --git a/clang/test/SemaOpenCL/cl20-device-side-enqueue.cl b/clang/test/SemaOpenCL/cl20-device-side-enqueue.cl --- a/clang/test/SemaOpenCL/cl20-device-side-enqueue.cl +++ b/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 diff --git a/clang/test/SemaOpenCL/func.cl b/clang/test/SemaOpenCL/func.cl --- a/clang/test/SemaOpenCL/func.cl +++ b/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);