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