MSVC allows

  template<typename T> void f() {}
  template<> __declspec(dllimport) void f<int>() {}

without f<int> being specified as inline. This only works with dllimport
and seems to have no effect on linkage without it.
>From cdfa0b7385ed11dc25292c9503424afd369c5967 Mon Sep 17 00:00:00 2001
From: Nico Rieck <[email protected]>
Date: Fri, 23 May 2014 10:55:33 +0200
Subject: [PATCH 3/7] MS ABI: Treat dllimport explicit specializations as
 inline

---
 lib/CodeGen/CGCXXABI.h                |  4 ++++
 lib/CodeGen/CodeGenModule.cpp         |  7 +++++++
 lib/CodeGen/MicrosoftCXXABI.cpp       |  2 ++
 lib/Sema/SemaDecl.cpp                 | 20 +++++++++++++-------
 test/CodeGenCXX/dllimport-members.cpp | 28 ++++++++++++++--------------
 test/CodeGenCXX/dllimport.cpp         | 24 ++++++++++++------------
 test/SemaCXX/dllimport.cpp            | 27 +++++++++++++++++++--------
 7 files changed, 71 insertions(+), 41 deletions(-)

diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 615ec23..8336549 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -382,6 +382,10 @@ public:
   /// class definition should have linkonce linkage.
   virtual bool isInlineInitializedStaticDataMemberLinkOnce() { return false; }
 
+  /// \brief Returns true iff explicit function template specializations
+  /// declared dllimport are treated as inline.
+  virtual bool treatImportedExplicitSpecializationAsInline() { return false; }
+
   /**************************** Array cookies ******************************/
 
   /// Returns the extra size required in order to store the array
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 0d781fd..34c1a5f 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1962,6 +1962,13 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(
       isVarDeclInlineInitializedStaticDataMember(cast<VarDecl>(D)))
     return llvm::GlobalValue::LinkOnceODRLinkage;
 
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    if (getCXXABI().treatImportedExplicitSpecializationAsInline() &&
+        FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+        FD->hasAttr<DLLImportAttr>())
+      return llvm::GlobalValue::AvailableExternallyLinkage;
+  }
+
   // C++ doesn't have tentative definitions and thus cannot have common
   // linkage.
   if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 65b98d2..abe8d27 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -52,6 +52,8 @@ public:
 
   bool isInlineInitializedStaticDataMemberLinkOnce()  override{ return true; }
 
+  bool treatImportedExplicitSpecializationAsInline() override { return true; }
+
   llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
                                       llvm::Value *ptr,
                                       QualType type) override;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0fea7ed..d85d09f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -9767,14 +9767,20 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
   if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>())
     ResolveExceptionSpec(D->getLocation(), FPT);
 
-  // dllimport cannot be applied to non-inline function definitions.
-  if (FD->hasAttr<DLLImportAttr>() && !FD->isInlined() &&
-      !FD->isTemplateInstantiation()) {
-    assert(!FD->hasAttr<DLLExportAttr>());
-    Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition);
-    FD->setInvalidDecl();
-    return D;
+  // Checking attributes of current function definition
+  if (const DLLImportAttr *DA = FD->getAttr<DLLImportAttr>()) {
+    // dllimport attribute cannot be directly applied to non-inline function
+    // definitions. MSVC treats explicit specializations as inline.
+    bool TreatAsInline = Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+              FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization &&
+              FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+    if (!DA->isInherited() && !FD->isInlined() && !TreatAsInline &&
+        !FD->isTemplateInstantiation()) {
+      Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition);
+      FD->setInvalidDecl();
+    }
   }
+
   // We want to attach documentation to original Decl (which might be
   // a function template).
   ActOnDocumentableDecl(D);
diff --git a/test/CodeGenCXX/dllimport-members.cpp b/test/CodeGenCXX/dllimport-members.cpp
index 1822a27..7577448 100644
--- a/test/CodeGenCXX/dllimport-members.cpp
+++ b/test/CodeGenCXX/dllimport-members.cpp
@@ -528,11 +528,11 @@ USE(MemFunTmpl::importedStatic<ExplicitInst_Imported>)
 template<> __declspec(dllimport) void MemFunTmpl::importedNormal<ExplicitSpec_Imported>();
 USEMF(MemFunTmpl, importedNormal<ExplicitSpec_Imported>)
 
-// M32-DAG-FIXME: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
-// M64-DAG-FIXME: declare dllimport                void @"\01??$importedNormal@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
+// M64-DAG: declare dllimport                void @"\01??$importedNormal@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
 #ifdef MSABI
-//template<> __declspec(dllimport) void MemFunTmpl::importedNormal<ExplicitSpec_Def_Imported>() {}
-//USEMF(MemFunTmpl, importedNormal<ExplicitSpec_Def_Imported>)
+template<> __declspec(dllimport) void MemFunTmpl::importedNormal<ExplicitSpec_Def_Imported>() {}
+USEMF(MemFunTmpl, importedNormal<ExplicitSpec_Def_Imported>)
 #endif
 
 // M32-DAG: declare dllimport x86_thiscallcc void @"\01??$importedNormal@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
