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

Reply via email to