https://github.com/chbessonova updated 
https://github.com/llvm/llvm-project/pull/205808

>From c58bb45a896c2e4cc02700af751feb553034c412 Mon Sep 17 00:00:00 2001
From: Kristina Bessonova <[email protected]>
Date: Fri, 19 Jun 2026 18:08:22 +0200
Subject: [PATCH 1/3] [PAC][clang] Implement address/type discrimination for
 VTT vtable pointers

Add support for address and type discrimination for vtable pointers stored
in VTTs under the `-fptrauth-vtt-vtable-pointer-discrimination` option.
This option is not enabled by default on any target and works in
combination with `-fptrauth-vtable-pointer-address-discrimination` and/or
`-fptrauth-vtable-pointer-type-discrimination`.

Explicit user control over the signing schema for VTT entries is not
currently supported.

For address discrimination, the address of the corresponding VTT entry is
used as the discriminator.

The type discriminator is computed similarly to the one used for vtable
pointers stored in objects, but is based on the vtable type rather than
its primary base. To distinguish VTT entries from object vtable pointers,
the discriminator is derived from the vtable mangling with an appended
`_VTT` suffix.
---
 clang/include/clang/AST/ASTContext.h          |   4 +-
 clang/include/clang/Basic/Features.def        |   1 +
 clang/include/clang/Basic/LangOptions.def     |   1 +
 clang/include/clang/Options/Options.td        |   2 +
 clang/lib/AST/ASTContext.cpp                  |   5 +-
 clang/lib/CodeGen/CGPointerAuth.cpp           |  30 ++++--
 clang/lib/CodeGen/CGVTT.cpp                   |  27 +++--
 clang/lib/CodeGen/CodeGenFunction.h           |   3 +
 clang/lib/CodeGen/CodeGenModule.h             |  14 +--
 clang/lib/CodeGen/ItaniumCXXABI.cpp           |  10 +-
 clang/lib/Driver/ToolChains/Clang.cpp         |   3 +
 clang/lib/Driver/ToolChains/Linux.cpp         |   5 +
 clang/lib/Frontend/CompilerInvocation.cpp     |  15 ++-
 .../test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp | 102 ++++++++++++++++++
 clang/test/Driver/aarch64-ptrauth.c           |  14 ++-
 clang/test/Preprocessor/ptrauth_feature.c     |  33 ++++--
 16 files changed, 216 insertions(+), 53 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 7ed6509c3c16c..bc2ba9f3d9c91 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1515,8 +1515,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   /// Return the "other" discriminator used for the pointer auth schema used 
for
   /// vtable pointers in instances of the requested type.
-  uint16_t
-  getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD);
+  uint16_t getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD,
+                                                    bool IsVTTEntry = false);
 
   /// Return the "other" type-specific discriminator for the given type.
   uint16_t getPointerAuthTypeDiscriminator(QualType T);
diff --git a/clang/include/clang/Basic/Features.def 
b/clang/include/clang/Basic/Features.def
index f0a9c4889ea2d..cfd5bf69f938c 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -156,6 +156,7 @@ FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
 FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
 FEATURE(ptrauth_vtable_pointer_address_discrimination, 
LangOpts.PointerAuthVTPtrAddressDiscrimination)
 FEATURE(ptrauth_vtable_pointer_type_discrimination, 
LangOpts.PointerAuthVTPtrTypeDiscrimination)
+FEATURE(ptrauth_vtt_vtable_pointer_discrimination, 
LangOpts.PointerAuthVTTVTPtrDiscrimination)
 FEATURE(ptrauth_type_info_vtable_pointer_discrimination, 
LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
 FEATURE(ptrauth_member_function_pointer_type_discrimination, 
LangOpts.PointerAuthCalls)
 FEATURE(ptrauth_signed_block_descriptors, 
LangOpts.PointerAuthBlockDescriptorPointers)
diff --git a/clang/include/clang/Basic/LangOptions.def 
b/clang/include/clang/Basic/LangOptions.def
index 1fb491a54a278..2240c9d506ff3 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -126,6 +126,7 @@ LANGOPT(PointerAuthIndirectGotos, 1, 0, NotCompatible, 
"indirect gotos pointer a
 LANGOPT(PointerAuthAuthTraps, 1, 0, NotCompatible, "pointer authentication 
failure traps")
 LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, NotCompatible, 
"incorporate address discrimination in authenticated vtable pointers")
 LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, NotCompatible, "incorporate 
type discrimination in authenticated vtable pointers")
+LANGOPT(PointerAuthVTTVTPtrDiscrimination, 1, 0, NotCompatible, "incorporate 
discrimination in authenticated vtable pointers in VTTs")
 LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, NotCompatible, 
"incorporate type and address discrimination in authenticated vtable pointers 
for std::type_info")
 LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0, Benign,
         "Use type discrimination when signing function pointers")
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 77c93db0079d5..967f057d12e38 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4991,6 +4991,8 @@ defm ptrauth_vtable_pointer_address_discrimination :
   OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable 
address discrimination of vtable pointers">;
 defm ptrauth_vtable_pointer_type_discrimination :
   OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type 
discrimination of vtable pointers">;
+defm ptrauth_vtt_vtable_pointer_discrimination :
+  OptInCC1FFlag<"ptrauth-vtt-vtable-pointer-discrimination", "Apply the same 
vtable pointer discrimination scheme to VTT entries as to object vtable 
pointers">;
 defm ptrauth_type_info_vtable_pointer_discrimination :
   OptInCC1FFlag<"ptrauth-type-info-vtable-pointer-discrimination", "Enable 
type and address discrimination of vtable pointer of std::type_info">;
 defm ptrauth_function_pointer_type_discrimination : 
OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination",
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2228811546c0f..a5aa05279db1e 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3363,13 +3363,16 @@ QualType ASTContext::removeAddrSpaceQualType(QualType 
T) const {
 }
 
 uint16_t
-ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD) {
+ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD,
+                                                     bool IsVTTEntry) {
   assert(RD->isPolymorphic() &&
          "Attempted to get vtable pointer discriminator on a monomorphic 
type");
   std::unique_ptr<MangleContext> MC(createMangleContext());
   SmallString<256> Str;
   llvm::raw_svector_ostream Out(Str);
   MC->mangleCXXVTable(RD, Out);
+  if (IsVTTEntry)
+    Out << "_VTT";
   return llvm::getPointerAuthStableSipHash(Str);
 }
 
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp 
b/clang/lib/CodeGen/CGPointerAuth.cpp
index 28d3289dfe04f..0fbc889836399 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -561,18 +561,24 @@ llvm::Constant 
*CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
 }
 
 std::optional<PointerAuthQualifier>
-CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
-  auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
+CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass,
+                                              bool IsVTTEntry) {
+  auto DefaultAuthentication =
+      IsVTTEntry ? getCodeGenOpts().PointerAuth.CXXVTTVTablePointers
+                 : getCodeGenOpts().PointerAuth.CXXVTablePointers;
   if (!DefaultAuthentication)
     return std::nullopt;
   const CXXRecordDecl *PrimaryBase =
       Context.baseForVTableAuthentication(ThisClass);
+  const CXXRecordDecl *TypeDiscriminatorClass =
+      IsVTTEntry ? ThisClass : PrimaryBase;
 
   unsigned Key = DefaultAuthentication.getKey();
   bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated();
   auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination();
   unsigned TypeBasedDiscriminator =
-      Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase);
+      Context.getPointerAuthVTablePointerDiscriminator(TypeDiscriminatorClass,
+                                                       IsVTTEntry);
   unsigned Discriminator;
   if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) {
     Discriminator = TypeBasedDiscriminator;
@@ -583,8 +589,11 @@ CodeGenModule::computeVTPointerAuthentication(const 
CXXRecordDecl *ThisClass) {
     assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None);
     Discriminator = 0;
   }
