From: Nico Rieck Date: Mon, 31 Mar 2014 14:56:15 +0000 (+0000) Subject: Sema: Check dll attributes on redeclarations X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=59c123020a78ea27d43aea22595bac380bd0ccc1;p=clang Sema: Check dll attributes on redeclarations A redeclaration may not add dllimport or dllexport attributes. dllexport is sticky and can be omitted on redeclarations while dllimport cannot. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205197 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1a6784bef9..bd461f4597 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2077,6 +2077,8 @@ def err_attribute_selectany_non_extern_data : Error< def warn_attribute_invalid_on_definition : Warning< "'%0' attribute cannot be specified on a definition">, InGroup; +def err_attribute_dll_redeclaration : Error< + "redeclaration of %q0 cannot add %q1 attribute">; def err_attribute_dllimport_data_definition : Error< "definition of dllimport data">; def err_attribute_weakref_not_static : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 82579d89cd..26f8b2587f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4845,6 +4845,56 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } } +static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, + NamedDecl *NewDecl, + bool IsSpecialization) { + if (TemplateDecl *OldTD = dyn_cast(OldDecl)) + OldDecl = OldTD->getTemplatedDecl(); + if (TemplateDecl *NewTD = dyn_cast(NewDecl)) + NewDecl = NewTD->getTemplatedDecl(); + + if (!OldDecl || !NewDecl) + return; + + const DLLImportAttr *OldImportAttr = OldDecl->getAttr(); + const DLLExportAttr *OldExportAttr = OldDecl->getAttr(); + const DLLImportAttr *NewImportAttr = NewDecl->getAttr(); + const DLLExportAttr *NewExportAttr = NewDecl->getAttr(); + + // dllimport and dllexport are inheritable attributes so we have to exclude + // inherited attribute instances. + bool HasNewAttr = (NewImportAttr && !NewImportAttr->isInherited()) || + (NewExportAttr && !NewExportAttr->isInherited()); + + // A redeclaration is not allowed to add a dllimport or dllexport attribute, + // the only exception being explicit specializations. + // Implicitly generated declarations are also excluded for now because there + // is no other way to switch these to use dllimport or dllexport. + bool AddsAttr = !(OldImportAttr || OldExportAttr) && HasNewAttr; + if (AddsAttr && !IsSpecialization && !OldDecl->isImplicit()) { + S.Diag(NewDecl->getLocation(), diag::err_attribute_dll_redeclaration) + << NewDecl + << (NewImportAttr ? (const Attr *)NewImportAttr : NewExportAttr); + S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); + NewDecl->setInvalidDecl(); + return; + } + + // A redeclaration is not allowed to drop a dllimport attribute, the only + // exception being inline function definitions. + // FIXME: Handle inline functions. + // NB: MSVC converts such a declaration to dllexport. + if (OldImportAttr && !HasNewAttr) { + S.Diag(NewDecl->getLocation(), + diag::warn_redeclaration_without_attribute_prev_attribute_ignored) + << NewDecl << OldImportAttr; + S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); + S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); + OldDecl->dropAttr(); + NewDecl->dropAttr(); + } +} + /// Given that we are within the definition of the given function, /// will that definition behave like C99's 'inline', where the /// definition is discarded except for optimization purposes? @@ -5497,6 +5547,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + if (D.isRedeclaration() && !Previous.empty()) { + checkDLLAttributeRedeclaration( + *this, dyn_cast(Previous.getRepresentativeDecl()), NewVD, + IsExplicitSpecialization); + } + if (NewTemplate) { if (NewVD->isInvalidDecl()) NewTemplate->setInvalidDecl(); @@ -7318,6 +7374,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Set this FunctionDecl's range up to the right paren. NewFD->setRangeEnd(D.getSourceRange().getEnd()); + if (D.isRedeclaration() && !Previous.empty()) { + checkDLLAttributeRedeclaration( + *this, dyn_cast(Previous.getRepresentativeDecl()), NewFD, + isExplicitSpecialization || isFunctionTemplateSpecialization); + } + if (getLangOpts().CPlusPlus) { if (FunctionTemplate) { if (NewFD->isInvalidDecl()) @@ -9679,17 +9741,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { FD->setInvalidDecl(); return D; } - - // Visual C++ appears to not think this is an issue, so only issue - // a warning when Microsoft extensions are disabled. - if (!LangOpts.MicrosoftExt) { - // If a symbol previously declared dllimport is later defined, the - // attribute is ignored in subsequent references, and a warning is - // emitted. - Diag(FD->getLocation(), - diag::warn_redeclaration_without_attribute_prev_attribute_ignored) - << FD << DA; - } } // We want to attach documentation to original Decl (which might be // a function template). diff --git a/test/Sema/dllexport.c b/test/Sema/dllexport.c index eb39fbe9bf..675bd492f8 100644 --- a/test/Sema/dllexport.c +++ b/test/Sema/dllexport.c @@ -31,6 +31,16 @@ int __declspec(dllexport) GlobalInit2 = 1; __declspec(dllexport) extern int GlobalDeclInit; int GlobalDeclInit = 1; +// Redeclarations +__declspec(dllexport) extern int GlobalRedecl1; +__declspec(dllexport) int GlobalRedecl1; + +__declspec(dllexport) extern int GlobalRedecl2; + int GlobalRedecl2; + + extern int GlobalRedecl3; // expected-note{{previous declaration is here}} +__declspec(dllexport) extern int GlobalRedecl3; // expected-error{{redeclaration of 'GlobalRedecl3' cannot add 'dllexport' attribute}} + // Export in local scope. void functionScope() { __declspec(dllexport) extern int ExternLocalVarDecl; @@ -69,6 +79,9 @@ __declspec(dllexport) void redecl2(); __declspec(dllexport) void redecl3(); void redecl3() {} + void redecl4(); // expected-note{{previous declaration is here}} +__declspec(dllexport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllexport' attribute}} + //===----------------------------------------------------------------------===// diff --git a/test/Sema/dllimport.c b/test/Sema/dllimport.c index 0bd4afc8b8..46031173cd 100644 --- a/test/Sema/dllimport.c +++ b/test/Sema/dllimport.c @@ -31,17 +31,17 @@ __declspec(dllimport) int GlobalInit1 = 1; // expected-error{{definition of dlli int __declspec(dllimport) GlobalInit2 = 1; // expected-error{{definition of dllimport data}} // Declare, then reject definition. -__declspec(dllimport) extern int ExternGlobalDeclInit; -int ExternGlobalDeclInit = 1; // expected-error{{definition of dllimport data}} +__declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int ExternGlobalDeclInit = 1; // expected-warning{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -__declspec(dllimport) int GlobalDeclInit; -int GlobalDeclInit = 1; // expected-error{{definition of dllimport data}} +__declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int GlobalDeclInit = 1; // expected-warning{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; -int *GlobalDeclChunkAttrInit = 0; // expected-error{{definition of dllimport data}} +int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int *GlobalDeclChunkAttrInit = 0; // expected-warning{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -int GlobalDeclAttrInit __attribute__((dllimport)); -int GlobalDeclAttrInit = 1; // expected-error{{definition of dllimport data}} +int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int GlobalDeclAttrInit = 1; // expected-warning{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} // Redeclarations __declspec(dllimport) extern int GlobalRedecl1; @@ -56,6 +56,14 @@ int *__attribute__((dllimport)) GlobalRedecl2b; int GlobalRedecl2c __attribute__((dllimport)); int GlobalRedecl2c __attribute__((dllimport)); +// NB: MSVC issues a warning and makes GlobalRedecl3 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) extern int GlobalRedecl3; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + extern int GlobalRedecl3; // expected-warning{{'GlobalRedecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + + extern int GlobalRedecl4; // expected-note{{previous declaration is here}} +__declspec(dllimport) extern int GlobalRedecl4; // expected-error{{redeclaration of 'GlobalRedecl4' cannot add 'dllimport' attribute}} + // Import in local scope. __declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}} __declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}} @@ -95,5 +103,13 @@ inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dl __declspec(dllimport) void redecl1(); __declspec(dllimport) void redecl1(); -__declspec(dllimport) void redecl3(); +// NB: MSVC issues a warning and makes redecl2/redecl3 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) void redecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + void redecl2(); // expected-warning{{'redecl2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + +__declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} void redecl3() {} // expected-warning{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + + void redecl4(); // expected-note{{previous declaration is here}} +__declspec(dllimport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllimport' attribute}} diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index 9f7bcc625f..0f6ebbb069 100644 --- a/test/SemaCXX/MicrosoftExtensions.cpp +++ b/test/SemaCXX/MicrosoftExtensions.cpp @@ -119,10 +119,11 @@ enum : long long { // expected-warning{{enumeration types with a fixed underlyi class AAA { __declspec(dllimport) void f(void) { } -void f2(void); +void f2(void); // expected-note{{previous declaration is here}} }; -__declspec(dllimport) void AAA::f2(void) { // expected-error {{'dllimport' attribute can be applied only to symbol}} +__declspec(dllimport) void AAA::f2(void) { // expected-error{{'dllimport' attribute can be applied only to symbol}} + // expected-error@-1{{redeclaration of 'AAA::f2' cannot add 'dllimport' attribute}} } diff --git a/test/SemaCXX/dllexport.cpp b/test/SemaCXX/dllexport.cpp index 6476383495..acbd4ce78f 100644 --- a/test/SemaCXX/dllexport.cpp +++ b/test/SemaCXX/dllexport.cpp @@ -43,6 +43,16 @@ int __declspec(dllexport) GlobalInit2 = 1; __declspec(dllexport) extern int GlobalDeclInit; int GlobalDeclInit = 1; +// Redeclarations +__declspec(dllexport) extern int GlobalRedecl1; +__declspec(dllexport) int GlobalRedecl1; + +__declspec(dllexport) extern int GlobalRedecl2; + int GlobalRedecl2; + + extern int GlobalRedecl3; // expected-note{{previous declaration is here}} +__declspec(dllexport) extern int GlobalRedecl3; // expected-error{{redeclaration of 'GlobalRedecl3' cannot add 'dllexport' attribute}} + // Export in local scope. void functionScope() { __declspec(dllexport) extern int ExternLocalVarDecl; @@ -84,6 +94,22 @@ __declspec(dllexport) void redecl1() {} __declspec(dllexport) void redecl2(); void redecl2() {} + void redecl3(); // expected-note{{previous declaration is here}} +__declspec(dllexport) void redecl3(); // expected-error{{redeclaration of 'redecl3' cannot add 'dllexport' attribute}} + +// Friend functions +struct FuncFriend { + friend __declspec(dllexport) void friend1(); + friend __declspec(dllexport) void friend2(); + friend void friend3(); // expected-note{{previous declaration is here}} +}; +__declspec(dllexport) void friend1() {} + void friend2() {} +__declspec(dllexport) void friend3() {} // expected-error{{redeclaration of 'friend3' cannot add 'dllexport' attribute}} + +// Implicit declarations can be redeclared with dllexport. +__declspec(dllexport) void* operator new(__SIZE_TYPE__ n); + //===----------------------------------------------------------------------===// @@ -104,8 +130,18 @@ template __declspec(dllexport) void funcTmplRedecl1() {} template __declspec(dllexport) void funcTmplRedecl2(); template void funcTmplRedecl2() {} -template __declspec(dllexport) void funcTmplRedecl3(); -template void funcTmplRedecl3() {} +template void funcTmplRedecl3(); // expected-note{{previous declaration is here}} +template __declspec(dllexport) void funcTmplRedecl3(); // expected-error{{redeclaration of 'funcTmplRedecl3' cannot add 'dllexport' attribute}} + +// Function template friends +struct FuncTmplFriend { + template friend __declspec(dllexport) void funcTmplFriend1(); + template friend __declspec(dllexport) void funcTmplFriend2(); + template friend void funcTmplFriend3(); // expected-note{{previous declaration is here}} +}; +template __declspec(dllexport) void funcTmplFriend1() {} +template void funcTmplFriend2() {} +template __declspec(dllexport) void funcTmplFriend3() {} // expected-error{{redeclaration of 'funcTmplFriend3' cannot add 'dllexport' attribute}} template void funcTmpl() {} diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp index c36718b542..f63943924c 100644 --- a/test/SemaCXX/dllimport.cpp +++ b/test/SemaCXX/dllimport.cpp @@ -43,17 +43,17 @@ __declspec(dllimport) int GlobalInit1 = 1; // expected-error{{definition of dlli int __declspec(dllimport) GlobalInit2 = 1; // expected-error{{definition of dllimport data}} // Declare, then reject definition. -__declspec(dllimport) extern int ExternGlobalDeclInit; -int ExternGlobalDeclInit = 1; // expected-error{{definition of dllimport data}} +__declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int ExternGlobalDeclInit = 1; // expected-warning{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -__declspec(dllimport) int GlobalDeclInit; -int GlobalDeclInit = 1; // expected-error{{definition of dllimport data}} +__declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int GlobalDeclInit = 1; // expected-warning{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; -int *GlobalDeclChunkAttrInit = 0; // expected-error{{definition of dllimport data}} +int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int *GlobalDeclChunkAttrInit = 0; // expected-warning{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -int GlobalDeclAttrInit __attribute__((dllimport)); -int GlobalDeclAttrInit = 1; // expected-error{{definition of dllimport data}} +int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +int GlobalDeclAttrInit = 1; // expected-warning{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} // Redeclarations __declspec(dllimport) extern int GlobalRedecl1; @@ -68,6 +68,14 @@ int *__attribute__((dllimport)) GlobalRedecl2b; int GlobalRedecl2c __attribute__((dllimport)); int GlobalRedecl2c __attribute__((dllimport)); +// NB: MSVC issues a warning and makes GlobalRedecl3 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) extern int GlobalRedecl3; // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + extern int GlobalRedecl3; // expected-warning{{'GlobalRedecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + + extern int GlobalRedecl4; // expected-note{{previous declaration is here}} +__declspec(dllimport) extern int GlobalRedecl4; // expected-error{{redeclaration of 'GlobalRedecl4' cannot add 'dllimport' attribute}} + // Import in local scope. __declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}} __declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}} @@ -110,9 +118,32 @@ inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dl __declspec(dllimport) void redecl1(); __declspec(dllimport) void redecl1(); -__declspec(dllimport) void redecl3(); +// NB: MSVC issues a warning and makes redecl2/redecl3 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) void redecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + void redecl2(); // expected-warning{{'redecl2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + +__declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} void redecl3() {} // expected-warning{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + void redecl4(); // expected-note{{previous declaration is here}} +__declspec(dllimport) void redecl4(); // expected-error{{redeclaration of 'redecl4' cannot add 'dllimport' attribute}} + +// Friend functions +struct FuncFriend { + friend __declspec(dllimport) void friend1(); + friend __declspec(dllimport) void friend2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + friend __declspec(dllimport) void friend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + friend void friend4(); // expected-note{{previous declaration is here}} +}; +__declspec(dllimport) void friend1(); + void friend2(); // expected-warning{{'friend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + void friend3() {} // expected-warning{{'friend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +__declspec(dllimport) void friend4(); // expected-error{{redeclaration of 'friend4' cannot add 'dllimport' attribute}} + +// Implicit declarations can be redeclared with dllimport. +__declspec(dllimport) void* operator new(__SIZE_TYPE__ n); + //===----------------------------------------------------------------------===// @@ -127,12 +158,27 @@ template void __declspec(dllimport) funcTmplDecl2(); template __declspec(dllimport) void funcTmplRedecl1(); template __declspec(dllimport) void funcTmplRedecl1(); -template __declspec(dllimport) void funcTmplRedecl2(); -template void funcTmplRedecl2(); +template __declspec(dllimport) void funcTmplRedecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +template void funcTmplRedecl2(); // expected-warning{{'funcTmplRedecl2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -template __declspec(dllimport) void funcTmplRedecl3(); +template __declspec(dllimport) void funcTmplRedecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} template void funcTmplRedecl3() {} // expected-warning{{'funcTmplRedecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template void funcTmplRedecl4(); // expected-note{{previous declaration is here}} +template __declspec(dllimport) void funcTmplRedecl4(); // expected-error{{redeclaration of 'funcTmplRedecl4' cannot add 'dllimport' attribute}} + +// Function template friends +struct FuncTmplFriend { + template friend __declspec(dllimport) void funcTmplFriend1(); + template friend __declspec(dllimport) void funcTmplFriend2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + template friend __declspec(dllimport) void funcTmplFriend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + template friend void funcTmplFriend4(); // expected-note{{previous declaration is here}} +}; +template __declspec(dllimport) void funcTmplFriend1(); +template void funcTmplFriend2(); // expected-warning{{'funcTmplFriend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template void funcTmplFriend3() {} // expected-warning{{'funcTmplFriend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template __declspec(dllimport) void funcTmplFriend4(); // expected-error{{redeclaration of 'funcTmplFriend4' cannot add 'dllimport' attribute}} + template void funcTmpl() {} template __declspec(dllimport) void importedFuncTmpl();