https://github.com/ahatanak updated https://github.com/llvm/llvm-project/pull/205930
>From bac79d92c7e1819cbcfce8cf533fad8f78c0c292 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <[email protected]> Date: Thu, 25 Jun 2026 10:38:26 -0700 Subject: [PATCH 1/4] [CodeGen] Disable exact dynamic_cast for duplicable vtables Add a TargetInfo predicate, vtablesMayBeDuplicated(), that is true on targets whose ABI allows a class's vtable to be emitted with more than one address in a program (e.g., Apple Mach-O). Use the new predicate in hasUniqueVTablePointer() to stop assuming a unique address for weak vtables on such targets, which disables the exact cast for them. A class with a key function has external linkage and a single definition, so its vtable keeps a unique address and the optimization is retained. Fixes https://github.com/llvm/llvm-project/issues/120129 rdar://129380573 --- clang/include/clang/Basic/TargetInfo.h | 5 ++ clang/lib/Basic/Targets/OSTargets.h | 4 ++ clang/lib/CodeGen/ItaniumCXXABI.cpp | 6 +++ .../dynamic-cast-exact-disabled.cpp | 47 +++++++++++++++---- clang/test/CodeGenCXX/dynamic-cast-exact.cpp | 2 +- .../CodeGenCXX/ptrauth-dynamic-cast-exact.cpp | 2 +- 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index d1914d626c753..7cf39a27efda7 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1799,6 +1799,11 @@ class TargetInfo : public TransferrableTargetInfo, /// Clang backwards compatibility rather than GCC/Itanium ABI compatibility. virtual bool areDefaultedSMFStillPOD(const LangOptions&) const; + /// Returns true if the target's ABI allows a class's vtable to be + /// duplicated, so the same vtable may be emitted with more than one address + /// in a program. + virtual bool vtablesMayBeDuplicated() const { return false; } + /// Controls whether global operator delete is called by the deleting /// destructor or at the point where ::delete was called. Historically Clang /// called global operator delete outside of the deleting destructor for both diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 9461680df8bdb..434ad661356aa 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -62,6 +62,10 @@ class LLVM_LIBRARY_VISIBILITY AppleMachOTargetInfo /// similar to ELF's "protected"; Apple Mach-O requires a "weak" attribute on /// declarations that can be dynamically replaced. bool hasProtectedVisibility() const override { return false; } + + /// Apple Mach-O can autohide a vtable so that each image gets its own copy, + /// so a class's vtable may have more than one address in a program. + bool vtablesMayBeDuplicated() const override { return true; } }; template <typename Target> diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index b4b3284f752ae..f7e370418b409 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -218,6 +218,12 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { if (!llvm::GlobalValue::isWeakForLinker(CGM.getVTableLinkage(RD))) return true; + // On targets that may duplicate a vtable, a weak vtable can be emitted with + // a distinct address in more than one image, so its address cannot be + // assumed to be unique. + if (CGM.getTarget().vtablesMayBeDuplicated()) + return false; + // Even if there are multiple definitions of the vtable, they are required // by the ABI to use the same symbol name, so should be merged at load // time. However, if the class has hidden visibility, there can be diff --git a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp index bf202d14c3398..3faaf71875b37 100644 --- a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp +++ b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp @@ -1,16 +1,31 @@ -// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,EXACT -// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O0 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,INEXACT -// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -fvisibility=hidden -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,INEXACT -// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -fapple-kext -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,INEXACT -// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -fno-assume-unique-vtables -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,INEXACT +// The exact dynamic_cast optimization is enabled for a weak vtable only on +// targets with unique vtables; for a class with a key function (a unique, +// externally defined vtable) it is also enabled where the optimization applies +// at all. The ENABLED/DISABLED prefixes track the weak vtable (class B); the +// KEY-ENABLED/KEY-DISABLED prefixes track the key-function class (WithKey). +// +// Baseline, unique vtables: +// RUN: %clang_cc1 -I%S %s -triple x86_64-unknown-linux-gnu -O1 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,ENABLED,KEY-ENABLED +// Disabled without optimization: +// RUN: %clang_cc1 -I%S %s -triple x86_64-unknown-linux-gnu -O0 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,DISABLED,KEY-DISABLED +// Disabled for a weak vtable with non-default visibility, but kept for the +// key-function class (its vtable is external): +// RUN: %clang_cc1 -I%S %s -triple x86_64-unknown-linux-gnu -O1 -fvisibility=hidden -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,DISABLED,KEY-ENABLED +// Disabled under -fapple-kext: +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -fapple-kext -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,DISABLED,KEY-DISABLED +// Disabled by -fno-assume-unique-vtables: +// RUN: %clang_cc1 -I%S %s -triple x86_64-unknown-linux-gnu -O1 -fno-assume-unique-vtables -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,DISABLED,KEY-DISABLED +// Disabled for a weak vtable on a target that may duplicate vtables (Apple +// Mach-O), but kept for the key-function class: +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,DISABLED,KEY-ENABLED struct A { virtual ~A(); }; struct B final : A { }; // CHECK-LABEL: @_Z5exactP1A B *exact(A *a) { - // INEXACT: call {{.*}} @__dynamic_cast - // EXACT-NOT: call {{.*}} @__dynamic_cast + // DISABLED: call {{.*}} @__dynamic_cast + // ENABLED-NOT: call {{.*}} @__dynamic_cast return dynamic_cast<B*>(a); } @@ -24,8 +39,20 @@ struct D final : private C { // CHECK-LABEL: @_Z5exactP1C D *exact(C *a) { - // INEXACT: call {{.*}} @__dynamic_cast - // EXACT: entry: - // EXACT-NEXT: ret ptr null + // DISABLED: call {{.*}} @__dynamic_cast + // ENABLED: entry: + // ENABLED-NEXT: ret ptr null return dynamic_cast<D*>(a); } + +// WithKey has a key function (the out-of-line g()), so its vtable has external +// linkage and a unique address even on a target that may duplicate vtables. +struct WithKey final : A { virtual void g(); }; + +// CHECK-LABEL: @_Z12cast_withkeyP1A +WithKey *cast_withkey(A *a) { + // KEY-DISABLED: call {{.*}} @__dynamic_cast + // KEY-ENABLED-NOT: call {{.*}} @__dynamic_cast + // KEY-ENABLED: icmp eq ptr {{.*}}, {{.*}}@_ZTV7WithKey + return dynamic_cast<WithKey*>(a); +} diff --git a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp index 86a97f764e729..b93f623ccbe98 100644 --- a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp +++ b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - -O1 -disable-llvm-passes | FileCheck %s --implicit-check-not='call {{.*}} @__dynamic_cast' +// RUN: %clang_cc1 -I%S %s -triple x86_64-unknown-linux-gnu -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - -O1 -disable-llvm-passes | FileCheck %s --implicit-check-not='call {{.*}} @__dynamic_cast' struct Offset { virtual ~Offset(); }; struct A { virtual ~A(); }; struct B final : Offset, A { }; diff --git a/clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp b/clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp index 1710ca5563380..c16f9a38adeb5 100644 --- a/clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp +++ b/clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -I%S %s -triple arm64e-apple-darwin10 -O1 -fptrauth-calls -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK +// RUN: %clang_cc1 -I%S %s -triple aarch64-linux-gnu -O1 -fptrauth-calls -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK struct A { virtual ~A(); >From f55586757baee4bff4a2b69c9d4f704707adcebe Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <[email protected]> Date: Fri, 26 Jun 2026 11:40:12 -0700 Subject: [PATCH 2/4] [CodeGen] Model vtable pointer uniqueness as a single policy Consolidate the AssumeUniqueVTables CodeGenOption and the vtablesMayBeDuplicated() target predicate added in bac79d92c7e1 into one vtable uniqueness policy (VTableUniquenessKind), so a single place decides whether the exact dynamic_cast optimization may assume a unique vtable address. -fassume-unique-vtables, previously a no-op, now forces the optimization on. rdar://129380573 --- clang/include/clang/Basic/CodeGenOptions.def | 2 +- clang/include/clang/Basic/CodeGenOptions.h | 28 +++++++++++++++++++ clang/include/clang/Basic/TargetInfo.h | 9 +++--- clang/include/clang/Options/Options.td | 13 +++++---- clang/lib/Basic/Targets/OSTargets.h | 9 ++++-- clang/lib/CodeGen/CodeGenModule.cpp | 12 ++++++++ clang/lib/CodeGen/CodeGenModule.h | 6 ++++ clang/lib/CodeGen/ItaniumCXXABI.cpp | 19 ++++++------- clang/lib/Driver/ToolChains/Clang.cpp | 8 ++++-- clang/lib/Frontend/CompilerInvocation.cpp | 19 +++++++++++++ .../dynamic-cast-exact-disabled.cpp | 3 ++ clang/test/Driver/fassume-unique-vtables.cpp | 17 ++++++++--- 12 files changed, 114 insertions(+), 31 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 5f3baf771ff96..4a219b176b691 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -39,7 +39,7 @@ CODEGENOPT(ImplicitMapSyms, 1, 0, Benign) ///< -Wa,-mmapsyms=implicit CODEGENOPT(AsmVerbose , 1, 0, Benign) ///< -dA, -fverbose-asm. CODEGENOPT(PreserveAsmComments, 1, 1, Benign) ///< -dA, -fno-preserve-as-comments. CODEGENOPT(AssumeSaneOperatorNew , 1, 1, Benign) ///< implicit __attribute__((malloc)) operator new -CODEGENOPT(AssumeUniqueVTables , 1, 1, Benign) ///< Assume a class has only one vtable. +ENUM_CODEGENOPT(RequestedVTableUniqueness, VTableUniquenessRequest, 2, VTableUniquenessRequest::TargetDefault, Benign) ///< -f[no-]assume-unique-vtables CODEGENOPT(Autolink , 1, 1, Benign) ///< -fno-autolink CODEGENOPT(AutoImport , 1, 1, Benign) ///< -fno-auto-import CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0, Benign) ///< Whether ARC should be EH-safe. diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 97d68877467fd..74b980414d865 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -36,6 +36,33 @@ class PassBuilder; } namespace clang { +/// The resolved policy for whether a class's vtable can be assumed to have a +/// unique address program-wide. This controls the exact dynamic_cast +/// optimization (and, where a vtable is not assumed unique, whether it may be +/// marked unnamed_addr so the platform can duplicate it). It is computed from +/// the target's default and the -f[no-]assume-unique-vtables request. +enum class VTableUniquenessKind { + /// Every vtable has a single address program-wide. + AlwaysUnique, + /// A vtable with strong linkage (e.g., a class with a key function) is + /// unique, but a vague-linkage (weak) vtable may be duplicated by the + /// platform and so has no unique address. + UniqueIfStrongLinkage, + /// No vtable is assumed to have a unique address, but the platform is not + /// allowed to duplicate vtables. + NeverUnique, +}; + +/// The vtable-uniqueness policy requested on the command line. +enum class VTableUniquenessRequest { + /// No -f[no-]assume-unique-vtables was given; use the target's default. + TargetDefault, + /// -fassume-unique-vtables: assume every vtable is unique. + AlwaysUnique, + /// -fno-assume-unique-vtables: assume no vtable is unique. + NeverUnique, +}; + /// Bitfields of CodeGenOptions, split out from CodeGenOptions to ensure /// that this large collection of bitfields is a trivial class type. class CodeGenOptionsBase { @@ -75,6 +102,7 @@ class CodeGenOptionsBase { using DebugInfoKind = llvm::codegenoptions::DebugInfoKind; using DebuggerKind = llvm::DebuggerKind; using RelocSectionSymType = llvm::RelocSectionSymType; + using VTableUniquenessRequest = ::clang::VTableUniquenessRequest; #define CODEGENOPT(Name, Bits, Default, Compatibility) unsigned Name : Bits; #define ENUM_CODEGENOPT(Name, Type, Bits, Default, Compatibility) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 7cf39a27efda7..181a3a774b2b4 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1799,10 +1799,11 @@ class TargetInfo : public TransferrableTargetInfo, /// Clang backwards compatibility rather than GCC/Itanium ABI compatibility. virtual bool areDefaultedSMFStillPOD(const LangOptions&) const; - /// Returns true if the target's ABI allows a class's vtable to be - /// duplicated, so the same vtable may be emitted with more than one address - /// in a program. - virtual bool vtablesMayBeDuplicated() const { return false; } + /// Returns the target's default policy for whether a class's vtable can be + /// assumed to have a unique address program-wide. + virtual VTableUniquenessKind getDefaultVTableUniqueness() const { + return VTableUniquenessKind::AlwaysUnique; + } /// Controls whether global operator delete is called by the deleting /// destructor or at the point where ::delete was called. Historically Clang diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 3c2091013d152..aa7b71f0c8fbe 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -1662,12 +1662,13 @@ def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>; def : Flag<["-"], "static-libasan">, Alias<static_libsan>; def fasm : Flag<["-"], "fasm">, Group<f_Group>; -defm assume_unique_vtables : BoolFOption<"assume-unique-vtables", - CodeGenOpts<"AssumeUniqueVTables">, DefaultTrue, - PosFlag<SetTrue>, - NegFlag<SetFalse, [], [ClangOption, CC1Option], - "Disable optimizations based on vtable pointer identity">, - BothFlags<[], [ClangOption, CLOption]>>; +def fassume_unique_vtables : Flag<["-"], "fassume-unique-vtables">, + Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, + HelpText<"Assume each polymorphic class has a single vtable with a unique " + "address, enabling optimizations based on vtable pointer identity">; +def fno_assume_unique_vtables : Flag<["-"], "fno-assume-unique-vtables">, + Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, + HelpText<"Disable optimizations based on vtable pointer identity">; def fassume_sane_operator_new : Flag<["-"], "fassume-sane-operator-new">, Group<f_Group>; def fastcp : Flag<["-"], "fastcp">, Group<f_Group>; diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 434ad661356aa..2968648787962 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -63,9 +63,12 @@ class LLVM_LIBRARY_VISIBILITY AppleMachOTargetInfo /// declarations that can be dynamically replaced. bool hasProtectedVisibility() const override { return false; } - /// Apple Mach-O can autohide a vtable so that each image gets its own copy, - /// so a class's vtable may have more than one address in a program. - bool vtablesMayBeDuplicated() const override { return true; } + /// Apple Mach-O can autohide a vague-linkage vtable so that each image gets + /// its own copy, so such a vtable may have more than one address in a + /// program. A strong (key-function) vtable still has a unique address. + VTableUniquenessKind getDefaultVTableUniqueness() const override { + return VTableUniquenessKind::UniqueIfStrongLinkage; + } }; template <typename Target> diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index fec18acd46998..1db6dad01a402 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6292,6 +6292,18 @@ bool CodeGenModule::supportsCOMDAT() const { return getTriple().supportsCOMDAT(); } +VTableUniquenessKind CodeGenModule::getVTableUniqueness() const { + switch (getCodeGenOpts().getRequestedVTableUniqueness()) { + case VTableUniquenessRequest::AlwaysUnique: + return VTableUniquenessKind::AlwaysUnique; + case VTableUniquenessRequest::NeverUnique: + return VTableUniquenessKind::NeverUnique; + case VTableUniquenessRequest::TargetDefault: + return getTarget().getDefaultVTableUniqueness(); + } + llvm_unreachable("invalid VTableUniquenessRequest"); +} + void CodeGenModule::maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO) { if (!shouldBeInCOMDAT(*this, D)) diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 4283b6a3dc869..f1ff1556d79b5 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -902,6 +902,12 @@ class CodeGenModule : public CodeGenTypeCache { } const TargetInfo &getTarget() const { return Target; } const llvm::Triple &getTriple() const { return Target.getTriple(); } + + /// Returns the vtable-uniqueness policy in effect: the explicit + /// -f[no-]assume-unique-vtables request when one was given, otherwise the + /// target's default. + VTableUniquenessKind getVTableUniqueness() const; + bool supportsCOMDAT() const; void maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index f7e370418b409..1407d6c5c2659 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -201,10 +201,12 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { /// practice in some cases due to language extensions. bool hasUniqueVTablePointer(QualType RecordTy) { const CXXRecordDecl *RD = RecordTy->getAsCXXRecordDecl(); + VTableUniquenessKind Uniqueness = CGM.getVTableUniqueness(); - // Under -fapple-kext, multiple definitions of the same vtable may be - // emitted. - if (!CGM.getCodeGenOpts().AssumeUniqueVTables || + // With NeverUnique (e.g., -fno-assume-unique-vtables) no vtable is assumed + // unique. Under -fapple-kext, multiple definitions of the same vtable may + // be emitted. + if (Uniqueness == VTableUniquenessKind::NeverUnique || getContext().getLangOpts().AppleKext) return false; @@ -218,12 +220,6 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { if (!llvm::GlobalValue::isWeakForLinker(CGM.getVTableLinkage(RD))) return true; - // On targets that may duplicate a vtable, a weak vtable can be emitted with - // a distinct address in more than one image, so its address cannot be - // assumed to be unique. - if (CGM.getTarget().vtablesMayBeDuplicated()) - return false; - // Even if there are multiple definitions of the vtable, they are required // by the ABI to use the same symbol name, so should be merged at load // time. However, if the class has hidden visibility, there can be @@ -233,7 +229,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { llvm::GlobalValue::DefaultVisibility) return false; - return true; + // A vague-linkage (weak) vtable on a target that may duplicate it + // (UniqueIfStrongLinkage) can be emitted with a distinct address in more + // than one image, so its address cannot be assumed unique. + return Uniqueness != VTableUniquenessKind::UniqueIfStrongLinkage; } bool shouldEmitExactDynamicCast(QualType DestRecordTy) override { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index bb3fbc3c585a6..39df02f07314d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7773,9 +7773,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new); - // -fassume-unique-vtables is on by default. - Args.addOptOutFlag(CmdArgs, options::OPT_fassume_unique_vtables, - options::OPT_fno_assume_unique_vtables); + // Forward the last -fassume-unique-vtables / -fno-assume-unique-vtables the + // user passed. When neither is given, the target's default vtable uniqueness + // policy applies. + Args.AddLastArg(CmdArgs, options::OPT_fassume_unique_vtables, + options::OPT_fno_assume_unique_vtables); // -fsized-deallocation is on by default in C++14 onwards and otherwise off // by default. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index dfde7b756dbff..67a7125ab4502 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1760,6 +1760,17 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, GenerateArg(Consumer, Opt); } + switch (Opts.getRequestedVTableUniqueness()) { + case VTableUniquenessRequest::AlwaysUnique: + GenerateArg(Consumer, OPT_fassume_unique_vtables); + break; + case VTableUniquenessRequest::NeverUnique: + GenerateArg(Consumer, OPT_fno_assume_unique_vtables); + break; + case VTableUniquenessRequest::TargetDefault: + break; + } + if (Opts.EnableAIXExtendedAltivecABI) GenerateArg(Consumer, OPT_mabi_EQ_vec_extabi); @@ -2168,6 +2179,14 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } + if (const Arg *A = Args.getLastArg(OPT_fassume_unique_vtables, + OPT_fno_assume_unique_vtables)) { + Opts.setRequestedVTableUniqueness( + A->getOption().matches(OPT_fassume_unique_vtables) + ? VTableUniquenessRequest::AlwaysUnique + : VTableUniquenessRequest::NeverUnique); + } + if (Arg *A = Args.getLastArg(OPT_mxcoff_roptr)) { if (!T.isOSAIX()) Diags.Report(diag::err_drv_unsupported_opt_for_target) diff --git a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp index 3faaf71875b37..fa740ba72266c 100644 --- a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp +++ b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp @@ -18,6 +18,9 @@ // Disabled for a weak vtable on a target that may duplicate vtables (Apple // Mach-O), but kept for the key-function class: // RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,DISABLED,KEY-ENABLED +// Forced back on by -fassume-unique-vtables, even on a target that may +// duplicate vtables: +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -fassume-unique-vtables -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,ENABLED,KEY-ENABLED struct A { virtual ~A(); }; struct B final : A { }; diff --git a/clang/test/Driver/fassume-unique-vtables.cpp b/clang/test/Driver/fassume-unique-vtables.cpp index 05efde605c2fe..a960786107268 100644 --- a/clang/test/Driver/fassume-unique-vtables.cpp +++ b/clang/test/Driver/fassume-unique-vtables.cpp @@ -1,4 +1,13 @@ -// RUN: %clang -### -fno-assume-unique-vtables %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT %s -// RUN: %clang -### -fno-assume-unique-vtables -fassume-unique-vtables %s -S 2>&1 | FileCheck -check-prefix=CHECK-NOOPT %s -// CHECK-OPT: "-fno-assume-unique-vtables" -// CHECK-NOOPT-NOT: "-fno-assume-unique-vtables" +// Both -f[no-]assume-unique-vtables are forwarded to -cc1 (last one wins). + +// RUN: %clang -### %s -S 2>&1 | FileCheck %s -check-prefix=DEFAULT +// DEFAULT-NOT: "-fassume-unique-vtables" +// DEFAULT-NOT: "-fno-assume-unique-vtables" + +// RUN: %clang -### -fno-assume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=NO --implicit-check-not="-fassume-unique-vtables" +// RUN: %clang -### -fassume-unique-vtables -fno-assume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=NO --implicit-check-not="-fassume-unique-vtables" +// NO: "-fno-assume-unique-vtables" + +// RUN: %clang -### -fassume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=YES --implicit-check-not="-fno-assume-unique-vtables" +// RUN: %clang -### -fno-assume-unique-vtables -fassume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=YES --implicit-check-not="-fno-assume-unique-vtables" +// YES: "-fassume-unique-vtables" >From 77d1325fe9561741388c1f9c27f767bd763cee93 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <[email protected]> Date: Tue, 30 Jun 2026 12:10:57 -0700 Subject: [PATCH 3/4] [CodeGen] Drop the requestable vtable-uniqueness policy Restore -f[no-]assume-unique-vtables to its original behavior; -fno-assume-unique-vtables disables the opt and -fassume-unique-vtables only cancels out the negative form. rdar://129380573 --- clang/include/clang/Basic/CodeGenOptions.def | 2 +- clang/include/clang/Basic/CodeGenOptions.h | 23 ++++--------------- clang/include/clang/Basic/TargetInfo.h | 6 ++--- clang/include/clang/Options/Options.td | 13 +++++------ clang/lib/Basic/Targets/OSTargets.h | 2 +- clang/lib/CodeGen/CodeGenModule.cpp | 12 ---------- clang/lib/CodeGen/CodeGenModule.h | 6 ----- clang/lib/CodeGen/ItaniumCXXABI.cpp | 18 +++++++-------- clang/lib/Driver/ToolChains/Clang.cpp | 8 +++---- clang/lib/Frontend/CompilerInvocation.cpp | 19 --------------- .../dynamic-cast-exact-disabled.cpp | 15 ++++++------ clang/test/Driver/fassume-unique-vtables.cpp | 17 ++++---------- 12 files changed, 38 insertions(+), 103 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 4a219b176b691..e7cebf0551127 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -39,7 +39,7 @@ CODEGENOPT(ImplicitMapSyms, 1, 0, Benign) ///< -Wa,-mmapsyms=implicit CODEGENOPT(AsmVerbose , 1, 0, Benign) ///< -dA, -fverbose-asm. CODEGENOPT(PreserveAsmComments, 1, 1, Benign) ///< -dA, -fno-preserve-as-comments. CODEGENOPT(AssumeSaneOperatorNew , 1, 1, Benign) ///< implicit __attribute__((malloc)) operator new -ENUM_CODEGENOPT(RequestedVTableUniqueness, VTableUniquenessRequest, 2, VTableUniquenessRequest::TargetDefault, Benign) ///< -f[no-]assume-unique-vtables +CODEGENOPT(DisableExactDynamicCast , 1, 0, Benign) ///< -fno-assume-unique-vtables: disable the exact dynamic_cast optimization. CODEGENOPT(Autolink , 1, 1, Benign) ///< -fno-autolink CODEGENOPT(AutoImport , 1, 1, Benign) ///< -fno-auto-import CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0, Benign) ///< Whether ARC should be EH-safe. diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 74b980414d865..c12434135a198 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -36,11 +36,10 @@ class PassBuilder; } namespace clang { -/// The resolved policy for whether a class's vtable can be assumed to have a -/// unique address program-wide. This controls the exact dynamic_cast -/// optimization (and, where a vtable is not assumed unique, whether it may be -/// marked unnamed_addr so the platform can duplicate it). It is computed from -/// the target's default and the -f[no-]assume-unique-vtables request. +/// A target's ABI policy for whether a class's vtable can be assumed to have +/// a unique address program-wide. This is the basis for the exact dynamic_cast +/// optimization (and, where a vtable is not assumed unique, for whether it may +/// be marked unnamed_addr so the platform can duplicate it). enum class VTableUniquenessKind { /// Every vtable has a single address program-wide. AlwaysUnique, @@ -48,19 +47,6 @@ enum class VTableUniquenessKind { /// unique, but a vague-linkage (weak) vtable may be duplicated by the /// platform and so has no unique address. UniqueIfStrongLinkage, - /// No vtable is assumed to have a unique address, but the platform is not - /// allowed to duplicate vtables. - NeverUnique, -}; - -/// The vtable-uniqueness policy requested on the command line. -enum class VTableUniquenessRequest { - /// No -f[no-]assume-unique-vtables was given; use the target's default. - TargetDefault, - /// -fassume-unique-vtables: assume every vtable is unique. - AlwaysUnique, - /// -fno-assume-unique-vtables: assume no vtable is unique. - NeverUnique, }; /// Bitfields of CodeGenOptions, split out from CodeGenOptions to ensure @@ -102,7 +88,6 @@ class CodeGenOptionsBase { using DebugInfoKind = llvm::codegenoptions::DebugInfoKind; using DebuggerKind = llvm::DebuggerKind; using RelocSectionSymType = llvm::RelocSectionSymType; - using VTableUniquenessRequest = ::clang::VTableUniquenessRequest; #define CODEGENOPT(Name, Bits, Default, Compatibility) unsigned Name : Bits; #define ENUM_CODEGENOPT(Name, Type, Bits, Default, Compatibility) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 181a3a774b2b4..c05cbce77baef 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1799,9 +1799,9 @@ class TargetInfo : public TransferrableTargetInfo, /// Clang backwards compatibility rather than GCC/Itanium ABI compatibility. virtual bool areDefaultedSMFStillPOD(const LangOptions&) const; - /// Returns the target's default policy for whether a class's vtable can be - /// assumed to have a unique address program-wide. - virtual VTableUniquenessKind getDefaultVTableUniqueness() const { + /// Returns whether the target's ABI guarantees that a class's vtable has a + /// unique address program-wide. + virtual VTableUniquenessKind getVTableUniqueness() const { return VTableUniquenessKind::AlwaysUnique; } diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index aa7b71f0c8fbe..b6e727e834eed 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -1662,13 +1662,12 @@ def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>; def : Flag<["-"], "static-libasan">, Alias<static_libsan>; def fasm : Flag<["-"], "fasm">, Group<f_Group>; -def fassume_unique_vtables : Flag<["-"], "fassume-unique-vtables">, - Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, - HelpText<"Assume each polymorphic class has a single vtable with a unique " - "address, enabling optimizations based on vtable pointer identity">; -def fno_assume_unique_vtables : Flag<["-"], "fno-assume-unique-vtables">, - Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, - HelpText<"Disable optimizations based on vtable pointer identity">; +defm assume_unique_vtables : BoolFOption<"assume-unique-vtables", + CodeGenOpts<"DisableExactDynamicCast">, DefaultFalse, + PosFlag<SetFalse>, + NegFlag<SetTrue, [], [ClangOption, CC1Option], + "Disable optimizations based on vtable pointer identity">, + BothFlags<[], [ClangOption, CLOption]>>; def fassume_sane_operator_new : Flag<["-"], "fassume-sane-operator-new">, Group<f_Group>; def fastcp : Flag<["-"], "fastcp">, Group<f_Group>; diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 2968648787962..7c4666606d89f 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -66,7 +66,7 @@ class LLVM_LIBRARY_VISIBILITY AppleMachOTargetInfo /// Apple Mach-O can autohide a vague-linkage vtable so that each image gets /// its own copy, so such a vtable may have more than one address in a /// program. A strong (key-function) vtable still has a unique address. - VTableUniquenessKind getDefaultVTableUniqueness() const override { + VTableUniquenessKind getVTableUniqueness() const override { return VTableUniquenessKind::UniqueIfStrongLinkage; } }; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 1db6dad01a402..fec18acd46998 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6292,18 +6292,6 @@ bool CodeGenModule::supportsCOMDAT() const { return getTriple().supportsCOMDAT(); } -VTableUniquenessKind CodeGenModule::getVTableUniqueness() const { - switch (getCodeGenOpts().getRequestedVTableUniqueness()) { - case VTableUniquenessRequest::AlwaysUnique: - return VTableUniquenessKind::AlwaysUnique; - case VTableUniquenessRequest::NeverUnique: - return VTableUniquenessKind::NeverUnique; - case VTableUniquenessRequest::TargetDefault: - return getTarget().getDefaultVTableUniqueness(); - } - llvm_unreachable("invalid VTableUniquenessRequest"); -} - void CodeGenModule::maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO) { if (!shouldBeInCOMDAT(*this, D)) diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index f1ff1556d79b5..4283b6a3dc869 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -902,12 +902,6 @@ class CodeGenModule : public CodeGenTypeCache { } const TargetInfo &getTarget() const { return Target; } const llvm::Triple &getTriple() const { return Target.getTriple(); } - - /// Returns the vtable-uniqueness policy in effect: the explicit - /// -f[no-]assume-unique-vtables request when one was given, otherwise the - /// target's default. - VTableUniquenessKind getVTableUniqueness() const; - bool supportsCOMDAT() const; void maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 1407d6c5c2659..e5799d7f17959 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -201,12 +201,11 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { /// practice in some cases due to language extensions. bool hasUniqueVTablePointer(QualType RecordTy) { const CXXRecordDecl *RD = RecordTy->getAsCXXRecordDecl(); - VTableUniquenessKind Uniqueness = CGM.getVTableUniqueness(); - // With NeverUnique (e.g., -fno-assume-unique-vtables) no vtable is assumed - // unique. Under -fapple-kext, multiple definitions of the same vtable may - // be emitted. - if (Uniqueness == VTableUniquenessKind::NeverUnique || + // The exact dynamic_cast optimization relies on the vtable having a unique + // address. -fno-assume-unique-vtables disables it, and under -fapple-kext + // multiple definitions of the same vtable may be emitted. + if (CGM.getCodeGenOpts().DisableExactDynamicCast || getContext().getLangOpts().AppleKext) return false; @@ -229,10 +228,11 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { llvm::GlobalValue::DefaultVisibility) return false; - // A vague-linkage (weak) vtable on a target that may duplicate it - // (UniqueIfStrongLinkage) can be emitted with a distinct address in more - // than one image, so its address cannot be assumed unique. - return Uniqueness != VTableUniquenessKind::UniqueIfStrongLinkage; + // A vague-linkage (weak) vtable on a target whose ABI may duplicate it can + // be emitted with a distinct address in more than one image, so its address + // cannot be assumed unique. + return CGM.getTarget().getVTableUniqueness() != + VTableUniquenessKind::UniqueIfStrongLinkage; } bool shouldEmitExactDynamicCast(QualType DestRecordTy) override { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 39df02f07314d..bb3fbc3c585a6 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7773,11 +7773,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new); - // Forward the last -fassume-unique-vtables / -fno-assume-unique-vtables the - // user passed. When neither is given, the target's default vtable uniqueness - // policy applies. - Args.AddLastArg(CmdArgs, options::OPT_fassume_unique_vtables, - options::OPT_fno_assume_unique_vtables); + // -fassume-unique-vtables is on by default. + Args.addOptOutFlag(CmdArgs, options::OPT_fassume_unique_vtables, + options::OPT_fno_assume_unique_vtables); // -fsized-deallocation is on by default in C++14 onwards and otherwise off // by default. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 67a7125ab4502..dfde7b756dbff 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1760,17 +1760,6 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, GenerateArg(Consumer, Opt); } - switch (Opts.getRequestedVTableUniqueness()) { - case VTableUniquenessRequest::AlwaysUnique: - GenerateArg(Consumer, OPT_fassume_unique_vtables); - break; - case VTableUniquenessRequest::NeverUnique: - GenerateArg(Consumer, OPT_fno_assume_unique_vtables); - break; - case VTableUniquenessRequest::TargetDefault: - break; - } - if (Opts.EnableAIXExtendedAltivecABI) GenerateArg(Consumer, OPT_mabi_EQ_vec_extabi); @@ -2179,14 +2168,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } - if (const Arg *A = Args.getLastArg(OPT_fassume_unique_vtables, - OPT_fno_assume_unique_vtables)) { - Opts.setRequestedVTableUniqueness( - A->getOption().matches(OPT_fassume_unique_vtables) - ? VTableUniquenessRequest::AlwaysUnique - : VTableUniquenessRequest::NeverUnique); - } - if (Arg *A = Args.getLastArg(OPT_mxcoff_roptr)) { if (!T.isOSAIX()) Diags.Report(diag::err_drv_unsupported_opt_for_target) diff --git a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp index fa740ba72266c..0fe32cac77773 100644 --- a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp +++ b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp @@ -1,8 +1,10 @@ -// The exact dynamic_cast optimization is enabled for a weak vtable only on -// targets with unique vtables; for a class with a key function (a unique, -// externally defined vtable) it is also enabled where the optimization applies -// at all. The ENABLED/DISABLED prefixes track the weak vtable (class B); the -// KEY-ENABLED/KEY-DISABLED prefixes track the key-function class (WithKey). +// The ENABLED/DISABLED prefixes track the weak vtable (class B); +// KEY-ENABLED/KEY-DISABLED track the key-function class (WithKey), whose +// vtable is external with a unique address. The weak vtable gets the exact +// dynamic_cast optimization only on targets with unique vtables; the +// key-function vtable keeps it even on targets that may duplicate weak +// vtables, and loses it only when the optimization is turned off entirely +// (-O0, -fapple-kext, -fno-assume-unique-vtables). // // Baseline, unique vtables: // RUN: %clang_cc1 -I%S %s -triple x86_64-unknown-linux-gnu -O1 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,ENABLED,KEY-ENABLED @@ -18,9 +20,6 @@ // Disabled for a weak vtable on a target that may duplicate vtables (Apple // Mach-O), but kept for the key-function class: // RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,DISABLED,KEY-ENABLED -// Forced back on by -fassume-unique-vtables, even on a target that may -// duplicate vtables: -// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -O1 -fassume-unique-vtables -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=CHECK,ENABLED,KEY-ENABLED struct A { virtual ~A(); }; struct B final : A { }; diff --git a/clang/test/Driver/fassume-unique-vtables.cpp b/clang/test/Driver/fassume-unique-vtables.cpp index a960786107268..05efde605c2fe 100644 --- a/clang/test/Driver/fassume-unique-vtables.cpp +++ b/clang/test/Driver/fassume-unique-vtables.cpp @@ -1,13 +1,4 @@ -// Both -f[no-]assume-unique-vtables are forwarded to -cc1 (last one wins). - -// RUN: %clang -### %s -S 2>&1 | FileCheck %s -check-prefix=DEFAULT -// DEFAULT-NOT: "-fassume-unique-vtables" -// DEFAULT-NOT: "-fno-assume-unique-vtables" - -// RUN: %clang -### -fno-assume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=NO --implicit-check-not="-fassume-unique-vtables" -// RUN: %clang -### -fassume-unique-vtables -fno-assume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=NO --implicit-check-not="-fassume-unique-vtables" -// NO: "-fno-assume-unique-vtables" - -// RUN: %clang -### -fassume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=YES --implicit-check-not="-fno-assume-unique-vtables" -// RUN: %clang -### -fno-assume-unique-vtables -fassume-unique-vtables %s -S 2>&1 | FileCheck %s -check-prefix=YES --implicit-check-not="-fno-assume-unique-vtables" -// YES: "-fassume-unique-vtables" +// RUN: %clang -### -fno-assume-unique-vtables %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT %s +// RUN: %clang -### -fno-assume-unique-vtables -fassume-unique-vtables %s -S 2>&1 | FileCheck -check-prefix=CHECK-NOOPT %s +// CHECK-OPT: "-fno-assume-unique-vtables" +// CHECK-NOOPT-NOT: "-fno-assume-unique-vtables" >From 7cfb76b594ce4a0f23bc228b159e784373a0cfe2 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <[email protected]> Date: Thu, 25 Jun 2026 11:40:44 -0700 Subject: [PATCH 4/4] [CodeGen] Mark weak vtables unnamed_addr on duplicable-vtable targets When a target's getVTableUniqueness() is UniqueIfStrongLinkage, as on Apple Mach-O, the platform may emit a class's weak vtable as a separate copy in more than one linkage unit. A symbol that can legitimately exist at several addresses has no meaningful address, so such a vtable can be marked unnamed_addr. On Mach-O, a weak vtable that is unnamed_addr lowers to a .weak_def_can_be_hidden definition, which the static linker coalesces and then drops from the dynamic export trie. Keeping these vtables out of the exported symbol set cuts the work dyld has to do at load time. #200108 dropped unnamed_addr from vtables because the exact dynamic_cast optimization compares an object's vtable pointer against a known vtable address and depends on that address being unique. Adding unnamed_addr is safe here because that optimization is never performed for these weak vtables, so nothing relies on them having a unique address. rdar://179929460 --- clang/lib/CodeGen/CGVTables.cpp | 11 +++++++-- clang/lib/CodeGen/ItaniumCXXABI.cpp | 8 +++++++ .../construction-vtable-unnamed-addr.cpp | 22 +++++++++++++++++ clang/test/CodeGenCXX/key-function-vtable.cpp | 16 ++++++++----- clang/test/CodeGenCXX/mangle-subst-std.cpp | 10 ++++---- ...trauth-explicit-vtable-pointer-control.cpp | 19 ++++++++------- ...rauth-vtable-virtual-inheritance-thunk.cpp | 3 ++- .../CodeGenCXX/template-instantiation.cpp | 4 ++-- clang/test/CodeGenCXX/type_visibility.cpp | 20 ++++++++-------- .../test/CodeGenCXX/virt-template-vtable.cpp | 8 +++---- clang/test/CodeGenCXX/visibility.cpp | 4 ++-- clang/test/CodeGenCXX/vtable-assume-load.cpp | 4 ++-- .../vtable-available-externally.cpp | 12 +++++----- .../CodeGenCXX/vtable-key-function-ios.cpp | 24 ++++++++++++------- clang/test/CodeGenCXX/vtable-key-function.cpp | 2 +- clang/test/CodeGenCXX/vtt-layout.cpp | 2 +- 16 files changed, 110 insertions(+), 59 deletions(-) create mode 100644 clang/test/CodeGenCXX/construction-vtable-unnamed-addr.cpp diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 91ce36efae835..353ab6748fd48 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -988,8 +988,15 @@ llvm::GlobalVariable *CodeGenVTables::GenerateConstructionVTable( CGM.CreateOrReplaceCXXRuntimeVariable(Name, VTType, Linkage, Align); // dynamic_cast assumes the vtable address is unique; see - // https://github.com/llvm/llvm-project/pull/200108 - if (!CGM.shouldEmitRTTI()) + // https://github.com/llvm/llvm-project/pull/200108. The address is + // insignificant either when no RTTI is emitted or for a weak vtable on a + // target that may duplicate vtables. In those cases the vtable can be marked + // unnamed_addr. + bool VTableMayBeDuplicated = + CGM.getTarget().getVTableUniqueness() == + VTableUniquenessKind::UniqueIfStrongLinkage && + VTable->isWeakForLinker(); + if (!CGM.shouldEmitRTTI() || VTableMayBeDuplicated) VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor( diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index e5799d7f17959..7925be69cbbcb 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2104,6 +2104,14 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, // Set the correct linkage. VTable->setLinkage(Linkage); + // On a target that may duplicate vtables, a weak vtable does not have a + // unique address, so its address is insignificant and it can be marked + // unnamed_addr. + if (CGM.getTarget().getVTableUniqueness() == + VTableUniquenessKind::UniqueIfStrongLinkage && + VTable->isWeakForLinker()) + VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + if (CGM.supportsCOMDAT() && VTable->isWeakForLinker()) VTable->setComdat(CGM.getModule().getOrInsertComdat(VTable->getName())); diff --git a/clang/test/CodeGenCXX/construction-vtable-unnamed-addr.cpp b/clang/test/CodeGenCXX/construction-vtable-unnamed-addr.cpp new file mode 100644 index 0000000000000..3f96ea334809a --- /dev/null +++ b/clang/test/CodeGenCXX/construction-vtable-unnamed-addr.cpp @@ -0,0 +1,22 @@ +// C has no key function, so its primary vtable and construction vtables have +// weak (vague) linkage. On a target that may duplicate vtables (Apple Mach-O) +// such weak vtables are marked unnamed_addr; on other targets they are not. +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - | FileCheck %s --check-prefix=DARWIN +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -std=c++11 -emit-llvm -o - | FileCheck %s --check-prefix=LINUX + +struct V { virtual void f() {} virtual ~V() {} }; +struct A : virtual V { virtual void a() {} }; +struct B : virtual V { virtual void b() {} }; +struct C : A, B { virtual void c() {} }; + +C *make() { return new C(); } + +// C's primary vtable and the construction vtables for its A and B bases are +// weak, so they are marked unnamed_addr on Mach-O but not on Linux. +// DARWIN-DAG: @_ZTV1C = linkonce_odr unnamed_addr constant +// DARWIN-DAG: @_ZTC1C0_1A = linkonce_odr unnamed_addr constant +// DARWIN-DAG: @_ZTC1C8_1B = linkonce_odr unnamed_addr constant + +// LINUX-DAG: @_ZTV1C = linkonce_odr constant +// LINUX-DAG: @_ZTC1C0_1A = linkonce_odr constant +// LINUX-DAG: @_ZTC1C8_1B = linkonce_odr constant diff --git a/clang/test/CodeGenCXX/key-function-vtable.cpp b/clang/test/CodeGenCXX/key-function-vtable.cpp index ecdf5702f50bb..5be477868e7fa 100644 --- a/clang/test/CodeGenCXX/key-function-vtable.cpp +++ b/clang/test/CodeGenCXX/key-function-vtable.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-none-linux-gnu %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple arm-apple-darwin %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-none-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,LINUX +// RUN: %clang_cc1 -triple arm-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DARWIN // Simple key function test struct testa { virtual void a(); }; @@ -43,9 +43,13 @@ inline void X1::f() { } void use_X1() { X1 x1; } -// CHECK-DAG: @_ZTV2X1 = linkonce_odr constant +// LINUX-DAG: @_ZTV2X1 = linkonce_odr constant +// DARWIN-DAG: @_ZTV2X1 = linkonce_odr unnamed_addr constant // CHECK-DAG: @_ZTV5testa ={{.*}}constant { [3 x ptr] } { [3 x ptr] [ptr null -// CHECK-DAG: @_ZTV5testc = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null -// CHECK-DAG: @_ZTV5testb = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null -// CHECK-DAG: @_ZTV5teste = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null +// LINUX-DAG: @_ZTV5testc = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null +// DARWIN-DAG: @_ZTV5testc = linkonce_odr unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null +// LINUX-DAG: @_ZTV5testb = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null +// DARWIN-DAG: @_ZTV5testb = linkonce_odr unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null +// LINUX-DAG: @_ZTV5teste = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null +// DARWIN-DAG: @_ZTV5teste = linkonce_odr unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null // CHECK-DAG: @_ZTVN12_GLOBAL__N_15testgE = internal constant { [3 x ptr] } { [3 x ptr] [ptr null diff --git a/clang/test/CodeGenCXX/mangle-subst-std.cpp b/clang/test/CodeGenCXX/mangle-subst-std.cpp index 5149969779cbe..648c9af63e282 100644 --- a/clang/test/CodeGenCXX/mangle-subst-std.cpp +++ b/clang/test/CodeGenCXX/mangle-subst-std.cpp @@ -4,13 +4,13 @@ // involve standard substitutions. -// CHECK: @_ZTVSd = linkonce_odr constant +// CHECK: @_ZTVSd = linkonce_odr unnamed_addr constant // CHECK: @_ZTTSd = linkonce_odr unnamed_addr constant -// CHECK: @_ZTCSd0_Si = linkonce_odr constant -// CHECK: @_ZTCSd16_So = linkonce_odr constant -// CHECK: @_ZTVSi = linkonce_odr constant +// CHECK: @_ZTCSd0_Si = linkonce_odr unnamed_addr constant +// CHECK: @_ZTCSd16_So = linkonce_odr unnamed_addr constant +// CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant // CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant -// CHECK: @_ZTVSo = linkonce_odr constant +// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant // CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant namespace std { diff --git a/clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp b/clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp index 0d6e043e74d45..b2ddf52062d3c 100644 --- a/clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp +++ b/clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp @@ -1,34 +1,34 @@ // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NODISC %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NODISC,DARWIN %s // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,TYPE %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,TYPE,DARWIN %s // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,ADDR %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,ADDR,DARWIN %s // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,BOTH %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,BOTH,DARWIN %s // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NODISC %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NODISC,LINUX %s // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,TYPE %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,TYPE,LINUX %s // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,ADDR %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,ADDR,LINUX %s // RUN: %clang_cc1 %s -x c++ -std=c++20 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ -// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,BOTH %s +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,BOTH,LINUX %s #include <ptrauth.h> @@ -80,7 +80,8 @@ struct authenticated(default_key, default_address_discrimination, custom_discrim // CHECK: @_ZTVN5test19ConstEvalE = external constant { [3 x ptr] }, align 8 // CHECK: @_ZN5test12ceE = global %{{.*}} { ptr ptrauth (ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTVN5test19ConstEvalE, i32 0, i32 0, i32 2), i32 2, i64 0, ptr @_ZN5test12ceE) }, align 8 -// CHECK: @_ZTVN5test116ConstEvalDerivedE = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr @_ZTIN5test116ConstEvalDerivedE, ptr ptrauth (ptr @_ZN5test19ConstEval1fEv, i32 0, i64 26259, ptr getelementptr inbounds ({ [3 x ptr] }, ptr @_ZTVN5test116ConstEvalDerivedE, i32 0, i32 0, i32 2))] },{{.*}}align 8 +// DARWIN: @_ZTVN5test116ConstEvalDerivedE = linkonce_odr unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr @_ZTIN5test116ConstEvalDerivedE, ptr ptrauth (ptr @_ZN5test19ConstEval1fEv, i32 0, i64 26259, ptr getelementptr inbounds ({ [3 x ptr] }, ptr @_ZTVN5test116ConstEvalDerivedE, i32 0, i32 0, i32 2))] },{{.*}}align 8 +// LINUX: @_ZTVN5test116ConstEvalDerivedE = linkonce_odr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr @_ZTIN5test116ConstEvalDerivedE, ptr ptrauth (ptr @_ZN5test19ConstEval1fEv, i32 0, i64 26259, ptr getelementptr inbounds ({ [3 x ptr] }, ptr @_ZTVN5test116ConstEvalDerivedE, i32 0, i32 0, i32 2))] },{{.*}}align 8 // CHECK: @_ZN5test13cedE = global { ptr } { ptr ptrauth (ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTVN5test116ConstEvalDerivedE, i32 0, i32 0, i32 2), i32 2, i64 0, ptr @_ZN5test13cedE) }, align 8 struct authenticated(default_key, address_discrimination, no_extra_discrimination) ConstEval { diff --git a/clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp b/clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp index 980249aa5d7aa..0dc6e0fef248d 100644 --- a/clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp +++ b/clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp @@ -177,7 +177,8 @@ // CHECK: @_ZTS1G = constant [3 x i8] c"1G\00", align 1 -// CHECK: @_ZTV1B = linkonce_odr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr @_ZTI1B, +// DARWIN: @_ZTV1B = linkonce_odr unnamed_addr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr @_ZTI1B, +// ELF: @_ZTV1B = linkonce_odr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr @_ZTI1B, // CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 2)), // CHECK-SAME: ptr ptrauth (ptr @_ZN1A1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3)), // CHECK-SAME: ptr ptrauth (ptr @_ZN1A1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 4)), diff --git a/clang/test/CodeGenCXX/template-instantiation.cpp b/clang/test/CodeGenCXX/template-instantiation.cpp index ee7540309f0c1..bd0b5890c1a60 100644 --- a/clang/test/CodeGenCXX/template-instantiation.cpp +++ b/clang/test/CodeGenCXX/template-instantiation.cpp @@ -3,9 +3,9 @@ // Instantiation order varies on different C++ dialects (IE, between C++98 and C++11). // CHECK-DAG: @_ZN7PR100011xE ={{.*}} global -// CHECK-DAG: @_ZTVN5test018stdio_sync_filebufIA3_iEE = weak_odr constant +// CHECK-DAG: @_ZTVN5test018stdio_sync_filebufIA3_iEE = weak_odr unnamed_addr constant // CHECK-DAG: @_ZN7PR100011SIiE3arrE = linkonce_odr global [3 x i32] -// CHECK-DAG: @_ZTVN5test018stdio_sync_filebufIA4_iEE = linkonce_odr constant +// CHECK-DAG: @_ZTVN5test018stdio_sync_filebufIA4_iEE = linkonce_odr unnamed_addr constant // Negative checks go under prefix "CHECK2" to avoid interference with CHECK and CHECK-DAG. // CHECK2-NOT: @_ZN7PR100014kBarE = external global i32 diff --git a/clang/test/CodeGenCXX/type_visibility.cpp b/clang/test/CodeGenCXX/type_visibility.cpp index 48d2eb5d0d0a2..fecf2dbc53d37 100644 --- a/clang/test/CodeGenCXX/type_visibility.cpp +++ b/clang/test/CodeGenCXX/type_visibility.cpp @@ -25,11 +25,11 @@ namespace temp0 { template struct B<A>; // FUNS-LABEL: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp01BINS_1AEEE = weak_odr constant + // VARS: @_ZTVN5temp01BINS_1AEEE = weak_odr unnamed_addr constant // VARS: @_ZTIN5temp01BINS_1AEEE = weak_odr constant // VARS: @_ZTSN5temp01BINS_1AEEE = weak_odr constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTIN5temp01BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTSN5temp01BINS_1AEEE = weak_odr hidden constant } @@ -42,11 +42,11 @@ namespace temp1 { template struct B<A>; // FUNS-LABEL: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp11BINS_1AEEE = weak_odr constant + // VARS: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant // VARS: @_ZTIN5temp11BINS_1AEEE = weak_odr constant // VARS: @_ZTSN5temp11BINS_1AEEE = weak_odr constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp11BINS_1AEEE = weak_odr constant + // VARS-HIDDEN: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant // VARS-HIDDEN: @_ZTIN5temp11BINS_1AEEE = weak_odr constant // VARS-HIDDEN: @_ZTSN5temp11BINS_1AEEE = weak_odr constant } @@ -59,11 +59,11 @@ namespace temp2 { template struct B<A>; // FUNS-LABEL: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp21BINS_1AEEE = weak_odr constant + // VARS: @_ZTVN5temp21BINS_1AEEE = weak_odr unnamed_addr constant // VARS: @_ZTIN5temp21BINS_1AEEE = weak_odr constant // VARS: @_ZTSN5temp21BINS_1AEEE = weak_odr constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTIN5temp21BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTSN5temp21BINS_1AEEE = weak_odr hidden constant } @@ -76,11 +76,11 @@ namespace temp3 { template struct B<A>; // FUNS-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden constant + // VARS: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden constant // VARS: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant } @@ -93,11 +93,11 @@ namespace temp4 { template struct B<A>; // FUNS-LABEL: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv( - // VARS: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden constant + // VARS: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden constant // VARS: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant // FUNS-HIDDEN-LABEL: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv( - // VARS-HIDDEN: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden constant + // VARS-HIDDEN: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant // VARS-HIDDEN: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden constant // VARS-HIDDEN: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant } diff --git a/clang/test/CodeGenCXX/virt-template-vtable.cpp b/clang/test/CodeGenCXX/virt-template-vtable.cpp index 2431952209ce3..a14dbe962e569 100644 --- a/clang/test/CodeGenCXX/virt-template-vtable.cpp +++ b/clang/test/CodeGenCXX/virt-template-vtable.cpp @@ -16,10 +16,10 @@ extern template class A<short>; template class A<short>; -// CHECK: @_ZTV1B = linkonce_odr {{(dso_local )?}}constant -// CHECK: @_ZTV1AIlE = weak_odr {{(dso_local )?}}constant -// CHECK: @_ZTV1AIsE = weak_odr {{(dso_local )?}}constant -// CHECK: @_ZTV1AIiE = linkonce_odr {{(dso_local )?}}constant +// CHECK: @_ZTV1B = linkonce_odr {{(dso_local )?(unnamed_addr )?}}constant +// CHECK: @_ZTV1AIlE = weak_odr {{(dso_local )?(unnamed_addr )?}}constant +// CHECK: @_ZTV1AIsE = weak_odr {{(dso_local )?(unnamed_addr )?}}constant +// CHECK: @_ZTV1AIiE = linkonce_odr {{(dso_local )?(unnamed_addr )?}}constant template<class T> struct C { virtual void c() {} diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp index 9951a13ac311b..7a1b6102ac953 100644 --- a/clang/test/CodeGenCXX/visibility.cpp +++ b/clang/test/CodeGenCXX/visibility.cpp @@ -195,7 +195,7 @@ namespace test27 { // CHECK-HIDDEN: _ZTVN6test271CIiE1DE = constant } -// CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden constant +// CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden unnamed_addr constant // CHECK-HIDDEN: @_ZTVN6Test161AIcEE = external constant // CHECK-HIDDEN: @_ZTTN6Test161AIcEE = external unnamed_addr constant @@ -206,7 +206,7 @@ namespace test27 { // CHECK: @_ZGVZN6test681fC1EvE4test = linkonce_odr global // CHECK-HIDDEN: @_ZGVZN6test681fC1EvE4test = linkonce_odr hidden global -// CHECK-HIDDEN: @_ZTVN6test701DE = linkonce_odr hidden constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZTIN6test701DE] }, align 8 +// CHECK-HIDDEN: @_ZTVN6test701DE = linkonce_odr hidden unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZTIN6test701DE] }, align 8 // CHECK-HIDDEN: @_ZTTN6test701DE = linkonce_odr hidden unnamed_addr constant [1 x ptr] [ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr] }, ptr @_ZTVN6test701DE, i32 0, i32 0, i32 3)], align 8 // CHECK: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr global diff --git a/clang/test/CodeGenCXX/vtable-assume-load.cpp b/clang/test/CodeGenCXX/vtable-assume-load.cpp index 25e11add357a9..b37f2cfda6c0e 100644 --- a/clang/test/CodeGenCXX/vtable-assume-load.cpp +++ b/clang/test/CodeGenCXX/vtable-assume-load.cpp @@ -235,7 +235,7 @@ struct B : A { void bar(); }; -// CHECK8-DAG: @_ZTVN5test81CE = linkonce_odr constant +// CHECK8-DAG: @_ZTVN5test81CE = linkonce_odr unnamed_addr constant struct C : A { C(); void bar(); @@ -250,7 +250,7 @@ struct D : A { }; void D::bar() {} -// CHECK8-DAG: @_ZTVN5test81EE = linkonce_odr constant +// CHECK8-DAG: @_ZTVN5test81EE = linkonce_odr unnamed_addr constant struct E : A { E(); }; diff --git a/clang/test/CodeGenCXX/vtable-available-externally.cpp b/clang/test/CodeGenCXX/vtable-available-externally.cpp index d7e2e1cbc07f1..66aeb63cf9909 100644 --- a/clang/test/CodeGenCXX/vtable-available-externally.cpp +++ b/clang/test/CodeGenCXX/vtable-available-externally.cpp @@ -225,8 +225,8 @@ struct A { void A::foo() {} // Because key function is inline we will generate vtable as linkonce_odr. -// CHECK-TEST10-DAG: @_ZTVN6Test101DE = linkonce_odr constant -// CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101DE = linkonce_odr constant +// CHECK-TEST10-DAG: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant +// CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant struct D : A { void bar(); }; @@ -260,8 +260,8 @@ struct F : A { inline void F::cat() {} // no key function, vtable will be generated everywhere it will be used -// CHECK-TEST10-DAG: @_ZTVN6Test101EE = linkonce_odr constant -// CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101EE = linkonce_odr constant +// CHECK-TEST10-DAG: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant +// CHECK-FORCE-EMIT-DAG: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant struct E : A {}; @@ -453,7 +453,7 @@ void testcaseB() { namespace Test18 { // Here vtable will be only emitted because it is referenced by assume-load // after the Derived construction. -// CHECK-FORCE-EMIT-DAG: @_ZTVN6Test187DerivedE = linkonce_odr constant {{.*}} @_ZTIN6Test187DerivedE, {{.*}} @_ZN6Test184Base3funEv, {{.*}} @_ZN6Test184BaseD2Ev, {{.*}} @_ZN6Test187DerivedD0Ev +// CHECK-FORCE-EMIT-DAG: @_ZTVN6Test187DerivedE = linkonce_odr unnamed_addr constant {{.*}} @_ZTIN6Test187DerivedE, {{.*}} @_ZN6Test184Base3funEv, {{.*}} @_ZN6Test184BaseD2Ev, {{.*}} @_ZN6Test187DerivedD0Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr void @_ZN6Test187DerivedD0Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr void @_ZN6Test184BaseD2Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr noundef i32 @_ZN6Test184Base3funEv @@ -476,7 +476,7 @@ int foo() { namespace TestTemplates { -// CHECK-FORCE-EMIT-DAG: @_ZTVN13TestTemplates8TemplateIiEE = linkonce_odr constant {{.*}} @_ZTIN13TestTemplates8TemplateIiEE, {{.*}} @_ZN13TestTemplates8TemplateIiE3fooEi, {{.*}}@_ZN13TestTemplates8TemplateIiE22thisShouldBeEmittedTooEi, {{.*}}@_ZN13TestTemplates8TemplateIiED1Ev, {{.*}}@_ZN13TestTemplates8TemplateIiED0Ev +// CHECK-FORCE-EMIT-DAG: @_ZTVN13TestTemplates8TemplateIiEE = linkonce_odr unnamed_addr constant {{.*}} @_ZTIN13TestTemplates8TemplateIiEE, {{.*}} @_ZN13TestTemplates8TemplateIiE3fooEi, {{.*}}@_ZN13TestTemplates8TemplateIiE22thisShouldBeEmittedTooEi, {{.*}}@_ZN13TestTemplates8TemplateIiED1Ev, {{.*}}@_ZN13TestTemplates8TemplateIiED0Ev // CHECK-FORCE-EMIT-DAG: define linkonce_odr noundef i32 @_ZN13TestTemplates8TemplateIiE22thisShouldBeEmittedTooEi template<class T> diff --git a/clang/test/CodeGenCXX/vtable-key-function-ios.cpp b/clang/test/CodeGenCXX/vtable-key-function-ios.cpp index adc378f104c9f..6d9fd0c9afb97 100644 --- a/clang/test/CodeGenCXX/vtable-key-function-ios.cpp +++ b/clang/test/CodeGenCXX/vtable-key-function-ios.cpp @@ -64,7 +64,8 @@ struct Test1a { // V-table needs to be defined weakly. Test1a::Test1a() { use(typeid(Test1a)); } -// CHECK: @_ZTV6Test1a = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test1a = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test1a = linkonce_odr dso_local constant // CHECK-LATE: @_ZTI6Test1a = linkonce_odr {{(dso_local )?}}constant // CHECK-LATE: @_ZTS6Test1a = linkonce_odr {{(dso_local )?}}constant @@ -84,7 +85,8 @@ inline void Test1b::foo() {} // V-table should be defined weakly.. Test1b::Test1b() { use(typeid(Test1b)); } -// CHECK: @_ZTV6Test1b = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test1b = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test1b = linkonce_odr dso_local constant // CHECK: @_ZTI6Test1b = linkonce_odr {{(dso_local )?}}constant // CHECK: @_ZTS6Test1b = linkonce_odr {{(dso_local )?}}constant @@ -98,7 +100,8 @@ struct Test2a { // V-table should be defined with weak linkage. Test2a::Test2a() { use(typeid(Test2a)); } -// CHECK: @_ZTV6Test2a = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test2a = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test2a = linkonce_odr dso_local constant // CHECK-LATE: @_ZTI6Test2a = linkonce_odr {{(dso_local )?}}constant // CHECK-LATE: @_ZTS6Test2a = linkonce_odr {{(dso_local )?}}constant @@ -117,7 +120,8 @@ void Test2b::bar() {} // V-table should be defined with weak linkage. Test2b::Test2b() { use(typeid(Test2b)); } -// CHECK: @_ZTV6Test2b = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test2b = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test2b = linkonce_odr dso_local constant // CHECK-LATE: @_ZTI6Test2b = linkonce_odr {{(dso_local )?}}constant // CHECK-LATE: @_ZTS6Test2b = linkonce_odr {{(dso_local )?}}constant @@ -136,7 +140,8 @@ inline void Test2c::foo() {} // V-table should be defined with weak linkage. Test2c::Test2c() { use(typeid(Test2c)); } -// CHECK: @_ZTV6Test2c = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test2c = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test2c = linkonce_odr dso_local constant // CHECK: @_ZTI6Test2c = linkonce_odr {{(dso_local )?}}constant // CHECK: @_ZTS6Test2c = linkonce_odr {{(dso_local )?}}constant @@ -150,7 +155,8 @@ struct Test3a { // V-table should be defined with weak linkage. Test3a::Test3a() { use(typeid(Test3a)); } -// CHECK: @_ZTV6Test3a = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test3a = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test3a = linkonce_odr dso_local constant // CHECK-LATE: @_ZTI6Test3a = linkonce_odr {{(dso_local )?}}constant // CHECK-LATE: @_ZTS6Test3a = linkonce_odr {{(dso_local )?}}constant @@ -170,7 +176,8 @@ inline void Test3b::bar() {} // V-table should be defined with weak linkage. Test3b::Test3b() { use(typeid(Test3b)); } -// CHECK: @_ZTV6Test3b = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test3b = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test3b = linkonce_odr dso_local constant // CHECK-LATE: @_ZTI6Test3b = linkonce_odr {{(dso_local )?}}constant // CHECK-LATE: @_ZTS6Test3b = linkonce_odr {{(dso_local )?}}constant @@ -191,6 +198,7 @@ inline void Test3c::foo() {} // V-table should be defined with weak linkage. Test3c::Test3c() { use(typeid(Test3c)); } -// CHECK: @_ZTV6Test3c = linkonce_odr {{(dso_local )?}}constant +// CHECK-UNIX: @_ZTV6Test3c = linkonce_odr unnamed_addr constant +// CHECK-MINGW: @_ZTV6Test3c = linkonce_odr dso_local constant // CHECK: @_ZTI6Test3c = linkonce_odr {{(dso_local )?}}constant // CHECK: @_ZTS6Test3c = linkonce_odr {{(dso_local )?}}constant diff --git a/clang/test/CodeGenCXX/vtable-key-function.cpp b/clang/test/CodeGenCXX/vtable-key-function.cpp index d44e8a8d1e910..bf2e6798d2149 100644 --- a/clang/test/CodeGenCXX/vtable-key-function.cpp +++ b/clang/test/CodeGenCXX/vtable-key-function.cpp @@ -9,7 +9,7 @@ struct A { // A does not have a key function, so the first constructor we emit should // cause the vtable to be defined (without assertions.) -// CHECK: @_ZTVN6PR56971AE = linkonce_odr constant +// CHECK: @_ZTVN6PR56971AE = linkonce_odr unnamed_addr constant A::A() { } A::A(int) { } } diff --git a/clang/test/CodeGenCXX/vtt-layout.cpp b/clang/test/CodeGenCXX/vtt-layout.cpp index 64c99651e0aa8..4d8cc817996ea 100644 --- a/clang/test/CodeGenCXX/vtt-layout.cpp +++ b/clang/test/CodeGenCXX/vtt-layout.cpp @@ -83,7 +83,7 @@ namespace Test6 { // CHECK: @_ZTVN5Test61AE ={{.*}}constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIN5Test61AE, ptr @__cxa_deleted_virtual, ptr @_ZN5Test61A6anchorEv] } // CHECK: @_ZTTN5Test21CE = linkonce_odr unnamed_addr constant [2 x ptr] [ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTVN5Test21CE, i32 0, i32 0, i32 4), ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTVN5Test21CE, i32 0, i32 0, i32 4)] // CHECK: @_ZTTN5Test31DE = linkonce_odr unnamed_addr constant [13 x ptr] [ptr getelementptr inbounds inrange(-40, 0) ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr @_ZTVN5Test31DE, i32 0, i32 0, i32 5), ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE0_NS_2C1E, i32 0, i32 0, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE0_NS_2C1E, i32 0, i32 1, i32 3), ptr getelementptr inbounds inrange(-48, 8) ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 0, i32 6), ptr getelementptr inbounds inrange(-48, 8) ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 0, i32 6), ptr getelementptr inbounds inrange(-24, 0) ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 1, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [7 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 2, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr @_ZTVN5Test31DE, i32 0, i32 2, i32 3), ptr getelementptr inbounds inrange(-48, 8) ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr @_ZTVN5Test31DE, i32 0, i32 1, i32 6), ptr getelementptr inbounds inrange(-48, 8) ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr @_ZTVN5Test31DE, i32 0, i32 1, i32 6), ptr getelementptr inbounds inrange(-24, 0) ({ [5 x ptr], [7 x ptr], [4 x ptr], [3 x ptr] }, ptr @_ZTVN5Test31DE, i32 0, i32 3, i32 3), ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE64_NS_2V2E, i32 0, i32 0, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test31DE64_NS_2V2E, i32 0, i32 1, i32 3)] -// CHECK: @_ZTVN5Test41DE = linkonce_odr constant { [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] } { [6 x ptr] [ptr inttoptr (i64 72 to ptr), ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 56 to ptr), ptr inttoptr (i64 40 to ptr), ptr null, ptr @_ZTIN5Test41DE], [8 x ptr] [ptr inttoptr (i64 40 to ptr), ptr inttoptr (i64 24 to ptr), ptr inttoptr (i64 56 to ptr), ptr null, ptr null, ptr inttoptr (i64 -16 to ptr), ptr @_ZTIN5Test41DE, ptr @_ZN5Test42V31gEv], [3 x ptr] [ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 -40 to ptr), ptr @_ZTIN5Test41DE], [4 x ptr] [ptr null, ptr inttoptr (i64 -56 to ptr), ptr @_ZTIN5Test41DE, ptr @_ZN5Test42A21fEv], [4 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -32 to ptr), ptr inttoptr (i64 -72 to ptr), ptr @_ZTIN5Test41DE] } +// CHECK: @_ZTVN5Test41DE = linkonce_odr unnamed_addr constant { [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] } { [6 x ptr] [ptr inttoptr (i64 72 to ptr), ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 56 to ptr), ptr inttoptr (i64 40 to ptr), ptr null, ptr @_ZTIN5Test41DE], [8 x ptr] [ptr inttoptr (i64 40 to ptr), ptr inttoptr (i64 24 to ptr), ptr inttoptr (i64 56 to ptr), ptr null, ptr null, ptr inttoptr (i64 -16 to ptr), ptr @_ZTIN5Test41DE, ptr @_ZN5Test42V31gEv], [3 x ptr] [ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 -40 to ptr), ptr @_ZTIN5Test41DE], [4 x ptr] [ptr null, ptr inttoptr (i64 -56 to ptr), ptr @_ZTIN5Test41DE, ptr @_ZN5Test42A21fEv], [4 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -32 to ptr), ptr inttoptr (i64 -72 to ptr), ptr @_ZTIN5Test41DE] } // CHECK: @_ZTTN5Test41DE = linkonce_odr unnamed_addr constant [19 x ptr] [ptr getelementptr inbounds inrange(-48, 0) ({ [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTVN5Test41DE, i32 0, i32 0, i32 6), ptr getelementptr inbounds inrange(-32, 0) ({ [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE0_NS_2C1E, i32 0, i32 0, i32 4), ptr getelementptr inbounds inrange(-24, 0) ({ [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE0_NS_2C1E, i32 0, i32 1, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE0_NS_2C1E, i32 0, i32 2, i32 3), ptr getelementptr inbounds inrange(-56, 8) ({ [8 x ptr], [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 0, i32 7), ptr getelementptr inbounds inrange(-56, 8) ({ [8 x ptr], [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 0, i32 7), ptr getelementptr inbounds inrange(-32, 0) ({ [8 x ptr], [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 1, i32 4), ptr getelementptr inbounds inrange(-24, 0) ({ [8 x ptr], [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 2, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [8 x ptr], [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 3, i32 3), ptr getelementptr inbounds inrange(-24, 0) ({ [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTVN5Test41DE, i32 0, i32 2, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTVN5Test41DE, i32 0, i32 3, i32 3), ptr getelementptr inbounds inrange(-56, 8) ({ [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTVN5Test41DE, i32 0, i32 1, i32 7), ptr getelementptr inbounds inrange(-56, 8) ({ [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTVN5Test41DE, i32 0, i32 1, i32 7), ptr getelementptr inbounds inrange(-32, 0) ({ [6 x ptr], [8 x ptr], [3 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTVN5Test41DE, i32 0, i32 4, i32 4), ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE40_NS_2V1E, i32 0, i32 0, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE40_NS_2V1E, i32 0, i32 1, i32 3), ptr getelementptr inbounds inrange(-32, 0) ({ [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE72_NS_2V2E, i32 0, i32 0, i32 4), ptr getelementptr inbounds inrange(-24, 0) ({ [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE72_NS_2V2E, i32 0, i32 1, i32 3), ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [3 x ptr], [4 x ptr] }, ptr @_ZTCN5Test41DE72_NS_2V2E, i32 0, i32 2, i32 3)] // CHECK: declare void @__cxa_pure_virtual() unnamed_addr // CHECK: declare void @__cxa_deleted_virtual() unnamed_addr _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