-  if (auto ExplicitAuthentication =
-          PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) {
+  auto ExplicitAuthentication =
+      PrimaryBase->getAttr<VTablePointerAuthenticationAttr>();
+
+  // TODO: enable explicit authentication path for VTT vtable entries.
+  if (!IsVTTEntry && ExplicitAuthentication) {
     auto ExplicitAddressDiscrimination =
         ExplicitAuthentication->getAddressDiscrimination();
     auto ExplicitDiscriminator =
@@ -642,11 +651,12 @@ CodeGenModule::getVTablePointerAuthentication(const 
CXXRecordDecl *Record) {
   return Authentication;
 }
 
-std::optional<CGPointerAuthInfo>
-CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,
-                                        const CXXRecordDecl *Record,
-                                        llvm::Value *StorageAddress) {
-  auto Authentication = getVTablePointerAuthentication(Record);
+std::optional<CGPointerAuthInfo> CodeGenModule::getVTablePointerAuthInfo(
+    CodeGenFunction *CGF, const CXXRecordDecl *Record,
+    llvm::Value *StorageAddress, bool IsVTTEntry) {
+  auto Authentication = IsVTTEntry
+                            ? computeVTPointerAuthentication(Record, 
IsVTTEntry)
+                            : getVTablePointerAuthentication(Record);
   if (!Authentication)
     return std::nullopt;
 
diff --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp
index 989a07d09d50e..caf51d10a4080 100644
--- a/clang/lib/CodeGen/CGVTT.cpp
+++ b/clang/lib/CodeGen/CGVTT.cpp
@@ -55,18 +55,17 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
   }
 
   SmallVector<llvm::Constant *, 8> VTTComponents;
-  for (const VTTComponent *i = Builder.getVTTComponents().begin(),
-                          *e = Builder.getVTTComponents().end(); i != e; ++i) {
-    const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex];
-    llvm::GlobalVariable *VTable = VTables[i->VTableIndex];
+  for (const auto &[Idx, C] : llvm::enumerate(Builder.getVTTComponents())) {
+    const VTTVTable &VTTVT = Builder.getVTTVTables()[C.VTableIndex];
+    llvm::GlobalVariable *VTable = VTables[C.VTableIndex];
     VTableLayout::AddressPointLocation AddressPoint;
     if (VTTVT.getBase() == RD) {
       // Just get the address point for the regular vtable.
       AddressPoint =
           getItaniumVTableContext().getVTableLayout(RD).getAddressPoint(
-              i->VTableBase);
+              C.VTableBase);
     } else {
-      AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
+      AddressPoint = VTableAddressPoints[C.VTableIndex].lookup(C.VTableBase);
       assert(AddressPoint.AddressPointIndex != 0 &&
              "Did not find ctor vtable address point!");
     }
@@ -91,11 +90,17 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
      llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr(
          VTable->getValueType(), VTable, Idxs, /*InBounds=*/true, InRange);
 
-     if (const auto &Schema =
-             CGM.getCodeGenOpts().PointerAuth.CXXVTTVTablePointers)
-       Init = CGM.getConstantSignedPointer(Init, Schema, nullptr, GlobalDecl(),
-                                           QualType());
-
+     if (auto PAuthQual = CGM.computeVTPointerAuthentication(
+             VTTVT.getBase(), /*IsVTTEntry=*/true)) {
+       llvm::Constant *Address = nullptr;
+       if (PAuthQual->isAddressDiscriminated())
+         Address = llvm::ConstantExpr::getGetElementPtr(
+             VTT->getType(), VTT, llvm::ConstantInt::get(CGM.Int32Ty, Idx));
+       auto *Discriminator = llvm::ConstantInt::get(
+           CGM.IntPtrTy, PAuthQual->getExtraDiscriminator());
+       Init = CGM.getConstantSignedPointer(Init, PAuthQual->getKey(), Address,
+                                           Discriminator);
+     }
      VTTComponents.push_back(Init);
   }
 
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index e7c24f1f36f1e..af2107dbbb920 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4668,6 +4668,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// Create the discriminator from the storage address and the entity hash.
   llvm::Value *EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,
                                                  llvm::Value *Discriminator);
