Re-commit r324991 "Fix for PR32992. Static const classes not exported."

Fix for PR32992. Static const classes not exported.

Patch by zahiraam!

(This re-lands the commit, but using S.MarkVariableReferenced instead of
S.PendingInstantiations.push_back, and with an additional test.)

Differential Revision: https://reviews.llvm.org/D42968

llvm-svn: 326089
This commit is contained in:
Hans Wennborg 2018-02-26 15:03:59 +00:00
parent 832f90fa0c
commit 83665e6d36
2 changed files with 41 additions and 3 deletions

View File

@ -5476,7 +5476,7 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
} }
} }
static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) {
Attr *ClassAttr = getDLLAttr(Class); Attr *ClassAttr = getDLLAttr(Class);
if (!ClassAttr) if (!ClassAttr)
return; return;
@ -5491,6 +5491,14 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) {
return; return;
for (Decl *Member : Class->decls()) { for (Decl *Member : Class->decls()) {
// Defined static variables that are members of an exported base
// class must be marked export too.
auto *VD = dyn_cast<VarDecl>(Member);
if (VD && Member->getAttr<DLLExportAttr>() &&
VD->getStorageClass() == SC_Static &&
TSK == TSK_ImplicitInstantiation)
S.MarkVariableReferenced(VD->getLocation(), VD);
auto *MD = dyn_cast<CXXMethodDecl>(Member); auto *MD = dyn_cast<CXXMethodDecl>(Member);
if (!MD) if (!MD)
continue; continue;
@ -10902,12 +10910,12 @@ void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
void Sema::referenceDLLExportedClassMethods() { void Sema::referenceDLLExportedClassMethods() {
if (!DelayedDllExportClasses.empty()) { 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. // be called again, so use a local copy of DelayedDllExportClasses.
SmallVector<CXXRecordDecl *, 4> WorkList; SmallVector<CXXRecordDecl *, 4> WorkList;
std::swap(DelayedDllExportClasses, WorkList); std::swap(DelayedDllExportClasses, WorkList);
for (CXXRecordDecl *Class : WorkList) for (CXXRecordDecl *Class : WorkList)
ReferenceDllExportedMethods(*this, Class); ReferenceDllExportedMembers(*this, Class);
} }
} }

View File

@ -29,6 +29,8 @@ struct External { int v; };
// The vftable for struct W is comdat largest because we have RTTI. // The vftable for struct W is comdat largest because we have RTTI.
// M32-DAG: $"\01??_7W@@6B@" = comdat largest // M32-DAG: $"\01??_7W@@6B@" = comdat largest
// M32-DAG: $"\01?smember@?$Base@H@PR32992@@0HA" = comdat any
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Globals // Globals
@ -94,7 +96,35 @@ inline int __declspec(dllexport) inlineStaticLocalsFunc() {
return x++; return x++;
} }
namespace PR32992 {
// Static data members of a instantiated base class should be exported.
template <class T>
class Base {
virtual void myfunc() {}
static int smember;
};
// MSC-DAG: @"\01?smember@?$Base@H@PR32992@@0HA" = weak_odr dso_local dllexport global i32 77, comdat, align 4
template <class T> int Base<T>::smember = 77;
template <class T>
class __declspec(dllexport) Derived2 : Base<T> {
void myfunc() {}
};
class Derived : public Derived2<int> {
void myfunc() {}
};
} // namespace PR32992
namespace PR32992_1 {
namespace a { enum b { c }; }
template <typename> class d {
static constexpr a::b e = a::c;
};
namespace f {
template <typename g = int> class h : d<g> {};
}
using f::h;
class __declspec(dllexport) i : h<> {};
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Variable templates // Variable templates