This patch implements semantic handling of redeclarations with dllimport or dllexport attributes. Both attributes must appear on the first declaration, and dllimport must appear on every redeclaration.
-Nico
>From 8dc0d3dea7097f2820200143a378dc46537cf027 Mon Sep 17 00:00:00 2001 From: Nico Rieck <[email protected]> Date: Wed, 26 Mar 2014 16:28:11 +0100 Subject: [PATCH] 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. --- include/clang/Basic/DiagnosticSemaKinds.td | 2 + lib/Sema/SemaDecl.cpp | 72 +++++++++++++++++++++++++----- test/Sema/dllexport.c | 13 ++++++ test/Sema/dllimport.c | 34 ++++++++++---- test/SemaCXX/MicrosoftExtensions.cpp | 5 ++- test/SemaCXX/dllexport.cpp | 40 ++++++++++++++++- test/SemaCXX/dllimport.cpp | 70 ++++++++++++++++++++++++----- 7 files changed, 200 insertions(+), 36 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 105974b..4786708 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2074,6 +2074,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<IgnoredAttributes>; +def err_attribute_dll_redeclaration : Error< + "%q0 redeclared with different dll attributes">; 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 e4511c9..27ad642 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4845,6 +4845,55 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } } +static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, + NamedDecl *NewDecl, + bool IsSpecialization) { + if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) + OldDecl = OldTD->getTemplatedDecl(); + if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl)) + NewDecl = NewTD->getTemplatedDecl(); + + if (!OldDecl || !NewDecl) + return; + + const DLLImportAttr *OldImportAttr = OldDecl->getAttr<DLLImportAttr>(); + const DLLExportAttr *OldExportAttr = OldDecl->getAttr<DLLExportAttr>(); + const DLLImportAttr *NewImportAttr = NewDecl->getAttr<DLLImportAttr>(); + const DLLExportAttr *NewExportAttr = NewDecl->getAttr<DLLExportAttr>(); + + // 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; + 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<DLLImportAttr>(); + NewDecl->dropAttr<DLLImportAttr>(); + } +} + /// 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? @@ -5500,6 +5549,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + if (D.isRedeclaration() && !Previous.empty()) { + checkDLLAttributeRedeclaration( + *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD, + IsExplicitSpecialization); + } + if (NewTemplate) { if (NewVD->isInvalidDecl()) NewTemplate->setInvalidDecl(); @@ -7306,6 +7361,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<NamedDecl>(Previous.getRepresentativeDecl()), NewFD, + isExplicitSpecialization || isFunctionTemplateSpecialization); + } + if (getLangOpts().CPlusPlus) { if (FunctionTemplate) { if (NewFD->isInvalidDecl()) @@ -9667,17 +9728,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 eb39fbe..5cfe147 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{{'GlobalRedecl3' redeclared with different dll attributes}} + // 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{{'redecl4' redeclared with different dll attributes}} + //===----------------------------------------------------------------------===// diff --git a/test/Sema/dllimport.c b/test/Sema/dllimport.c index 0bd4afc..4aea694 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{{'GlobalRedecl4' redeclared with different dll attributes}} + // 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{{'redecl4' redeclared with different dll attributes}} diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index 9f7bcc6..60a758e 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{{'f2' redeclared with different DLL attributes}} } diff --git a/test/SemaCXX/dllexport.cpp b/test/SemaCXX/dllexport.cpp index 6476383..378e231 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{{'GlobalRedecl3' redeclared with different dll attributes}} + // 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{{'redecl3' redeclared with different dll attributes}} + +// 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{{'friend3' redeclared with different dll attributes}} + +// Implicit declarations can be redeclared with dllexport. +__declspec(dllexport) void* operator new(__SIZE_TYPE__ n); + //===----------------------------------------------------------------------===// @@ -104,8 +130,18 @@ template<typename T> __declspec(dllexport) void funcTmplRedecl1() {} template<typename T> __declspec(dllexport) void funcTmplRedecl2(); template<typename T> void funcTmplRedecl2() {} -template<typename T> __declspec(dllexport) void funcTmplRedecl3(); -template<typename T> void funcTmplRedecl3() {} +template<typename T> void funcTmplRedecl3(); // expected-note{{previous declaration is here}} +template<typename T> __declspec(dllexport) void funcTmplRedecl3(); // expected-error{{'funcTmplRedecl3' redeclared with different dll attributes}} + +// Function template friends +struct FuncTmplFriend { + template<typename T> friend __declspec(dllexport) void funcTmplFriend1(); + template<typename T> friend __declspec(dllexport) void funcTmplFriend2(); + template<typename T> friend void funcTmplFriend3(); // expected-note{{previous declaration is here}} +}; +template<typename T> __declspec(dllexport) void funcTmplFriend1() {} +template<typename T> void funcTmplFriend2() {} +template<typename T> __declspec(dllexport) void funcTmplFriend3() {} // expected-error{{'funcTmplFriend3' redeclared with different dll attributes}} template<typename T> void funcTmpl() {} diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp index c36718b..95bc6a2 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{{'GlobalRedecl4' redeclared with different dll attributes}} + // 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{{'redecl4' redeclared with different dll attributes}} + +// 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{{'friend4' redeclared with different dll attributes}} + +// Implicit declarations can be redeclared with dllimport. +__declspec(dllimport) void* operator new(__SIZE_TYPE__ n); + //===----------------------------------------------------------------------===// @@ -127,12 +158,27 @@ template<typename T> void __declspec(dllimport) funcTmplDecl2(); template<typename T> __declspec(dllimport) void funcTmplRedecl1(); template<typename T> __declspec(dllimport) void funcTmplRedecl1(); -template<typename T> __declspec(dllimport) void funcTmplRedecl2(); -template<typename T> void funcTmplRedecl2(); +template<typename T> __declspec(dllimport) void funcTmplRedecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +template<typename T> void funcTmplRedecl2(); // expected-warning{{'funcTmplRedecl2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -template<typename T> __declspec(dllimport) void funcTmplRedecl3(); +template<typename T> __declspec(dllimport) void funcTmplRedecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} template<typename T> void funcTmplRedecl3() {} // expected-warning{{'funcTmplRedecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template<typename T> void funcTmplRedecl4(); // expected-note{{previous declaration is here}} +template<typename T> __declspec(dllimport) void funcTmplRedecl4(); // expected-error{{'funcTmplRedecl4' redeclared with different dll attributes}} + +// Function template friends +struct FuncTmplFriend { + template<typename T> friend __declspec(dllimport) void funcTmplFriend1(); + template<typename T> friend __declspec(dllimport) void funcTmplFriend2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + template<typename T> friend __declspec(dllimport) void funcTmplFriend3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + template<typename T> friend void funcTmplFriend4(); // expected-note{{previous declaration is here}} +}; +template<typename T> __declspec(dllimport) void funcTmplFriend1(); +template<typename T> void funcTmplFriend2(); // expected-warning{{'funcTmplFriend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template<typename T> void funcTmplFriend3() {} // expected-warning{{'funcTmplFriend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template<typename T> __declspec(dllimport) void funcTmplFriend4(); // expected-error{{'funcTmplFriend4' redeclared with different dll attributes}} + template<typename T> void funcTmpl() {} template<typename T> __declspec(dllimport) void importedFuncTmpl(); -- 1.9.0.msysgit.0
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