+  CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &Schema,
+                                        llvm::Value *StorageAddress,
+                                        llvm::ConstantInt *Discriminator);
   CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &Schema,
                                         llvm::Value *StorageAddress,
                                         GlobalDecl SchemaDecl,
diff --git a/clang/lib/CodeGen/CodeGenModule.h 
b/clang/lib/CodeGen/CodeGenModule.h
index 0abd75ccb0551..ed14244ea0457 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -718,8 +718,6 @@ class CodeGenModule : public CodeGenTypeCache {
 
   llvm::DenseMap<const CXXRecordDecl *, std::optional<PointerAuthQualifier>>
       VTablePtrAuthInfos;
-  std::optional<PointerAuthQualifier>
-  computeVTPointerAuthentication(const CXXRecordDecl *ThisClass);
 
   AtomicOptions AtomicOpts;
 
@@ -1160,14 +1158,18 @@ class CodeGenModule : public CodeGenTypeCache {
                                    GlobalDecl SchemaDecl, QualType SchemaType);
 
   uint16_t getPointerAuthDeclDiscriminator(GlobalDecl GD);
-  std::optional<CGPointerAuthInfo>
-  getVTablePointerAuthInfo(CodeGenFunction *Context,
-                           const CXXRecordDecl *Record,
-                           llvm::Value *StorageAddress);
+
+  std::optional<CGPointerAuthInfo> getVTablePointerAuthInfo(
+      CodeGenFunction *Context, const CXXRecordDecl *Record,
+      llvm::Value *StorageAddress, bool IsVTTEntry = false);
 
   std::optional<PointerAuthQualifier>
   getVTablePointerAuthentication(const CXXRecordDecl *thisClass);
 
+  std::optional<PointerAuthQualifier>
+  computeVTPointerAuthentication(const CXXRecordDecl *ThisClass,
+                                 bool IsVTTEntry = false);
+
   CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD);
 
   // Return whether RTTI information should be emitted for this target.
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index b17478cb7ffde..f16293f4c2658 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -29,6 +29,7 @@
 #include "clang/AST/Mangle.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/Type.h"
+#include "clang/Basic/PointerAuthOptions.h"
 #include "clang/CodeGen/ConstantInitBuilder.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/GlobalValue.h"
@@ -2231,13 +2232,10 @@ llvm::Value 
*ItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
       CGF.Builder.CreateAlignedLoad(CGF.GlobalsVoidPtrTy, VTT,
                                     CGF.getPointerAlign());
 
-  if (auto &Schema = 
CGF.CGM.getCodeGenOpts().PointerAuth.CXXVTTVTablePointers) {
-    CGPointerAuthInfo PointerAuth = CGF.EmitPointerAuthInfo(Schema, VTT,
-                                                            GlobalDecl(),
-                                                            QualType());
-    AP = CGF.EmitPointerAuthAuth(PointerAuth, AP);
+  if (auto PointerAuth = CGM.getVTablePointerAuthInfo(&CGF, VTableClass, VTT,
+                                                      /*IsVTTEntry=*/true)) {
+    AP = CGF.EmitPointerAuthAuth(*PointerAuth, AP);
   }
-
   return AP;
 }
 
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 961906e02639a..3aea4f4bcb26d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1732,6 +1732,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
     Args.addOptInFlag(
         CmdArgs, options::OPT_fptrauth_vtable_pointer_type_discrimination,
         options::OPT_fno_ptrauth_vtable_pointer_type_discrimination);
+    Args.addOptInFlag(
+        CmdArgs, options::OPT_fptrauth_vtt_vtable_pointer_discrimination,
+        options::OPT_fno_ptrauth_vtt_vtable_pointer_discrimination);
     Args.addOptInFlag(
         CmdArgs, options::OPT_fptrauth_type_info_vtable_pointer_discrimination,
         options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination);
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp 
b/clang/lib/Driver/ToolChains/Linux.cpp
index 8d30a5ead3bbb..19d5c707951e3 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -527,6 +527,11 @@ static void handlePAuthABI(const Driver &D, const ArgList 
&DriverArgs,
           options::OPT_fno_ptrauth_vtable_pointer_type_discrimination))
     CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination");
 
+  if (!DriverArgs.hasArg(
+          options::OPT_fptrauth_vtt_vtable_pointer_discrimination,
+          options::OPT_fno_ptrauth_vtt_vtable_pointer_discrimination))
+    CC1Args.push_back("-fptrauth-vtt-vtable-pointer-discrimination");
+
   if (!DriverArgs.hasArg(
           options::OPT_fptrauth_type_info_vtable_pointer_discrimination,
           options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination))
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp 
b/clang/lib/Frontend/CompilerInvocation.cpp
index 6545307a8c8a7..9daee578ff242 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1480,8 +1480,15 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
       Opts.CXXTypeInfoVTablePointer =
           PointerAuthSchema(Key::ASDA, false, Discrimination::None);
 
