[clang] [CodeGen] Disable exact dynamic_cast for duplicable vtables (PR #205929)
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 26 11:46:15 PDT 2026
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 <ahatanak at gmail.com>
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 <ahatanak at gmail.com>
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"
More information about the cfe-commits
mailing list