From a70b39abffb42eb85fd2dd7960ec9dc7ae38510c Mon Sep 17 00:00:00 2001 From: Arthur Eubanks Date: Wed, 15 Jun 2022 09:44:43 -0700 Subject: [PATCH] [clang] Don't emit type test/assume for virtual classes that should never participate in WPD Reviewed By: pcc Differential Revision: https://reviews.llvm.org/D127876 --- clang/docs/LTOVisibility.rst | 15 ++++++++------- clang/lib/CodeGen/CGClass.cpp | 4 ++-- clang/lib/CodeGen/CGVTables.cpp | 10 +++++----- clang/lib/CodeGen/CodeGenModule.h | 8 ++++---- clang/lib/CodeGen/ItaniumCXXABI.cpp | 4 ++-- .../test/CodeGenCXX/lto-visibility-inference.cpp | 8 ++++---- 6 files changed, 25 insertions(+), 24 deletions(-) diff --git a/clang/docs/LTOVisibility.rst b/clang/docs/LTOVisibility.rst index cdc0b9cc0e19..ebc4cc906aa6 100644 --- a/clang/docs/LTOVisibility.rst +++ b/clang/docs/LTOVisibility.rst @@ -35,13 +35,14 @@ other classes receive hidden LTO visibility. Classes with internal linkage (e.g. classes declared in unnamed namespaces) also receive hidden LTO visibility. -During the LTO link, all classes with public LTO visibility will be refined -to hidden LTO visibility when the ``--lto-whole-program-visibility`` lld linker -option is applied (``-plugin-opt=whole-program-visibility`` for gold). This flag -can be used to defer specifying whether classes have hidden LTO visibility until -link time, to allow bitcode objects to be shared by different LTO links. -Due to an implementation limitation, symbols associated with classes with hidden -LTO visibility may still be exported from the binary when using this flag. It is +During the LTO link, all classes with public LTO visibility but not marked with +``[[clang::lto_visibility_public]]`` (see below) will be refined to hidden LTO +visibility when the ``--lto-whole-program-visibility`` lld linker option is +applied (``-plugin-opt=whole-program-visibility`` for gold). This flag can be +used to defer specifying whether classes have hidden LTO visibility until link +time, to allow bitcode objects to be shared by different LTO links. Due to an +implementation limitation, symbols associated with classes with hidden LTO +visibility may still be exported from the binary when using this flag. It is unsafe to refer to these symbols, and their visibility may be relaxed to hidden in a future compiler release. diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index cb16019c6350..153f299a1c4b 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2695,9 +2695,9 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD, if (SanOpts.has(SanitizerKind::CFIVCall)) EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc); else if (CGM.getCodeGenOpts().WholeProgramVTables && - // Don't insert type test assumes if we are forcing public std + // Don't insert type test assumes if we are forcing public // visibility. - !CGM.HasLTOVisibilityPublicStd(RD)) { + !CGM.AlwaysHasLTOVisibilityPublic(RD)) { llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)); llvm::Value *TypeId = diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index ab8a46b797ba..cdd40d2a6a2e 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -1175,7 +1175,10 @@ void CodeGenModule::EmitDeferredVTables() { DeferredVTables.clear(); } -bool CodeGenModule::HasLTOVisibilityPublicStd(const CXXRecordDecl *RD) { +bool CodeGenModule::AlwaysHasLTOVisibilityPublic(const CXXRecordDecl *RD) { + if (RD->hasAttr() || RD->hasAttr()) + return true; + if (!getCodeGenOpts().LTOVisibilityPublicStd) return false; @@ -1200,9 +1203,6 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) { if (!isExternallyVisible(LV.getLinkage())) return true; - if (RD->hasAttr() || RD->hasAttr()) - return false; - if (getTriple().isOSBinFormatCOFF()) { if (RD->hasAttr() || RD->hasAttr()) return false; @@ -1211,7 +1211,7 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) { return false; } - return !HasLTOVisibilityPublicStd(RD); + return !AlwaysHasLTOVisibilityPublic(RD); } llvm::GlobalObject::VCallVisibility CodeGenModule::GetVCallVisibilityLevel( diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 779d94ad62d9..f5ae83a2faca 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1382,10 +1382,10 @@ public: /// optimization. bool HasHiddenLTOVisibility(const CXXRecordDecl *RD); - /// Returns whether the given record has public std LTO visibility - /// and therefore may not participate in (single-module) CFI and whole-program - /// vtable optimization. - bool HasLTOVisibilityPublicStd(const CXXRecordDecl *RD); + /// Returns whether the given record has public LTO visibility (regardless of + /// -lto-whole-program-visibility) and therefore may not participate in + /// (single-module) CFI and whole-program vtable optimization. + bool AlwaysHasLTOVisibilityPublic(const CXXRecordDecl *RD); /// Returns the vcall visibility of the given type. This is the scope in which /// a virtual function call could be made which ends up being dispatched to a diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 03b06b8bc522..f51e9b303236 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -668,8 +668,8 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( CGM.HasHiddenLTOVisibility(RD); bool ShouldEmitWPDInfo = CGM.getCodeGenOpts().WholeProgramVTables && - // Don't insert type tests if we are forcing public std visibility. - !CGM.HasLTOVisibilityPublicStd(RD); + // Don't insert type tests if we are forcing public visibility. + !CGM.AlwaysHasLTOVisibilityPublic(RD); llvm::Value *VirtualFn = nullptr; { diff --git a/clang/test/CodeGenCXX/lto-visibility-inference.cpp b/clang/test/CodeGenCXX/lto-visibility-inference.cpp index 632b6e643f30..73ed168f6f31 100644 --- a/clang/test/CodeGenCXX/lto-visibility-inference.cpp +++ b/clang/test/CodeGenCXX/lto-visibility-inference.cpp @@ -79,11 +79,11 @@ void f(C1 *c1, C2 *c2, C3 *c3, C4 *c4, C5 *c5, C6 *c6, std::C7 *c7, // ITANIUM: type.test{{.*}}!"_ZTS2C4" // MS: type.test{{.*}}!"?AUC4@@" c4->f(); - // ITANIUM: type.test{{.*}}!"_ZTS2C5" - // MS: type.test{{.*}}!"?AUC5@@" + // ITANIUM-NOT: type.test{{.*}}!"_ZTS2C5" + // MS-NOT: type.test{{.*}}!"?AUC5@@" c5->f(); - // ITANIUM: type.test{{.*}}!"_ZTS2C6" - // MS: type.test{{.*}}!"?AUC6@@" + // ITANIUM-NOT: type.test{{.*}}!"_ZTS2C6" + // MS-NOT: type.test{{.*}}!"?AUC6@@" c6->f(); // ITANIUM: type.test{{.*}}!"_ZTSSt2C7" // MS-STD: type.test{{.*}}!"?AUC7@std@@"