-    Opts.CXXVTTVTablePointers =
-        PointerAuthSchema(Key::ASDA, false, Discrimination::None);
+    if (LangOpts.PointerAuthVTTVTPtrDiscrimination)
+      Opts.CXXVTTVTablePointers = PointerAuthSchema(
+          Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination,
+          LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type
+                                                      : Discrimination::None);
+    else
+      Opts.CXXVTTVTablePointers =
+          PointerAuthSchema(Key::ASDA, false, Discrimination::None);
+
     Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers =
         PointerAuthSchema(Key::ASIA, true, Discrimination::Decl);
     Opts.CXXMemberFunctionPointers =
@@ -3599,6 +3606,8 @@ static void GeneratePointerAuthArgs(const LangOptions 
&Opts,
     GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination);
   if (Opts.PointerAuthVTPtrTypeDiscrimination)
     GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
+  if (Opts.PointerAuthVTTVTPtrDiscrimination)
+    GenerateArg(Consumer, OPT_fptrauth_vtt_vtable_pointer_discrimination);
   if (Opts.PointerAuthTypeInfoVTPtrDiscrimination)
     GenerateArg(Consumer, 
OPT_fptrauth_type_info_vtable_pointer_discrimination);
   if (Opts.PointerAuthFunctionTypeDiscrimination)
@@ -3632,6 +3641,8 @@ static void ParsePointerAuthArgs(LangOptions &Opts, 
ArgList &Args,
       Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);
   Opts.PointerAuthVTPtrTypeDiscrimination =
       Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
+  Opts.PointerAuthVTTVTPtrDiscrimination =
+      Args.hasArg(OPT_fptrauth_vtt_vtable_pointer_discrimination);
   Opts.PointerAuthTypeInfoVTPtrDiscrimination =
       Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination);
   Opts.PointerAuthFunctionTypeDiscrimination =
diff --git a/clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp 
b/clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp
new file mode 100644
index 0000000000000..1c344d5247eaf
--- /dev/null
+++ b/clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp
@@ -0,0 +1,102 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest 
-fptrauth-calls -disable-llvm-passes \
+// RUN:     -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,DEFAULT %s
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest 
-fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \
+// RUN:     -disable-llvm-passes -emit-llvm -O0 -o - | FileCheck 
--check-prefixes=CHECK,DEFAULT %s
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest 
-fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \
+// RUN:     -fptrauth-vtable-pointer-address-discrimination 
-disable-llvm-passes -emit-llvm -O0 -o - | FileCheck 
--check-prefixes=CHECK,ADDRESS %s
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest 
-fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \
+// RUN:     -fptrauth-vtable-pointer-type-discrimination -disable-llvm-passes 
-emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,TYPE %s
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-pauthtest 
-fptrauth-calls -fptrauth-vtt-vtable-pointer-discrimination \
+// RUN:     -fptrauth-vtable-pointer-address-discrimination 
-fptrauth-vtable-pointer-type-discrimination \
+// RUN:     -disable-llvm-passes -emit-llvm -O0 -o - | FileCheck 
--check-prefixes=CHECK,ADDRESSTYPE %s
+
+// CHECK:      @_ZTT1D = linkonce_odr unnamed_addr constant [4 x ptr] [
+// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2),
+// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2),
+// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2),
+// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2)]
+
+// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 0, ptr @_ZTT1D),
+// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr 
getelementptr (ptr, ptr @_ZTT1D, i32 1)),
+// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr 
getelementptr (ptr, ptr @_ZTT1D, i32 2)),
+// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 0, ptr getelementptr 
(ptr, ptr @_ZTT1D, i32 3))]
+
+// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x 
ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820),
+// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x 
ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118),
+// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x 
ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118),
+// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x 
ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820)]
+
+// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) 
({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820, ptr @_ZTT1D),
+// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) 
({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr 
getelementptr (ptr, ptr @_ZTT1D, i32 1)),
+// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) 
({ [5 x ptr] }, ptr @_ZTC1D0_1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr 
getelementptr (ptr, ptr @_ZTT1D, i32 2)),
+// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) 
({ [5 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4), i32 2, i64 820, ptr 
getelementptr (ptr, ptr @_ZTT1D, i32 3))]
+
+// CHECK:      @_ZTT1A = linkonce_odr unnamed_addr constant [2 x ptr] [
+// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2),
+// DEFAULT-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2)]
+
+// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr @_ZTT1A),
+// ADDRESS-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 
x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 0, ptr getelementptr 
(ptr, ptr @_ZTT1A, i32 1))]
+
+// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x 
ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118),
+// TYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) ({ [5 x 
ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118)]
+
+// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) 
({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr 
@_ZTT1A),
+// ADDRESSTYPE-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-32, 8) 
({ [5 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4), i32 2, i64 49118, ptr 
getelementptr (ptr, ptr @_ZTT1A, i32 1))]
+
+// CHECK-LABEL: @_ZN1AC2Ev
+// CHECK:       %vtt.addr = alloca ptr, align 8
+// CHECK:       store ptr %vtt, ptr %vtt.addr, align 8
+// CHECK:       [[VTT:%.*]] = load ptr, ptr %vtt.addr, align 8
+// CHECK:       [[VTABLE:%.*]] = load ptr, ptr [[VTT]], align 8
+// ADDRESS:     [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64
+// ADDRESSTYPE: [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64
+// ADDRESSTYPE: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[VTABLE_ADDR]], i64 49118)
+// CHECK:       [[VTABLEi64:%.*]] = ptrtoint ptr [[VTABLE]] to i64
+// DEFAULT:     call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 0)
+// ADDRESS:     call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 
[[VTABLE_ADDR]])
+// TYPE:        call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 
49118)
+// ADDRESSTYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 
[[DISC]])
+
+// CHECK:       [[VTTOFFSET:%.*]]  = getelementptr inbounds ptr, ptr [[VTT]], 
i64 1
+// CHECK:       [[VTABLE2:%.*]] = load ptr, ptr [[VTTOFFSET]], align 8
+// ADDRESS:     [[VTABLE2_ADDR:%.*]] = ptrtoint ptr [[VTTOFFSET]] to i64
+// ADDRESSTYPE: [[VTABLE2_ADDR:%.*]] = ptrtoint ptr [[VTTOFFSET]] to i64
+// ADDRESSTYPE: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[VTABLE2_ADDR]], i64 49118)
+// CHECK:       [[VTABLE2i64:%.*]] = ptrtoint ptr [[VTABLE2]] to i64
+// DEFAULT:     call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 0)
+// ADDRESS:     call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 
[[VTABLE2_ADDR]])
+// TYPE:        call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 
49118)
+// ADDRESSTYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLE2i64]], i32 2, i64 
[[DISC]])
+
+// CHECK-LABEL: @_ZN1DC2Ev
+// CHECK:       %vtt.addr = alloca ptr, align 8
+// CHECK:       store ptr %vtt, ptr %vtt.addr, align 8
+// CHECK:       [[VTT:%.*]] = load ptr, ptr %vtt.addr, align 8
+// CHECK:       [[VTTOFFSET:%.*]] = getelementptr inbounds ptr, ptr [[VTT]], 
i64 1
+// CHECK:       call void @_ZN1AC2Ev(ptr noundef nonnull align 8 
dereferenceable(8) %this1, ptr noundef [[VTTOFFSET]])
+// CHECK:       [[VTABLE:%.*]] = load ptr, ptr [[VTT]], align 8
+// ADDRESS:     [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64
+// ADDRESSTYPE: [[VTABLE_ADDR:%.*]] = ptrtoint ptr [[VTT]] to i64
+// ADDRESSTYPE: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[VTABLE_ADDR]], i64 820)
+// CHECK:       [[VTABLEi64:%.*]] = ptrtoint ptr [[VTABLE]] to i64
+// DEFAULT:     call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 0)
+// ADDRESS:     call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 
[[VTABLE_ADDR]])
+// TYPE:        call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 820)
+// ADDRESSTYPE: call i64 @llvm.ptrauth.auth(i64 [[VTABLEi64]], i32 2, i64 
[[DISC]])
+
+struct V {
+    virtual void f();
+};
+
+struct A : virtual V {
+    A();
+};
+
+struct D : A {
+    D();
+};
+
+A::A() {}
+D::D() {}
diff --git a/clang/test/Driver/aarch64-ptrauth.c 
b/clang/test/Driver/aarch64-ptrauth.c
index a67e98fdda714..b328ddfe0ac9d 100644
--- a/clang/test/Driver/aarch64-ptrauth.c
+++ b/clang/test/Driver/aarch64-ptrauth.c
@@ -12,6 +12,7 @@
 // RUN:   -fno-ptrauth-auth-traps -fptrauth-auth-traps \
 // RUN:   -fno-ptrauth-vtable-pointer-address-discrimination 
