https://github.com/ahatanak updated https://github.com/llvm/llvm-project/pull/205929
>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/2] [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/2] [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" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
