Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -5476,7 +5476,7 @@ } } -static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { +static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); if (!ClassAttr) return; @@ -5491,6 +5491,16 @@ return; for (Decl *Member : Class->decls()) { + // Defined static variables that are members of an exported base + // class must be marked export too. Push them to implicit instantiation + // queue. + auto *VD = dyn_cast(Member); + if (VD && Member->getAttr() && + VD->getStorageClass() == SC_Static && + TSK == TSK_ImplicitInstantiation) + S.PendingInstantiations.push_back( + std::make_pair(VD, VD->getLocation())); + auto *MD = dyn_cast(Member); if (!MD) continue; @@ -10902,12 +10912,12 @@ void Sema::referenceDLLExportedClassMethods() { if (!DelayedDllExportClasses.empty()) { - // Calling ReferenceDllExportedMethods might cause the current function to + // Calling ReferenceDllExportedMembers might cause the current function to // be called again, so use a local copy of DelayedDllExportClasses. SmallVector WorkList; std::swap(DelayedDllExportClasses, WorkList); for (CXXRecordDecl *Class : WorkList) - ReferenceDllExportedMethods(*this, Class); + ReferenceDllExportedMembers(*this, Class); } } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4366,8 +4366,14 @@ std::make_pair(Var, PointOfInstantiation)); } else if (TSK == TSK_ImplicitInstantiation) { // Warn about missing definition at the end of translation unit. + // Only if the variables is not defined. + bool isStaticVarWithnoDef = Var->hasAttr() && + Var->isStaticDataMember() && + Var->hasInit() && + !Var->hasDefinition(); if (AtEndOfTU && !getDiagnostics().hasErrorOccurred() && - !getSourceManager().isInSystemHeader(PatternDecl->getLocStart())) { + !getSourceManager().isInSystemHeader(PatternDecl->getLocStart()) && + !isStaticVarWithnoDef) { Diag(PointOfInstantiation, diag::warn_var_template_missing) << Var; Diag(PatternDecl->getLocation(), diag::note_forward_template_decl); Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -28,6 +28,7 @@ // The vftable for struct W is comdat largest because we have RTTI. // M32-DAG: $"\01??_7W@@6B@" = comdat largest +// M32-DAG: $"\01?smember@?$Base@H@PR32992@@0HA" = comdat any //===----------------------------------------------------------------------===// @@ -977,3 +978,37 @@ // MSVC2015-DAG: define weak_odr dllexport {{.+}}ACE_Service_Object@@Q{{.+}}@$$Q // The declarations should not be exported. // MSVC2013-NOT: define weak_odr dllexport {{.+}}ACE_Service_Object@@Q{{.+}}@$$Q + +namespace PR32992 { +// Static data members of a instantiated base class should be exported. +template +class Base { + virtual void myfunc() {} + static int smember; +}; +// MS-DAG: @"\01?smember@?$Base@H@PR32992@@0HA" = weak_odr dllexport global i32 77, comdat, align 4 +template int Base::smember = 77; +template +class __declspec(dllexport) Derived2 : Base { + void myfunc() {} +}; +class Derived : public Derived2 { + void myfunc() {} +}; +} // namespace PR32992 + + +namespace PR32992_1 { + // expected-no-diagnostics +namespace a { + enum b { c }; +} +template class d { + static constexpr a::b e = a::c; +}; +namespace f { + template class h : d {}; +} +using f::h; +class __declspec(dllexport) i : h<> {}; +} // namespace PR32992