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

Reply via email to