@@ -7435,6 +7435,30 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
7435
7435
return false ;
7436
7436
}
7437
7437
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
+
7438
7462
// Explicit instantiation of a class template specialization
7439
7463
DeclResult
7440
7464
Sema::ActOnExplicitInstantiation (Scope *S,
@@ -7681,24 +7705,33 @@ Sema::ActOnExplicitInstantiation(Scope *S,
7681
7705
getDLLAttr (Specialization)->clone (getASTContext ()));
7682
7706
A->setInherited (true );
7683
7707
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);
7699
7709
}
7700
7710
}
7701
7711
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
+
7702
7735
// Set the template specialization kind. Make sure it is set before
7703
7736
// instantiating the members which will trigger ASTConsumer callbacks.
7704
7737
Specialization->setTemplateSpecializationKind (TSK);
0 commit comments