-fptrauth-vtable-pointer-address-discrimination \
 // RUN:   -fno-ptrauth-vtable-pointer-type-discrimination 
-fptrauth-vtable-pointer-type-discrimination \
+// RUN:   -fno-ptrauth-vtt-vtable-pointer-discrimination 
-fptrauth-vtt-vtable-pointer-discrimination \
 // RUN:   -fno-ptrauth-type-info-vtable-pointer-discrimination 
-fptrauth-type-info-vtable-pointer-discrimination \
 // RUN:   -fno-ptrauth-indirect-gotos -fptrauth-indirect-gotos \
 // RUN:   -fno-ptrauth-init-fini -fptrauth-init-fini \
@@ -26,6 +27,7 @@
 // RUN:   -fno-ptrauth-auth-traps -fptrauth-auth-traps \
 // RUN:   -fno-ptrauth-vtable-pointer-address-discrimination 
-fptrauth-vtable-pointer-address-discrimination \
 // RUN:   -fno-ptrauth-vtable-pointer-type-discrimination 
-fptrauth-vtable-pointer-type-discrimination \
+// RUN:   -fno-ptrauth-vtt-vtable-pointer-discrimination 
-fptrauth-vtt-vtable-pointer-discrimination \
 // RUN:   -fno-ptrauth-type-info-vtable-pointer-discrimination 
-fptrauth-type-info-vtable-pointer-discrimination \
 // RUN:   -fno-ptrauth-indirect-gotos -fptrauth-indirect-gotos \
 // RUN:   -fno-ptrauth-init-fini -fptrauth-init-fini \
@@ -33,7 +35,7 @@
 // RUN:   -fno-ptrauth-elf-got -fptrauth-elf-got \
 // RUN:   -fno-aarch64-jump-table-hardening -faarch64-jump-table-hardening \
 // RUN:   %s 2>&1 | FileCheck %s --check-prefix=ALL-LINUX-PAUTHABI