@@ -548,10 +548,10 @@ USEMF(MemFunTmpl, importedNormal<ExplicitSpec_InlineDef_Imported>)
 template<> __declspec(dllimport) void MemFunTmpl::importedStatic<ExplicitSpec_Imported>();
 USE(MemFunTmpl::importedStatic<ExplicitSpec_Imported>)
 
-// MSC-DAG-FIXME: declare dllimport                void @"\01??$importedStatic@UExplicitSpec_Def_Imported@@@MemFunTmpl@@SAXXZ"()
+// MSC-DAG: declare dllimport                void @"\01??$importedStatic@UExplicitSpec_Def_Imported@@@MemFunTmpl@@SAXXZ"()
 #ifdef MSABI
-//template<> __declspec(dllimport) void MemFunTmpl::importedStatic<ExplicitSpec_Def_Imported>() {}
-//USE(MemFunTmpl::importedStatic<ExplicitSpec_Def_Imported>)
+template<> __declspec(dllimport) void MemFunTmpl::importedStatic<ExplicitSpec_Def_Imported>() {}
+USE(MemFunTmpl::importedStatic<ExplicitSpec_Def_Imported>)
 #endif
 
 // MSC-DAG: declare dllimport                void @"\01??$importedStatic@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@SAXXZ"()
@@ -613,11 +613,11 @@ USE(MemFunTmpl::staticDef<ExplicitInst_Imported>)
 template<> __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitSpec_Imported>();
 USEMF(MemFunTmpl, normalDef<ExplicitSpec_Imported>)
 
-// M32-DAG-FIXME: declare dllimport x86_thiscallcc void @"\01??$normalDef@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
-// M64-DAG-FIXME: declare dllimport                void @"\01??$normalDef@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
+// M32-DAG: declare dllimport x86_thiscallcc void @"\01??$normalDef@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
+// M64-DAG: declare dllimport                void @"\01??$normalDef@UExplicitSpec_Def_Imported@@@MemFunTmpl@@QEAAXXZ"(%struct.MemFunTmpl*)
 #ifdef MSABI
-//template<> __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitSpec_Def_Imported>() {}
-//USEMF(MemFunTmpl, normalDef<ExplicitSpec_Def_Imported>)
+template<> __declspec(dllimport) void MemFunTmpl::normalDef<ExplicitSpec_Def_Imported>() {}
+USEMF(MemFunTmpl, normalDef<ExplicitSpec_Def_Imported>)
 #endif
 
 // M32-DAG: declare dllimport x86_thiscallcc void @"\01??$normalDef@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@QAEXXZ"(%struct.MemFunTmpl*)
@@ -633,10 +633,10 @@ USEMF(MemFunTmpl, normalDef<ExplicitSpec_InlineDef_Imported>)
 template<> __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitSpec_Imported>();
 USE(MemFunTmpl::staticDef<ExplicitSpec_Imported>)
 
-// MSC-DAG-FIXME: declare dllimport void @"\01??$staticDef@UExplicitSpec_Def_Imported@@@MemFunTmpl@@SAXXZ"()
+// MSC-DAG: declare dllimport void @"\01??$staticDef@UExplicitSpec_Def_Imported@@@MemFunTmpl@@SAXXZ"()
 #ifdef MSABI
-//template<> __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitSpec_Def_Imported>() {}
-//USE(MemFunTmpl::staticDef<ExplicitSpec_Def_Imported>)
+template<> __declspec(dllimport) void MemFunTmpl::staticDef<ExplicitSpec_Def_Imported>() {}
+USE(MemFunTmpl::staticDef<ExplicitSpec_Def_Imported>)
 #endif
 
 // MSC-DAG: declare dllimport void @"\01??$staticDef@UExplicitSpec_InlineDef_Imported@@@MemFunTmpl@@SAXXZ"()
diff --git a/test/CodeGenCXX/dllimport.cpp b/test/CodeGenCXX/dllimport.cpp
index 87f3c88..551229e 100644
--- a/test/CodeGenCXX/dllimport.cpp
+++ b/test/CodeGenCXX/dllimport.cpp
@@ -411,11 +411,11 @@ USE(importedFuncTmpl<ExplicitInst_Imported>)
 template<> __declspec(dllimport) void importedFuncTmplDecl<ExplicitSpec_Imported>();
 USE(importedFuncTmplDecl<ExplicitSpec_Imported>)
 
-// MSC-DAG-FIXME: declare dllimport void @"\01??$importedFuncTmplDecl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
-// MO1-DAG-FIXME: define available_externally dllimport void @"\01??$importedFuncTmplDecl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
+// MSC-DAG: declare dllimport void @"\01??$importedFuncTmplDecl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
+// MO1-DAG: define available_externally dllimport void @"\01??$importedFuncTmplDecl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
 #ifdef MSABI
