From: Hans Wennborg Date: Wed, 1 Feb 2017 18:52:53 +0000 (+0000) Subject: Drop 'dllimport' when redeclaring inline function template without the attribute... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3286ac625a20c1d7bf5293c89acd986f4f277be6;p=clang Drop 'dllimport' when redeclaring inline function template without the attribute (PR31695) For non-template dllimport functions, MSVC allows providing an inline definition without spelling out the attribute again. In the example below, f remains a dllimport function. __declspec(dllimport) int f(); inline int f() { return 42; } int useit() { return f(); } However, for a function template, not putting dllimport on the redeclaration causes it to be dropped. In the example below, f is not dllimport. template __declspec(dllimport) int f(); template inline int f() { return 42; } int useit() { return f(); } This patch makes Clang match MSVC for the second example. MSVC does not warn about the attribute being dropped in the example above, but I think we should. (MSVC does warn if the inline keyword isn't used.) Differential Revision: https://reviews.llvm.org/D29152 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@293800 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 60daae056b..32663121f8 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5702,13 +5702,17 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, if (OldDecl->isInvalidDecl()) return; + bool IsTemplate = false; if (TemplateDecl *OldTD = dyn_cast(OldDecl)) { OldDecl = OldTD->getTemplatedDecl(); + IsTemplate = true; if (!IsSpecialization) IsDefinition = false; } - if (TemplateDecl *NewTD = dyn_cast(NewDecl)) + if (TemplateDecl *NewTD = dyn_cast(NewDecl)) { NewDecl = NewTD->getTemplatedDecl(); + IsTemplate = true; + } if (!OldDecl || !NewDecl) return; @@ -5761,9 +5765,10 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, } // A redeclaration is not allowed to drop a dllimport attribute, the only - // exceptions being inline function definitions, local extern declarations, - // qualified friend declarations or special MSVC extension: in the last case, - // the declaration is treated as if it were marked dllexport. + // exceptions being inline function definitions (except for function + // templates), local extern declarations, qualified friend declarations or + // special MSVC extension: in the last case, the declaration is treated as if + // it were marked dllexport. bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false; bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft(); if (const auto *VD = dyn_cast(NewDecl)) { @@ -5778,7 +5783,8 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, FD->getFriendObjectKind() == Decl::FOK_Declared; } - if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember && + if (OldImportAttr && !HasNewAttr && + (!IsInline || (IsMicrosoft && IsTemplate)) && !IsStaticDataMember && !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) { if (IsMicrosoft && IsDefinition) { S.Diag(NewDecl->getLocation(), diff --git a/test/CodeGenCXX/dllimport.cpp b/test/CodeGenCXX/dllimport.cpp index 8e7ead9d1f..944c366f88 100644 --- a/test/CodeGenCXX/dllimport.cpp +++ b/test/CodeGenCXX/dllimport.cpp @@ -405,17 +405,17 @@ USE(inlineFuncTmpl1) template inline void __attribute__((dllimport)) inlineFuncTmpl2() {} USE(inlineFuncTmpl2) -// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"() +// MSC-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"() // GNU-DAG: define linkonce_odr void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv() -// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"() +// MO1-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDecl@UImplicitInst_Imported@@@@YAXXZ"() // GO1-DAG: define linkonce_odr void @_Z18inlineFuncTmplDeclI21ImplicitInst_ImportedEvv() template __declspec(dllimport) inline void inlineFuncTmplDecl(); template void inlineFuncTmplDecl() {} USE(inlineFuncTmplDecl) -// MSC-DAG: declare dllimport void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"() +// MSC-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"() // GNU-DAG: define linkonce_odr void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv() -// MO1-DAG: define available_externally dllimport void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"() +// MO1-DAG: define linkonce_odr void @"\01??$inlineFuncTmplDef@UImplicitInst_Imported@@@@YAXXZ"() // GO1-DAG: define linkonce_odr void @_Z17inlineFuncTmplDefI21ImplicitInst_ImportedEvv() template __declspec(dllimport) void inlineFuncTmplDef(); template inline void inlineFuncTmplDef() {} @@ -449,7 +449,7 @@ USE(funcTmplRedecl3) // GNU-DAG: declare void @_Z15funcTmplFriend2I24ImplicitInst_NotImportedEvv() // MSC-DAG: define linkonce_odr void @"\01??$funcTmplFriend3@UImplicitInst_NotImported@@@@YAXXZ"() // GNU-DAG: define linkonce_odr void @_Z15funcTmplFriend3I24ImplicitInst_NotImportedEvv() -// MSC-DAG: declare dllimport void @"\01??$funcTmplFriend4@UImplicitInst_Imported@@@@YAXXZ"() +// MSC-DAG: define linkonce_odr void @"\01??$funcTmplFriend4@UImplicitInst_Imported@@@@YAXXZ"() // GNU-DAG: define linkonce_odr void @_Z15funcTmplFriend4I21ImplicitInst_ImportedEvv() struct FuncTmplFriend { template friend __declspec(dllimport) void funcTmplFriend1(); diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp index 36a8ac625a..1c59ccad6e 100644 --- a/test/SemaCXX/dllimport.cpp +++ b/test/SemaCXX/dllimport.cpp @@ -396,20 +396,28 @@ template void __declspec(dllimport) funcTmplDecl2(); template __declspec(dllimport) void funcTmplDef() {} // expected-error{{dllimport cannot be applied to non-inline function definition}} // Import inline function template. -#ifdef GNU -// expected-warning@+5{{'dllimport' attribute ignored on inline function}} -// expected-warning@+5{{'dllimport' attribute ignored on inline function}} -// expected-warning@+6{{'dllimport' attribute ignored on inline function}} -// expected-warning@+9{{'inlineFuncTmplDef' redeclared inline; 'dllimport' attribute ignored}} -#endif -template __declspec(dllimport) inline void inlineFuncTmpl1() {} -template inline void __attribute__((dllimport)) inlineFuncTmpl2() {} +#ifdef GNU // MinGW always ignores dllimport on inline functions. -template __declspec(dllimport) inline void inlineFuncTmplDecl(); +template __declspec(dllimport) inline void inlineFuncTmpl1() {} // expected-warning{{'dllimport' attribute ignored on inline function}} +template inline void __attribute__((dllimport)) inlineFuncTmpl2() {} // expected-warning{{'dllimport' attribute ignored on inline function}} + +template __declspec(dllimport) inline void inlineFuncTmplDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}} template void inlineFuncTmplDecl() {} template __declspec(dllimport) void inlineFuncTmplDef(); -template inline void inlineFuncTmplDef() {} +template inline void inlineFuncTmplDef() {} // expected-warning{{'inlineFuncTmplDef' redeclared inline; 'dllimport' attribute ignored}} + +#else // MSVC drops dllimport when the function template is redeclared without it. (It doesn't warn, but we do.) + +template __declspec(dllimport) inline void inlineFuncTmpl1() {} +template inline void __attribute__((dllimport)) inlineFuncTmpl2() {} + +template __declspec(dllimport) inline void inlineFuncTmplDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +template void inlineFuncTmplDecl() {} // expected-warning{{'inlineFuncTmplDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + +template __declspec(dllimport) void inlineFuncTmplDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +template inline void inlineFuncTmplDef() {} // expected-warning{{'inlineFuncTmplDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif // Redeclarations template __declspec(dllimport) void funcTmplRedecl1(); @@ -436,7 +444,9 @@ struct FuncTmplFriend { 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}} #ifdef GNU -// expected-warning@+2{{'dllimport' attribute ignored on inline function}} +// expected-warning@+4{{'dllimport' attribute ignored on inline function}} +#else +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} #endif template friend __declspec(dllimport) inline void funcTmplFriend5(); }; @@ -444,6 +454,9 @@ 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}} +#ifdef MS +// expected-warning@+2{{'funcTmplFriend5' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif template inline void funcTmplFriend5() {} // External linkage is required. @@ -827,21 +840,28 @@ __declspec(dllimport) constexpr int MemberRedecl::ConstexprField; // expect struct ImportMemberTmpl { template __declspec(dllimport) void normalDecl(); template __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template __declspec(dllimport) void normalInlineDef(); template __declspec(dllimport) static void staticDecl(); template __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template __declspec(dllimport) static void staticInlineDef(); #ifdef GNU - // expected-warning@+5{{'dllimport' attribute ignored on inline function}} - // expected-warning@+5{{'dllimport' attribute ignored on inline function}} - // expected-warning@+5{{'dllimport' attribute ignored on inline function}} - // expected-warning@+5{{'dllimport' attribute ignored on inline function}} -#endif + template __declspec(dllimport) void normalInclass() {} // expected-warning{{'dllimport' attribute ignored on inline function}} + template __declspec(dllimport) inline void normalInlineDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}} + template __declspec(dllimport) static void staticInclass() {} // expected-warning{{'dllimport' attribute ignored on inline function}} + template __declspec(dllimport) static inline void staticInlineDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}} +#else template __declspec(dllimport) void normalInclass() {} - template __declspec(dllimport) inline void normalInlineDecl(); + template __declspec(dllimport) inline void normalInlineDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} template __declspec(dllimport) static void staticInclass() {} - template __declspec(dllimport) static inline void staticInlineDecl(); + template __declspec(dllimport) static inline void staticInlineDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#endif #if __has_feature(cxx_variable_templates) template __declspec(dllimport) static int StaticField; @@ -856,16 +876,22 @@ struct ImportMemberTmpl { }; template void ImportMemberTmpl::normalDef() {} // expected-warning{{'ImportMemberTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -template void ImportMemberTmpl::normalInlineDecl() {} template void ImportMemberTmpl::staticDef() {} // expected-warning{{'ImportMemberTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef GNU // dllimport was ignored above +template void ImportMemberTmpl::normalInlineDecl() {} template void ImportMemberTmpl::staticInlineDecl() {} +#else // dllimport dropped here +template void ImportMemberTmpl::normalInlineDecl() {} // expected-warning{{'ImportMemberTmpl::normalInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template void ImportMemberTmpl::staticInlineDecl() {} // expected-warning{{'ImportMemberTmpl::staticInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif #ifdef GNU -// expected-warning@+3{{ImportMemberTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} -// expected-warning@+3{{ImportMemberTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} +template inline void ImportMemberTmpl::normalInlineDef() {} // expected-warning{{ImportMemberTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} +template inline void ImportMemberTmpl::staticInlineDef() {} // expected-warning{{ImportMemberTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} +#else +template inline void ImportMemberTmpl::normalInlineDef() {} // expected-warning{{ImportMemberTmpl::normalInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template inline void ImportMemberTmpl::staticInlineDef() {} // expected-warning{{ImportMemberTmpl::staticInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} #endif -template inline void ImportMemberTmpl::normalInlineDef() {} -template inline void ImportMemberTmpl::staticInlineDef() {} #if __has_feature(cxx_variable_templates) template int ImportMemberTmpl::StaticFieldDef; // expected-error{{definition of dllimport static field not allowed}} @@ -1240,20 +1266,32 @@ template struct ImportClsTmplMemTmpl { template __declspec(dllimport) void normalDecl(); template __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template __declspec(dllimport) void normalInlineDef(); template __declspec(dllimport) static void staticDecl(); template __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template __declspec(dllimport) static void staticInlineDef(); #ifdef GNU // expected-warning@+5{{'dllimport' attribute ignored on inline function}} - // expected-warning@+5{{'dllimport' attribute ignored on inline function}} - // expected-warning@+5{{'dllimport' attribute ignored on inline function}} - // expected-warning@+5{{'dllimport' attribute ignored on inline function}} + // expected-warning@+8{{'dllimport' attribute ignored on inline function}} + // expected-warning@+8{{'dllimport' attribute ignored on inline function}} + // expected-warning@+11{{'dllimport' attribute ignored on inline function}} #endif template __declspec(dllimport) void normalInclass() {} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template __declspec(dllimport) inline void normalInlineDecl(); template __declspec(dllimport) static void staticInclass() {} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template __declspec(dllimport) static inline void staticInlineDecl(); #if __has_feature(cxx_variable_templates) @@ -1269,16 +1307,22 @@ struct ImportClsTmplMemTmpl { }; template template void ImportClsTmplMemTmpl::normalDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -template template void ImportClsTmplMemTmpl::normalInlineDecl() {} template template void ImportClsTmplMemTmpl::staticDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef GNU +template template void ImportClsTmplMemTmpl::normalInlineDecl() {} template template void ImportClsTmplMemTmpl::staticInlineDecl() {} +#else +template template void ImportClsTmplMemTmpl::normalInlineDecl() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template template void ImportClsTmplMemTmpl::staticInlineDecl() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif #ifdef GNU -// expected-warning@+3{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} -// expected-warning@+3{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} +template template inline void ImportClsTmplMemTmpl::normalInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} +template template inline void ImportClsTmplMemTmpl::staticInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} +#else +template template inline void ImportClsTmplMemTmpl::normalInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template template inline void ImportClsTmplMemTmpl::staticInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} #endif -template template inline void ImportClsTmplMemTmpl::normalInlineDef() {} -template template inline void ImportClsTmplMemTmpl::staticInlineDef() {} #if __has_feature(cxx_variable_templates) template template int ImportClsTmplMemTmpl::StaticFieldDef; // expected-warning{{definition of dllimport static field}}