-// ALL-LINUX-PAUTHABI: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" 
"-fptrauth-returns" "-fptrauth-auth-traps" 
"-fptrauth-vtable-pointer-address-discrimination" 
"-fptrauth-vtable-pointer-type-discrimination" 
"-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" 
"-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" 
"-fptrauth-elf-got"{{.*}} "-faarch64-jump-table-hardening"
+// ALL-LINUX-PAUTHABI: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" 
"-fptrauth-returns" "-fptrauth-auth-traps" 
"-fptrauth-vtable-pointer-address-discrimination" 
"-fptrauth-vtable-pointer-type-discrimination" 
"-fptrauth-vtt-vtable-pointer-discrimination" 
"-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" 
"-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" 
"-fptrauth-elf-got"{{.*}} "-faarch64-jump-table-hardening"
 
 // RUN: %clang -### -c --target=aarch64-linux \
 // RUN:   -fno-aarch64-jump-table-hardening -faarch64-jump-table-hardening \
@@ -57,19 +59,21 @@
 // RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest %s 2>&1 | 
FileCheck %s --check-prefix=PAUTHABI1
 // RUN: %clang -### -c --target=aarch64-linux-pauthtest %s 2>&1 | FileCheck %s 
--check-prefix=PAUTHABI1
 // PAUTHABI1:      "-cc1"{{.*}} "-triple" "aarch64-unknown-linux-pauthtest"
-// PAUTHABI1-SAME: "-fptrauth-intrinsics" "-fptrauth-calls" 
"-fptrauth-returns" "-fptrauth-auth-traps" 
"-fptrauth-vtable-pointer-address-discrimination" 
"-fptrauth-vtable-pointer-type-discrimination" 
"-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" 
"-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" 
"-faarch64-jump-table-hardening"
+// PAUTHABI1-SAME: "-fptrauth-intrinsics" "-fptrauth-calls" 
"-fptrauth-returns" "-fptrauth-auth-traps" 
"-fptrauth-vtable-pointer-address-discrimination" 
"-fptrauth-vtable-pointer-type-discrimination" 
"-fptrauth-vtt-vtable-pointer-discrimination" 
"-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" 
"-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" 
"-faarch64-jump-table-hardening"
 // PAUTHABI1-SAME: "-target-abi" "pauthtest"
 // PAUTHABI1-NOT: "-fptrauth-function-pointer-type-discrimination"
 
 // RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest 
-fno-ptrauth-intrinsics \
 // RUN:   -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \
 // RUN:   -fno-ptrauth-vtable-pointer-address-discrimination 
-fno-ptrauth-vtable-pointer-type-discrimination \
+// RUN:   -fno-ptrauth-vtt-vtable-pointer-discrimination \
 // RUN:   -fno-ptrauth-type-info-vtable-pointer-discrimination 
-fno-ptrauth-indirect-gotos \
 // RUN:   -fno-ptrauth-init-fini -fno-ptrauth-init-fini-address-discrimination 
\
 // RUN:   -fno-aarch64-jump-table-hardening %s 2>&1 | FileCheck %s 
--check-prefix=PAUTHABI2
 // RUN: %clang -### -c --target=aarch64-linux-pauthtest 
-fno-ptrauth-intrinsics \
 // RUN:   -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \
 // RUN:   -fno-ptrauth-vtable-pointer-address-discrimination 
-fno-ptrauth-vtable-pointer-type-discrimination \
+// RUN:   -fno-ptrauth-vtt-vtable-pointer-discrimination \
 // RUN:   -fno-ptrauth-type-info-vtable-pointer-discrimination 
-fno-ptrauth-indirect-gotos \
 // RUN:   -fno-ptrauth-init-fini -fno-ptrauth-init-fini-address-discrimination 
\
 // RUN:   -fno-aarch64-jump-table-hardening %s 2>&1 | FileCheck %s 
--check-prefix=PAUTHABI2
@@ -93,14 +97,16 @@
 //// Non-pauthtest ABI.
 // RUN: not %clang -### -c --target=aarch64-linux -fptrauth-intrinsics 
-fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \
 // RUN:   -fptrauth-vtable-pointer-address-discrimination 
-fptrauth-vtable-pointer-type-discrimination \
-// RUN:   -fptrauth-type-info-vtable-pointer-discrimination 
-fptrauth-indirect-gotos -fptrauth-init-fini \
-// RUN:   -fptrauth-init-fini-address-discrimination -fptrauth-elf-got %s 2>&1 
| FileCheck %s --check-prefix=ERR1
+// RUN:   -fptrauth-vtt-vtable-pointer-discrimination 
-fptrauth-type-info-vtable-pointer-discrimination \
+// RUN:   -fptrauth-indirect-gotos -fptrauth-init-fini 
-fptrauth-init-fini-address-discrimination \
+// RUN:   -fptrauth-elf-got %s 2>&1 | FileCheck %s --check-prefix=ERR1
 // ERR1:      error: unsupported option '-fptrauth-intrinsics' for target 
'{{.*}}'
 // ERR1-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}'
 // ERR1-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}'
 // ERR1-NEXT: error: unsupported option '-fptrauth-auth-traps' for target 
'{{.*}}'
 // ERR1-NEXT: error: unsupported option 
'-fptrauth-vtable-pointer-address-discrimination' for target '{{.*}}'
 // ERR1-NEXT: error: unsupported option 
'-fptrauth-vtable-pointer-type-discrimination' for target '{{.*}}'
+// ERR1-NEXT: error: unsupported option 
'-fptrauth-vtt-vtable-pointer-discrimination' for target '{{.*}}'
 // ERR1-NEXT: error: unsupported option 
'-fptrauth-type-info-vtable-pointer-discrimination' for target '{{.*}}'
 // ERR1-NEXT: error: unsupported option '-fptrauth-indirect-gotos' for target 
'{{.*}}'
 // ERR1-NEXT: error: unsupported option '-fptrauth-init-fini' for target 
'{{.*}}'
diff --git a/clang/test/Preprocessor/ptrauth_feature.c 
b/clang/test/Preprocessor/ptrauth_feature.c
index cebea4188415f..c187dd0160355 100644
--- a/clang/test/Preprocessor/ptrauth_feature.c
+++ b/clang/test/Preprocessor/ptrauth_feature.c
@@ -2,37 +2,40 @@
 //// For example, -fptrauth-init-fini will not affect codegen without 
-fptrauth-calls, but the preprocessor feature would be set anyway.
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-intrinsics | \
-// RUN:   FileCheck %s 
--check-prefixes=INTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=INTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-calls | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,CALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,CALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-returns | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,RETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,RETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 
-fptrauth-vtable-pointer-address-discrimination | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
+
+// RUN: %clang_cc1 -E %s -triple=aarch64 
-fptrauth-vtt-vtable-pointer-discrimination | \
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,VTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 
-fptrauth-vtable-pointer-type-discrimination | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 
-fptrauth-type-info-vtable-pointer-discrimination | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,TYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,TYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 
-fptrauth-function-pointer-type-discrimination | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,FUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,FUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-init-fini | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,INITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,INITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 
-fptrauth-init-fini-address-discrimination | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,INITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,INITFINI_ADDR_DISCR,NOGOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-indirect-gotos | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,GOTOS,NOELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,GOTOS,NOELFGOT,NOVTT
 
 // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-elf-got | \
-// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,ELFGOT
+// RUN:   FileCheck %s 
--check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,ELFGOT,NOVTT
 
 #if defined(__PTRAUTH__)
 // INTRIN: has_ptrauth_intrinsics
@@ -83,6 +86,14 @@ void has_ptrauth_vtable_pointer_type_discrimination() {}
 void no_ptrauth_vtable_pointer_type_discrimination() {}
 #endif
 
+#if __has_feature(ptrauth_vtt_vtable_pointer_discrimination)
+// VTT: has_ptrauth_vtt_vtable_pointer_discrimination
+void has_ptrauth_vtt_vtable_pointer_discrimination() {}
+#else
+// NOVTT: no_ptrauth_vtt_vtable_pointer_discrimination
+void no_ptrauth_vtt_vtable_pointer_discrimination() {}
+#endif
+
 #if __has_feature(ptrauth_type_info_vtable_pointer_discrimination)
 // TYPE_INFO_DISCR: has_ptrauth_type_info_vtable_pointer_discrimination
 void has_ptrauth_type_info_vtable_pointer_discrimination() {}

>From 9f33ec2a97289a295fbaba7fada5a6433276fec3 Mon Sep 17 00:00:00 2001
From: Kristina Bessonova <[email protected]>
Date: Wed, 15 Jul 2026 23:57:27 +0200
Subject: [PATCH 2/3] Address review comments

---
 clang/include/clang/AST/ASTContext.h |  4 ++--
 clang/lib/AST/ItaniumMangle.cpp      |  3 ++-
 clang/lib/CodeGen/CGExprConstant.cpp |  4 +++-
 clang/lib/CodeGen/CGPointerAuth.cpp  | 22 +++++++++++-----------
 clang/lib/CodeGen/CGVTT.cpp          |  5 +++--
 clang/lib/CodeGen/CodeGenModule.h    |  8 ++++----
 clang/lib/CodeGen/ItaniumCXXABI.cpp  |  4 ++--
 7 files changed, 27 insertions(+), 23 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index bc2ba9f3d9c91..c6b77295fb34b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1514,9 +1514,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
   QualType removeAddrSpaceQualType(QualType T) const;
 
   /// Return the "other" discriminator used for the pointer auth schema used 
for
-  /// vtable pointers in instances of the requested type.
+  /// vtable pointers using the given discriminator type.
   uint16_t getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD,
-                                                    bool IsVTTEntry = false);
+                                                    bool IsVTTEntry);
 
   /// Return the "other" type-specific discriminator for the given type.
   uint16_t getPointerAuthTypeDiscriminator(QualType T);
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 172a19f8f3537..76c91a6da6dfc 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -7363,7 +7363,8 @@ static void mangleOverrideDiscrimination(CXXNameMangler 
&Mangler,
   const CXXRecordDecl *PtrauthClassRD =
       Context.baseForVTableAuthentication(ThisRD);
   unsigned TypedDiscriminator =
-      Context.getPointerAuthVTablePointerDiscriminator(ThisRD);
+      Context.getPointerAuthVTablePointerDiscriminator(ThisRD,
+                                                       /*IsVTTEntry=*/false);
   Mangler.mangleVendorQualifier("__vtptrauth");
   auto &ManglerStream = Mangler.getStream();
   ManglerStream << "I";
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp 
b/clang/lib/CodeGen/CGExprConstant.cpp
index 27b7423a42f98..76dc1ee4a4250 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -850,7 +850,9 @@ bool ConstStructBuilder::Build(const APValue &Val, const 
RecordDecl *RD,
       llvm::Constant *VTableAddressPoint =
           CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset),
                                                 VTableClass);
