@@ -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
74397463DeclResult
74407464Sema::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);
0 commit comments