-//template<> __declspec(dllimport) void importedFuncTmplDecl<ExplicitSpec_Def_Imported>() {}
-//USE(importedFuncTmplDecl<ExplicitSpec_Def_Imported>)
+template<> __declspec(dllimport) void importedFuncTmplDecl<ExplicitSpec_Def_Imported>() {}
+USE(importedFuncTmplDecl<ExplicitSpec_Def_Imported>)
 #endif
 
 // MSC-DAG: declare dllimport void @"\01??$importedFuncTmplDecl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
@@ -431,11 +431,11 @@ USE(importedFuncTmplDecl<ExplicitSpec_InlineDef_Imported>)
 template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Imported>();
 USE(importedFuncTmpl<ExplicitSpec_Imported>)
 
-// MSC-DAG-FIXME: declare dllimport void @"\01??$importedFuncTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
-// MO1-DAG-FIXME: define available_externally dllimport void @"\01??$importedFuncTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
+// MSC-DAG: declare dllimport void @"\01??$importedFuncTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
+// MO1-DAG: define available_externally dllimport void @"\01??$importedFuncTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
 #ifdef MSABI
-//template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Def_Imported>() {}
-//USE(importedFuncTmpl<ExplicitSpec_Def_Imported>)
+template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Def_Imported>() {}
+USE(importedFuncTmpl<ExplicitSpec_Def_Imported>)
 #endif
 
 // MSC-DAG: declare dllimport void @"\01??$importedFuncTmpl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
@@ -488,11 +488,11 @@ USE(inlineFuncTmpl<ExplicitInst_Imported>)
 template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Imported>();
 USE(funcTmpl<ExplicitSpec_Imported>)
 
-// MSC-DAG-FIXME: declare dllimport void @"\01??$funcTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
-// MO1-DAG-FIXME: define available_externally dllimport void @"\01??$funcTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
+// MSC-DAG: declare dllimport void @"\01??$funcTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
+// MO1-DAG: define available_externally dllimport void @"\01??$funcTmpl@UExplicitSpec_Def_Imported@@@@YAXXZ"()
 #ifdef MSABI
-//template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Def_Imported>() {}
-//USE(funcTmpl<ExplicitSpec_Def_Imported>)
+template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Def_Imported>() {}
+USE(funcTmpl<ExplicitSpec_Def_Imported>)
 #endif
 
 // MSC-DAG: declare dllimport void @"\01??$funcTmpl@UExplicitSpec_InlineDef_Imported@@@@YAXXZ"()
diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp
index 2e7bd14..1e15e7e 100644
--- a/test/SemaCXX/dllimport.cpp
+++ b/test/SemaCXX/dllimport.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i686-win32     -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -triple x86_64-win32   -fsyntax-only -verify -std=c++1y %s
+// RUN: %clang_cc1 -triple i686-win32     -fsyntax-only -verify -std=c++11 -DMSABI %s
+// RUN: %clang_cc1 -triple x86_64-win32   -fsyntax-only -verify -std=c++1y -DMSABI %s
 // RUN: %clang_cc1 -triple i686-mingw32   -fsyntax-only -verify -std=c++1y %s
 // RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c++11 %s
 
@@ -249,11 +249,20 @@ extern template void importedFuncTmpl<ExplicitDecl_Imported>();
 // likely a bug because an implicit instantiation is accepted.
 template void importedFuncTmpl<ExplicitInst_Imported>();
 
-// Import specialization of an imported function template. A definition must be
-// declared inline.
+// Import specialization of an imported function template.
+template<> __declspec(dllimport) void importedFuncTmplDecl<ExplicitSpec_Imported>();
+template<> __declspec(dllimport) void importedFuncTmplDecl<ExplicitSpec_Def_Imported>() {} // error on mingw
+template<> __declspec(dllimport) inline void importedFuncTmplDecl<ExplicitSpec_InlineDef_Imported>() {}
+#ifndef MSABI
+// expected-error@-3{{dllimport cannot be applied to non-inline function definition}}
+#endif
+
 template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Imported>();
-template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Def_Imported>() {} // error on mingw
 template<> __declspec(dllimport) inline void importedFuncTmpl<ExplicitSpec_InlineDef_Imported>() {}
+#ifndef MSABI
+// expected-error@-3{{dllimport cannot be applied to non-inline function definition}}
+#endif
 
 // Not importing specialization of an imported function template without
 // explicit dllimport.
@@ -268,8 +277,10 @@ extern template __declspec(dllimport) void inlineFuncTmpl<ExplicitDecl_Imported>
 template __declspec(dllimport) void funcTmpl<ExplicitInst_Imported>();
 template __declspec(dllimport) void inlineFuncTmpl<ExplicitInst_Imported>();
 
-// Import specialization of a non-imported function template. A definition must
-// be declared inline.
+// Import specialization of a non-imported function template.
 template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Imported>();
-template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Def_Imported>() {} // error on mingw
 template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {}
+#ifndef MSABI
+// expected-error@-3{{dllimport cannot be applied to non-inline function definition}}
+#endif
-- 
1.9.0.msysgit.0

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to