From: David Majnemer Date: Wed, 18 Jun 2014 23:26:25 +0000 (+0000) Subject: Sema: Static redeclaration after extern declarations is a Microsoft Extension X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2e01479f1c4f2648a48dce00c007668fa4763d39;p=clang Sema: Static redeclaration after extern declarations is a Microsoft Extension CL permits static redeclarations to follow extern declarations. The storage specifier on the latter declaration has no effect. This fixes PR20034. Differential Revision: http://reviews.llvm.org/D4149 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211238 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index aa02519087..42117e37a6 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3814,8 +3814,8 @@ def note_extern_c_global_conflict : Note< "declared %select{in global scope|with C language linkage}0 here">; def warn_weak_import : Warning < "an already-declared variable is made a weak_import declaration %0">; -def warn_static_non_static : ExtWarn< - "static declaration of %0 follows non-static declaration">; +def ext_static_non_static : Extension< + "redeclaring non-static %0 as static is a Microsoft extension">, InGroup; def err_non_static_static : Error< "non-static declaration of %0 follows static declaration">; def err_extern_non_extern : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 304fd46cf9..d4c3cf2d06 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2253,6 +2253,24 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { return Sema::CXXInvalid; } +// Determine whether the previous declaration was a definition, implicit +// declaration, or a declaration. +template +static std::pair +getNoteDiagForInvalidRedeclaration(const T *Old, const T *New) { + diag::kind PrevDiag; + SourceLocation OldLocation = Old->getLocation(); + if (Old->isThisDeclarationADefinition()) + PrevDiag = diag::note_previous_definition; + else if (Old->isImplicit()) { + PrevDiag = diag::note_previous_implicit_declaration; + if (OldLocation.isInvalid()) + OldLocation = New->getLocation(); + } else + PrevDiag = diag::note_previous_declaration; + return std::make_pair(PrevDiag, OldLocation); +} + /// canRedefineFunction - checks if a function can be redefined. Currently, /// only extern inline functions can be redefined, and even then only in /// GNU89 mode. @@ -2345,18 +2363,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, if (Old->isInvalidDecl()) return true; - // Determine whether the previous declaration was a definition, - // implicit declaration, or a declaration. diag::kind PrevDiag; - SourceLocation OldLocation = Old->getLocation(); - if (Old->isThisDeclarationADefinition()) - PrevDiag = diag::note_previous_definition; - else if (Old->isImplicit()) { - PrevDiag = diag::note_previous_implicit_declaration; - if (OldLocation.isInvalid()) - OldLocation = New->getLocation(); - } else - PrevDiag = diag::note_previous_declaration; + SourceLocation OldLocation; + std::tie(PrevDiag, OldLocation) = + getNoteDiagForInvalidRedeclaration(Old, New); // Don't complain about this if we're in GNU89 mode and the old function // is an extern inline function. @@ -2368,7 +2378,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, !New->getTemplateSpecializationInfo() && !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { - Diag(New->getLocation(), diag::warn_static_non_static) << New; + Diag(New->getLocation(), diag::ext_static_non_static) << New; Diag(OldLocation, PrevDiag); } else { Diag(New->getLocation(), diag::err_static_non_static) << New; @@ -3069,13 +3079,25 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (New->isInvalidDecl()) return; + diag::kind PrevDiag; + SourceLocation OldLocation; + std::tie(PrevDiag, OldLocation) = + getNoteDiagForInvalidRedeclaration(Old, New); + // [dcl.stc]p8: Check if we have a non-static decl followed by a static. if (New->getStorageClass() == SC_Static && !New->isStaticDataMember() && Old->hasExternalFormalLinkage()) { - Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); - return New->setInvalidDecl(); + if (getLangOpts().MicrosoftExt) { + Diag(New->getLocation(), diag::ext_static_non_static) + << New->getDeclName(); + Diag(OldLocation, PrevDiag); + } else { + Diag(New->getLocation(), diag::err_static_non_static) + << New->getDeclName(); + Diag(OldLocation, PrevDiag); + return New->setInvalidDecl(); + } } // C99 6.2.2p4: // For an identifier declared with the storage-class specifier @@ -3092,7 +3114,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { !New->isStaticDataMember() && Old->getCanonicalDecl()->getStorageClass() == SC_Static) { Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } @@ -3100,13 +3122,13 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (New->hasExternalStorage() && !Old->hasLinkage() && Old->isLocalVarDecl()) { Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } if (Old->hasLinkage() && New->isLocalVarDecl() && !New->hasExternalStorage()) { Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } @@ -3119,17 +3141,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { !(Old->getLexicalDeclContext()->isRecord() && !New->getLexicalDeclContext()->isRecord())) { Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } if (New->getTLSKind() != Old->getTLSKind()) { if (!Old->getTLSKind()) { Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_declaration); + Diag(OldLocation, PrevDiag); } else if (!New->getTLSKind()) { Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_declaration); + Diag(OldLocation, PrevDiag); } else { // Do not allow redeclaration to change the variable between requiring // static and dynamic initialization. @@ -3137,7 +3159,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // declaration to determine the kind. Do we need to be compatible here? Diag(New->getLocation(), diag::err_thread_thread_different_kind) << New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic); - Diag(Old->getLocation(), diag::note_previous_declaration); + Diag(OldLocation, PrevDiag); } } @@ -3154,7 +3176,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (haveIncompatibleLanguageLinkages(Old, New)) { Diag(New->getLocation(), diag::err_different_language_linkage) << New; - Diag(Old->getLocation(), diag::note_previous_definition); + Diag(OldLocation, PrevDiag); New->setInvalidDecl(); return; } diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c index 5a45172ed2..b46e4fe39f 100644 --- a/test/Misc/warning-flags.c +++ b/test/Misc/warning-flags.c @@ -18,7 +18,7 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. -CHECK: Warnings without flags (106): +CHECK: Warnings without flags (105): CHECK-NEXT: ext_delete_void_ptr_operand CHECK-NEXT: ext_expected_semi_decl_list CHECK-NEXT: ext_explicit_specialization_storage_class @@ -114,7 +114,6 @@ CHECK-NEXT: warn_redeclaration_without_attribute_prev_attribute_ignored CHECK-NEXT: warn_register_objc_catch_parm CHECK-NEXT: warn_related_result_type_compatibility_class CHECK-NEXT: warn_related_result_type_compatibility_protocol -CHECK-NEXT: warn_static_non_static CHECK-NEXT: warn_template_export_unsupported CHECK-NEXT: warn_template_spec_extra_headers CHECK-NEXT: warn_tentative_incomplete_array diff --git a/test/Sema/private-extern.c b/test/Sema/private-extern.c index e9b67d5070..0c13c92bba 100644 --- a/test/Sema/private-extern.c +++ b/test/Sema/private-extern.c @@ -13,10 +13,10 @@ __private_extern__ int g2; int g3; // expected-note{{previous definition}} static int g3; // expected-error{{static declaration of 'g3' follows non-static declaration}} -extern int g4; // expected-note{{previous definition}} +extern int g4; // expected-note{{previous declaration}} static int g4; // expected-error{{static declaration of 'g4' follows non-static declaration}} -__private_extern__ int g5; // expected-note{{previous definition}} +__private_extern__ int g5; // expected-note{{previous declaration}} static int g5; // expected-error{{static declaration of 'g5' follows non-static declaration}} void f0() { @@ -30,12 +30,12 @@ void f1() { } void f2() { - extern int g8; // expected-note{{previous definition}} + extern int g8; // expected-note{{previous declaration}} int g8; // expected-error {{non-extern declaration of 'g8' follows extern declaration}} } void f3() { - __private_extern__ int g9; // expected-note{{previous definition}} + __private_extern__ int g9; // expected-note{{previous declaration}} int g9; // expected-error {{non-extern declaration of 'g9' follows extern declaration}} } diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c index bf2b1e4ee6..602624229d 100644 --- a/test/Sema/tentative-decls.c +++ b/test/Sema/tentative-decls.c @@ -23,7 +23,7 @@ int i1 = 1; // expected-note {{previous definition is here}} int i1 = 2; // expected-error {{redefinition of 'i1'}} int i1; int i1; -extern int i5; // expected-note {{previous definition is here}} +extern int i5; // expected-note {{previous declaration is here}} static int i5; // expected-error{{static declaration of 'i5' follows non-static declaration}} static int i2 = 5; // expected-note 1 {{previous definition is here}} @@ -49,7 +49,7 @@ int redef[]; // expected-note {{previous definition is here}} int redef[11]; // expected-error{{redefinition of 'redef'}} void func() { - extern int i6; // expected-note {{previous definition is here}} + extern int i6; // expected-note {{previous declaration is here}} static int i6; // expected-error{{static declaration of 'i6' follows non-static declaration}} } diff --git a/test/Sema/thread-specifier.c b/test/Sema/thread-specifier.c index d49b350667..3968ae14cf 100644 --- a/test/Sema/thread-specifier.c +++ b/test/Sema/thread-specifier.c @@ -58,7 +58,7 @@ int f(__thread int t7) { // expected-error {{' is only allowed on variable decla } __thread typedef int t14; // expected-error-re {{cannot combine with previous '{{__thread|_Thread_local|thread_local}}' declaration specifier}} -__thread int t15; // expected-note {{previous declaration is here}} +__thread int t15; // expected-note {{previous definition is here}} extern int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}} extern int t16; // expected-note {{previous declaration is here}} __thread int t16; // expected-error {{thread-local declaration of 't16' follows non-thread-local declaration}} diff --git a/test/Sema/var-redecl.c b/test/Sema/var-redecl.c index 363458b201..0e30aa2713 100644 --- a/test/Sema/var-redecl.c +++ b/test/Sema/var-redecl.c @@ -58,5 +58,5 @@ int *p=&g19; // expected-error{{use of undeclared identifier 'g19'}} \ // PR3645 static int a; -extern int a; // expected-note {{previous definition is here}} +extern int a; // expected-note {{previous declaration is here}} int a; // expected-error {{non-static declaration of 'a' follows static declaration}} diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index 3420d20cb8..3b54c281af 100644 --- a/test/SemaCXX/MicrosoftExtensions.cpp +++ b/test/SemaCXX/MicrosoftExtensions.cpp @@ -144,11 +144,14 @@ extern void static_func(); void static_func(); // expected-note {{previous declaration is here}} -static void static_func() // expected-warning {{static declaration of 'static_func' follows non-static declaration}} +static void static_func() // expected-warning {{redeclaring non-static 'static_func' as static is a Microsoft extension}} { } +extern const int static_var; // expected-note {{previous declaration is here}} +static const int static_var = 3; // expected-warning {{redeclaring non-static 'static_var' as static is a Microsoft extension}} + long function_prototype(int a); long (*function_ptr)(int a);