-      if (auto Authentication = CGM.getVTablePointerAuthentication(CD)) {
+      if (auto Authentication =
+              CGM.getVTablePointerAuthentication(CD,
+                                                 /*IsVTTEntry=*/false)) {
         VTableAddressPoint = Emitter.tryEmitConstantSignedPointer(
             VTableAddressPoint, *Authentication);
         if (!VTableAddressPoint)
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp 
b/clang/lib/CodeGen/CGPointerAuth.cpp
index 0fbc889836399..38f95eff242b1 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -636,27 +636,27 @@ CodeGenModule::computeVTPointerAuthentication(const 
CXXRecordDecl *ThisClass,
 }
 
 std::optional<PointerAuthQualifier>
-CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) {
+CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record,
+                                              bool IsVTTEntry) {
   if (!Record->getDefinition() || !Record->isPolymorphic())
     return std::nullopt;
 
-  auto Existing = VTablePtrAuthInfos.find(Record);
-  std::optional<PointerAuthQualifier> Authentication;
-  if (Existing != VTablePtrAuthInfos.end()) {
-    Authentication = Existing->getSecond();
-  } else {
-    Authentication = computeVTPointerAuthentication(Record);
-    VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));
+  if (!IsVTTEntry) {
+    auto Existing = VTablePtrAuthInfos.find(Record);
+    if (Existing != VTablePtrAuthInfos.end())
+      return Existing->getSecond();
   }
+  std::optional<PointerAuthQualifier> Authentication =
+      computeVTPointerAuthentication(Record, IsVTTEntry);
+  if (!IsVTTEntry)
+    VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));
   return Authentication;
 }
 
 std::optional<CGPointerAuthInfo> CodeGenModule::getVTablePointerAuthInfo(
     CodeGenFunction *CGF, const CXXRecordDecl *Record,
     llvm::Value *StorageAddress, bool IsVTTEntry) {
-  auto Authentication = IsVTTEntry
-                            ? computeVTPointerAuthentication(Record, 
IsVTTEntry)
-                            : getVTablePointerAuthentication(Record);
+  auto Authentication = getVTablePointerAuthentication(Record, IsVTTEntry);
   if (!Authentication)
     return std::nullopt;
 
diff --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp
index caf51d10a4080..bfc873ec59f52 100644
--- a/clang/lib/CodeGen/CGVTT.cpp
+++ b/clang/lib/CodeGen/CGVTT.cpp
@@ -90,8 +90,9 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
      llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr(
          VTable->getValueType(), VTable, Idxs, /*InBounds=*/true, InRange);
 
-     if (auto PAuthQual = CGM.computeVTPointerAuthentication(
-             VTTVT.getBase(), /*IsVTTEntry=*/true)) {
+     if (auto PAuthQual =
+             CGM.getVTablePointerAuthentication(VTTVT.getBase(),
+                                                /*IsVTTEntry=*/true)) {
        llvm::Constant *Address = nullptr;
        if (PAuthQual->isAddressDiscriminated())
          Address = llvm::ConstantExpr::getGetElementPtr(
diff --git a/clang/lib/CodeGen/CodeGenModule.h 
b/clang/lib/CodeGen/CodeGenModule.h
index ed14244ea0457..21aee9bcb79e3 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -718,6 +718,9 @@ class CodeGenModule : public CodeGenTypeCache {
 
   llvm::DenseMap<const CXXRecordDecl *, std::optional<PointerAuthQualifier>>
       VTablePtrAuthInfos;
+  std::optional<PointerAuthQualifier>
+  computeVTPointerAuthentication(const CXXRecordDecl *ThisClass,
+                                 bool IsVTTEntry);
 
   AtomicOptions AtomicOpts;
 
@@ -1164,10 +1167,7 @@ class CodeGenModule : public CodeGenTypeCache {
       llvm::Value *StorageAddress, bool IsVTTEntry = false);
 
   std::optional<PointerAuthQualifier>
-  getVTablePointerAuthentication(const CXXRecordDecl *thisClass);
-
-  std::optional<PointerAuthQualifier>
-  computeVTPointerAuthentication(const CXXRecordDecl *ThisClass,
+  getVTablePointerAuthentication(const CXXRecordDecl *thisClass,
                                  bool IsVTTEntry = false);
 
   CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD);
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index f16293f4c2658..fc719c961e737 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2233,9 +2233,9 @@ llvm::Value 
*ItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
                                     CGF.getPointerAlign());
 
   if (auto PointerAuth = CGM.getVTablePointerAuthInfo(&CGF, VTableClass, VTT,
-                                                      /*IsVTTEntry=*/true)) {
+                                                      /*IsVTTEntry=*/true))
     AP = CGF.EmitPointerAuthAuth(*PointerAuth, AP);
-  }
+
   return AP;
 }
 

>From add1e198bb1c629b254faf54f036592a3fad20aa Mon Sep 17 00:00:00 2001
From: Kristina Bessonova <[email protected]>
Date: Tue, 21 Jul 2026 14:54:54 +0200
Subject: [PATCH 3/3] Address review comment

---
 clang/lib/CodeGen/CGPointerAuth.cpp | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp 
b/clang/lib/CodeGen/CGPointerAuth.cpp
index 38f95eff242b1..6889899107266 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -641,15 +641,16 @@ CodeGenModule::getVTablePointerAuthentication(const 
CXXRecordDecl *Record,
   if (!Record->getDefinition() || !Record->isPolymorphic())
     return std::nullopt;
 
-  if (!IsVTTEntry) {
-    auto Existing = VTablePtrAuthInfos.find(Record);
-    if (Existing != VTablePtrAuthInfos.end())
-      return Existing->getSecond();
-  }
+  if (IsVTTEntry)
+    return computeVTPointerAuthentication(Record, IsVTTEntry);
+
+  auto Existing = VTablePtrAuthInfos.find(Record);
+  if (Existing != VTablePtrAuthInfos.end())
+    return Existing->getSecond();
+
   std::optional<PointerAuthQualifier> Authentication =
       computeVTPointerAuthentication(Record, IsVTTEntry);
-  if (!IsVTTEntry)
-    VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));
+  VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));
   return Authentication;
 }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to