@@ -1793,6 +1793,37 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
17931793 ThisTy, VTT, VTTTy, nullptr );
17941794}
17951795
1796+ // Check if any non-inline method has the specified attribute.
1797+ template <typename T>
1798+ static bool CXXRecordNonInlineHasAttr (const CXXRecordDecl *RD) {
1799+ for (const auto *D : RD->noload_decls ()) {
1800+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
1801+ if (FD->isInlined () || FD->doesThisDeclarationHaveABody () ||
1802+ FD->isPureVirtual ())
1803+ continue ;
1804+ if (D->hasAttr <T>())
1805+ return true ;
1806+ }
1807+ }
1808+
1809+ return false ;
1810+ }
1811+
1812+ static void setVTableSelectiveDLLImportExport (CodeGenModule &CGM,
1813+ llvm::GlobalVariable *VTable,
1814+ const CXXRecordDecl *RD) {
1815+ if (VTable->getDLLStorageClass () !=
1816+ llvm::GlobalVariable::DefaultStorageClass ||
1817+ RD->hasAttr <DLLImportAttr>() || RD->hasAttr <DLLExportAttr>())
1818+ return ;
1819+
1820+ if (CGM.getVTables ().isVTableExternal (RD)) {
1821+ if (CXXRecordNonInlineHasAttr<DLLImportAttr>(RD))
1822+ VTable->setDLLStorageClass (llvm::GlobalValue::DLLImportStorageClass);
1823+ } else if (CXXRecordNonInlineHasAttr<DLLExportAttr>(RD))
1824+ VTable->setDLLStorageClass (llvm::GlobalValue::DLLExportStorageClass);
1825+ }
1826+
17961827void ItaniumCXXABI::emitVTableDefinitions (CodeGenVTables &CGVT,
17971828 const CXXRecordDecl *RD) {
17981829 llvm::GlobalVariable *VTable = getAddrOfVTable (RD, CharUnits ());
@@ -1818,6 +1849,9 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
18181849 if (CGM.supportsCOMDAT () && VTable->isWeakForLinker ())
18191850 VTable->setComdat (CGM.getModule ().getOrInsertComdat (VTable->getName ()));
18201851
1852+ if (CGM.getTarget ().hasPS4DLLImportExport ())
1853+ setVTableSelectiveDLLImportExport (CGM, VTable, RD);
1854+
18211855 // Set the right visibility.
18221856 CGM.setGVProperties (VTable, RD);
18231857
@@ -1905,29 +1939,6 @@ ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base,
19051939 VTable->getValueType (), VTable, Indices, /* InBounds=*/ true , InRange);
19061940}
19071941
1908- // Check whether all the non-inline virtual methods for the class have the
1909- // specified attribute.
1910- template <typename T>
1911- static bool CXXRecordAllNonInlineVirtualsHaveAttr (const CXXRecordDecl *RD) {
1912- bool FoundNonInlineVirtualMethodWithAttr = false ;
1913- for (const auto *D : RD->noload_decls ()) {
1914- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
1915- if (!FD->isVirtualAsWritten () || FD->isInlineSpecified () ||
1916- FD->doesThisDeclarationHaveABody ())
1917- continue ;
1918- if (!D->hasAttr <T>())
1919- return false ;
1920- FoundNonInlineVirtualMethodWithAttr = true ;
1921- }
1922- }
1923-
1924- // We didn't find any non-inline virtual methods missing the attribute. We
1925- // will return true when we found at least one non-inline virtual with the
1926- // attribute. (This lets our caller know that the attribute needs to be
1927- // propagated up to the vtable.)
1928- return FoundNonInlineVirtualMethodWithAttr;
1929- }
1930-
19311942llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT (
19321943 CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
19331944 const CXXRecordDecl *NearestVBase) {
@@ -1981,26 +1992,10 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
19811992 getContext ().toCharUnitsFromBits (PAlign).getAsAlign ());
19821993 VTable->setUnnamedAddr (llvm::GlobalValue::UnnamedAddr::Global);
19831994
1984- // In MS C++ if you have a class with virtual functions in which you are using
1985- // selective member import/export, then all virtual functions must be exported
1986- // unless they are inline, otherwise a link error will result. To match this
1987- // behavior, for such classes, we dllimport the vtable if it is defined
1988- // externally and all the non-inline virtual methods are marked dllimport, and
1989- // we dllexport the vtable if it is defined in this TU and all the non-inline
1990- // virtual methods are marked dllexport.
1991- if (CGM.getTarget ().hasPS4DLLImportExport ()) {
1992- if ((!RD->hasAttr <DLLImportAttr>()) && (!RD->hasAttr <DLLExportAttr>())) {
1993- if (CGM.getVTables ().isVTableExternal (RD)) {
1994- if (CXXRecordAllNonInlineVirtualsHaveAttr<DLLImportAttr>(RD))
1995- VTable->setDLLStorageClass (llvm::GlobalValue::DLLImportStorageClass);
1996- } else {
1997- if (CXXRecordAllNonInlineVirtualsHaveAttr<DLLExportAttr>(RD))
1998- VTable->setDLLStorageClass (llvm::GlobalValue::DLLExportStorageClass);
1999- }
2000- }
2001- }
2002- CGM.setGVProperties (VTable, RD);
1995+ if (CGM.getTarget ().hasPS4DLLImportExport ())
1996+ setVTableSelectiveDLLImportExport (CGM, VTable, RD);
20031997
1998+ CGM.setGVProperties (VTable, RD);
20041999 return VTable;
20052000}
20062001
@@ -3285,7 +3280,7 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
32853280 // Import the typeinfo symbol when all non-inline virtual methods are
32863281 // imported.
32873282 if (CGM.getTarget ().hasPS4DLLImportExport ()) {
3288- if (RD && CXXRecordAllNonInlineVirtualsHaveAttr <DLLImportAttr>(RD)) {
3283+ if (RD && CXXRecordNonInlineHasAttr <DLLImportAttr>(RD)) {
32893284 GV->setDLLStorageClass (llvm::GlobalVariable::DLLImportStorageClass);
32903285 CGM.setDSOLocal (GV);
32913286 }
@@ -3938,13 +3933,13 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
39383933
39393934 // Export the typeinfo in the same circumstances as the vtable is exported.
39403935 auto GVDLLStorageClass = DLLStorageClass;
3941- if (CGM.getTarget ().hasPS4DLLImportExport ()) {
3936+ if (CGM.getTarget ().hasPS4DLLImportExport () &&
3937+ GVDLLStorageClass != llvm::GlobalVariable::DLLExportStorageClass) {
39423938 if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
39433939 const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl ());
39443940 if (RD->hasAttr <DLLExportAttr>() ||
3945- CXXRecordAllNonInlineVirtualsHaveAttr <DLLExportAttr>(RD)) {
3941+ CXXRecordNonInlineHasAttr <DLLExportAttr>(RD))
39463942 GVDLLStorageClass = llvm::GlobalVariable::DLLExportStorageClass;
3947- }
39483943 }
39493944 }
39503945
@@ -3984,9 +3979,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
39843979 CGM.setDSOLocal (GV);
39853980
39863981 TypeName->setDLLStorageClass (DLLStorageClass);
3987- GV->setDLLStorageClass (CGM.getTarget ().hasPS4DLLImportExport ()
3988- ? GVDLLStorageClass
3989- : DLLStorageClass);
3982+ GV->setDLLStorageClass (GVDLLStorageClass);
39903983
39913984 TypeName->setPartition (CGM.getCodeGenOpts ().SymbolPartition );
39923985 GV->setPartition (CGM.getCodeGenOpts ().SymbolPartition );
0 commit comments