Author: hans Date: Wed Feb 1 12:52:53 2017 New Revision: 293800 URL: http://llvm.org/viewvc/llvm-project?rev=293800&view=rev Log: 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 <typename> __declspec(dllimport) int f(); template <typename> inline int f() { return 42; } int useit() { return f<int>(); } 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 Modified: cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/CodeGenCXX/dllimport.cpp cfe/trunk/test/SemaCXX/dllimport.cpp Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=293800&r1=293799&r2=293800&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Feb 1 12:52:53 2017 @@ -5702,13 +5702,17 @@ static void checkDLLAttributeRedeclarati if (OldDecl->isInvalidDecl()) return; + bool IsTemplate = false; if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) { OldDecl = OldTD->getTemplatedDecl(); + IsTemplate = true; if (!IsSpecialization) IsDefinition = false; } - if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl)) + if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl)) { NewDecl = NewTD->getTemplatedDecl(); + IsTemplate = true; + } if (!OldDecl || !NewDecl) return; @@ -5761,9 +5765,10 @@ static void checkDLLAttributeRedeclarati } // 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<VarDecl>(NewDecl)) { @@ -5778,7 +5783,8 @@ static void checkDLLAttributeRedeclarati 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(), Modified: cfe/trunk/test/CodeGenCXX/dllimport.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllimport.cpp?rev=293800&r1=293799&r2=293800&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/dllimport.cpp (original) +++ cfe/trunk/test/CodeGenCXX/dllimport.cpp Wed Feb 1 12:52:53 2017 @@ -405,17 +405,17 @@ USE(inlineFuncTmpl1<ImplicitInst_Importe template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {} USE(inlineFuncTmpl2<ImplicitInst_Imported>) -// 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<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl(); template<typename T> void inlineFuncTmplDecl() {} USE(inlineFuncTmplDecl<ImplicitInst_Imported>) -// 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<typename T> __declspec(dllimport) void inlineFuncTmplDef(); template<typename T> inline void inlineFuncTmplDef() {} @@ -449,7 +449,7 @@ USE(funcTmplRedecl3<ImplicitInst_NotImpo // 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<typename T> friend __declspec(dllimport) void funcTmplFriend1(); Modified: cfe/trunk/test/SemaCXX/dllimport.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllimport.cpp?rev=293800&r1=293799&r2=293800&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/dllimport.cpp (original) +++ cfe/trunk/test/SemaCXX/dllimport.cpp Wed Feb 1 12:52:53 2017 @@ -396,20 +396,28 @@ template<typename T> void __declspec(dll template<typename T> __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<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {} -template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {} +#ifdef GNU // MinGW always ignores dllimport on inline functions. -template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl(); +template<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {} // expected-warning{{'dllimport' attribute ignored on inline function}} +template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {} // expected-warning{{'dllimport' attribute ignored on inline function}} + +template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}} template<typename T> void inlineFuncTmplDecl() {} template<typename T> __declspec(dllimport) void inlineFuncTmplDef(); -template<typename T> inline void inlineFuncTmplDef() {} +template<typename T> 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<typename T> __declspec(dllimport) inline void inlineFuncTmpl1() {} +template<typename T> inline void __attribute__((dllimport)) inlineFuncTmpl2() {} + +template<typename T> __declspec(dllimport) inline void inlineFuncTmplDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +template<typename T> void inlineFuncTmplDecl() {} // expected-warning{{'inlineFuncTmplDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} + +template<typename T> __declspec(dllimport) void inlineFuncTmplDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} +template<typename T> inline void inlineFuncTmplDef() {} // expected-warning{{'inlineFuncTmplDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif // Redeclarations template<typename T> __declspec(dllimport) void funcTmplRedecl1(); @@ -436,7 +444,9 @@ struct FuncTmplFriend { 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}} #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<typename T> friend __declspec(dllimport) inline void funcTmplFriend5(); }; @@ -444,6 +454,9 @@ template<typename T> __declspec(dllimpor 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{{redeclaration of 'funcTmplFriend4' cannot add 'dllimport' attribute}} +#ifdef MS +// expected-warning@+2{{'funcTmplFriend5' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#endif template<typename T> inline void funcTmplFriend5() {} // External linkage is required. @@ -827,21 +840,28 @@ __declspec(dllimport) constexpr int Memb struct ImportMemberTmpl { template<typename T> __declspec(dllimport) void normalDecl(); template<typename T> __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<typename T> __declspec(dllimport) void normalInlineDef(); template<typename T> __declspec(dllimport) static void staticDecl(); template<typename T> __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<typename T> __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<typename T> __declspec(dllimport) void normalInclass() {} // expected-warning{{'dllimport' attribute ignored on inline function}} + template<typename T> __declspec(dllimport) inline void normalInlineDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}} + template<typename T> __declspec(dllimport) static void staticInclass() {} // expected-warning{{'dllimport' attribute ignored on inline function}} + template<typename T> __declspec(dllimport) static inline void staticInlineDecl(); // expected-warning{{'dllimport' attribute ignored on inline function}} +#else template<typename T> __declspec(dllimport) void normalInclass() {} - template<typename T> __declspec(dllimport) inline void normalInlineDecl(); + template<typename T> __declspec(dllimport) inline void normalInlineDecl(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} template<typename T> __declspec(dllimport) static void staticInclass() {} - template<typename T> __declspec(dllimport) static inline void staticInlineDecl(); + template<typename T> __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<typename T> __declspec(dllimport) static int StaticField; @@ -856,16 +876,22 @@ struct ImportMemberTmpl { }; template<typename T> void ImportMemberTmpl::normalDef() {} // expected-warning{{'ImportMemberTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -template<typename T> void ImportMemberTmpl::normalInlineDecl() {} template<typename T> void ImportMemberTmpl::staticDef() {} // expected-warning{{'ImportMemberTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef GNU // dllimport was ignored above +template<typename T> void ImportMemberTmpl::normalInlineDecl() {} template<typename T> void ImportMemberTmpl::staticInlineDecl() {} +#else // dllimport dropped here +template<typename T> void ImportMemberTmpl::normalInlineDecl() {} // expected-warning{{'ImportMemberTmpl::normalInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template<typename T> 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<typename T> inline void ImportMemberTmpl::normalInlineDef() {} // expected-warning{{ImportMemberTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} +template<typename T> inline void ImportMemberTmpl::staticInlineDef() {} // expected-warning{{ImportMemberTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} +#else +template<typename T> inline void ImportMemberTmpl::normalInlineDef() {} // expected-warning{{ImportMemberTmpl::normalInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template<typename T> inline void ImportMemberTmpl::staticInlineDef() {} // expected-warning{{ImportMemberTmpl::staticInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} #endif -template<typename T> inline void ImportMemberTmpl::normalInlineDef() {} -template<typename T> inline void ImportMemberTmpl::staticInlineDef() {} #if __has_feature(cxx_variable_templates) template<typename T> int ImportMemberTmpl::StaticFieldDef; // expected-error{{definition of dllimport static field not allowed}} @@ -1240,20 +1266,32 @@ template<typename T> struct ImportClsTmplMemTmpl { template<typename U> __declspec(dllimport) void normalDecl(); template<typename U> __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<typename U> __declspec(dllimport) void normalInlineDef(); template<typename U> __declspec(dllimport) static void staticDecl(); template<typename U> __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<typename U> __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<typename U> __declspec(dllimport) void normalInclass() {} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template<typename U> __declspec(dllimport) inline void normalInlineDecl(); template<typename U> __declspec(dllimport) static void staticInclass() {} +#ifdef MS +// expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} +#endif template<typename U> __declspec(dllimport) static inline void staticInlineDecl(); #if __has_feature(cxx_variable_templates) @@ -1269,16 +1307,22 @@ struct ImportClsTmplMemTmpl { }; template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalInlineDecl() {} template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::staticDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +#ifdef GNU +template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalInlineDecl() {} template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::staticInlineDecl() {} +#else +template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::normalInlineDecl() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDecl' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template<typename T> template<typename U> void ImportClsTmplMemTmpl<T>::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<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared inline; 'dllimport' attribute ignored}} +template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared inline; 'dllimport' attribute ignored}} +#else +template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::normalInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} +template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {} // expected-warning{{'ImportClsTmplMemTmpl::staticInlineDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} #endif -template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::normalInlineDef() {} -template<typename T> template<typename U> inline void ImportClsTmplMemTmpl<T>::staticInlineDef() {} #if __has_feature(cxx_variable_templates) template<typename T> template<typename U> int ImportClsTmplMemTmpl<T>::StaticFieldDef; // expected-warning{{definition of dllimport static field}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits