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

Reply via email to