Skip to content

Commit fc78d7c

Browse files
committed
[Sema] Respect DLL attributes more faithfully
On MSVC, if an implicit instantiation already exists and an explicit instantiation definition with a DLL attribute is created, the DLL attribute still takes effect. Make clang match this behavior for exporting. Differential Revision: https://reviews.llvm.org/D26657 llvm-svn: 288682
1 parent c14916d commit fc78d7c

File tree

3 files changed

+60
-15
lines changed

3 files changed

+60
-15
lines changed

clang/lib/Sema/SemaTemplate.cpp

+48-15
Original file line numberDiff line numberDiff line change
@@ -7435,6 +7435,30 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
74357435
return false;
74367436
}
74377437

7438+
/// Make a dllexport or dllimport attr on a class template specialization take
7439+
/// effect.
7440+
static void dllExportImportClassTemplateSpecialization(
7441+
Sema &S, ClassTemplateSpecializationDecl *Def) {
7442+
auto *A = cast_or_null<InheritableAttr>(getDLLAttr(Def));
7443+
assert(A && "dllExportImportClassTemplateSpecialization called "
7444+
"on Def without dllexport or dllimport");
7445+
7446+
// We reject explicit instantiations in class scope, so there should
7447+
// never be any delayed exported classes to worry about.
7448+
assert(S.DelayedDllExportClasses.empty() &&
7449+
"delayed exports present at explicit instantiation");
7450+
S.checkClassLevelDLLAttribute(Def);
7451+
7452+
// Propagate attribute to base class templates.
7453+
for (auto &B : Def->bases()) {
7454+
if (auto *BT = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
7455+
B.getType()->getAsCXXRecordDecl()))
7456+
S.propagateDLLAttrToBaseClassTemplate(Def, A, BT, B.getLocStart());
7457+
}
7458+
7459+
S.referenceDLLExportedClassMethods();
7460+
}
7461+
74387462
// Explicit instantiation of a class template specialization
74397463
DeclResult
74407464
Sema::ActOnExplicitInstantiation(Scope *S,
@@ -7681,24 +7705,33 @@ Sema::ActOnExplicitInstantiation(Scope *S,
76817705
getDLLAttr(Specialization)->clone(getASTContext()));
76827706
A->setInherited(true);
76837707
Def->addAttr(A);
7684-
7685-
// We reject explicit instantiations in class scope, so there should
7686-
// never be any delayed exported classes to worry about.
7687-
assert(DelayedDllExportClasses.empty() &&
7688-
"delayed exports present at explicit instantiation");
7689-
checkClassLevelDLLAttribute(Def);
7690-
7691-
// Propagate attribute to base class templates.
7692-
for (auto &B : Def->bases()) {
7693-
if (auto *BT = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
7694-
B.getType()->getAsCXXRecordDecl()))
7695-
propagateDLLAttrToBaseClassTemplate(Def, A, BT, B.getLocStart());
7696-
}
7697-
7698-
referenceDLLExportedClassMethods();
7708+
dllExportImportClassTemplateSpecialization(*this, Def);
76997709
}
77007710
}
77017711

7712+
// Fix a TSK_ImplicitInstantiation followed by a
7713+
// TSK_ExplicitInstantiationDefinition
7714+
if (Old_TSK == TSK_ImplicitInstantiation &&
7715+
Specialization->hasAttr<DLLExportAttr>() &&
7716+
(Context.getTargetInfo().getCXXABI().isMicrosoft() ||
7717+
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) {
7718+
// In the MS ABI, an explicit instantiation definition can add a dll
7719+
// attribute to a template with a previous implicit instantiation.
7720+
// MinGW doesn't allow this. We limit clang to only adding dllexport, to
7721+
// avoid potentially strange codegen behavior. For example, if we extend
7722+
// this conditional to dllimport, and we have a source file calling a
7723+
// method on an implicitly instantiated template class instance and then
7724+
// declaring a dllimport explicit instantiation definition for the same
7725+
// template class, the codegen for the method call will not respect the
7726+
// dllimport, while it will with cl. The Def will already have the DLL
7727+
// attribute, since the Def and Specialization will be the same in the
7728+
// case of Old_TSK == TSK_ImplicitInstantiation, and we already added the
7729+
// attribute to the Specialization; we just need to make it take effect.
7730+
assert(Def == Specialization &&
7731+
"Def and Specialization should match for implicit instantiation");
7732+
dllExportImportClassTemplateSpecialization(*this, Def);
7733+
}
7734+
77027735
// Set the template specialization kind. Make sure it is set before
77037736
// instantiating the members which will trigger ASTConsumer callbacks.
77047737
Specialization->setTemplateSpecializationKind(TSK);

clang/test/CodeGenCXX/dllexport.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,13 @@ USEMEMFUNC(ExplicitInstantiationDeclExportedDefTemplate<int>, f);
771771
// M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstantiationDeclExportedDefTemplate* @"\01??0?$ExplicitInstantiationDeclExportedDefTemplate@H@@QAE@XZ"
772772
// G32-DAG: define weak_odr x86_thiscallcc void @_ZN44ExplicitInstantiationDeclExportedDefTemplateIiE1fEv
773773

774+
template <typename T> struct ImplicitInstantiationExplicitInstantiationDefExportedTemplate { void f() {} };
775+
ImplicitInstantiationExplicitInstantiationDefExportedTemplate<int> ImplicitInstantiationExplicitInstantiationDefExportedTemplateInstance;
776+
template class __declspec(dllexport) ImplicitInstantiationExplicitInstantiationDefExportedTemplate<int>;
777+
USEMEMFUNC(ImplicitInstantiationExplicitInstantiationDefExportedTemplate<int>, f);
778+
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ImplicitInstantiationExplicitInstantiationDefExportedTemplate@H@@QAEXXZ"
779+
// G32-DAG: define weak_odr x86_thiscallcc void @_ZN61ImplicitInstantiationExplicitInstantiationDefExportedTemplateIiE1fEv
780+
774781
namespace { struct InternalLinkageType {}; }
775782
struct __declspec(dllexport) PR23308 {
776783
void f(InternalLinkageType*);

clang/test/CodeGenCXX/windows-itanium-dllexport.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ template class __declspec(dllexport) c<char>;
2323
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcEaSERKS0_
2424
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
2525

26+
c<double> g;
27+
template class __declspec(dllexport) c<double>;
28+
29+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_
30+
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv

0 commit comments

Comments
 (0)