Author: Kristina Bessonova
Date: 2026-08-10T11:56:34-07:00
New Revision: ad716f78e3743a626fe166768d77e2da1ef2e7e2

URL: 
https://github.com/llvm/llvm-project/commit/ad716f78e3743a626fe166768d77e2da1ef2e7e2
DIFF: 
https://github.com/llvm/llvm-project/commit/ad716f78e3743a626fe166768d77e2da1ef2e7e2.diff

LOG: [PAC][clang] Implement address/type discrimination for VTT vtable pointers 
(#205808)

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.

Added: 
    clang/test/CodeGenCXX/ptrauth-vtable-in-vtt.cpp

Modified: 
    clang/docs/PointerAuthentication.md
    clang/docs/ReleaseNotes.md
    clang/include/clang/AST/ASTContext.h
    clang/include/clang/Basic/Features.def
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Basic/PointerAuthOptions.h
    clang/include/clang/Options/Options.td
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/ItaniumMangle.cpp
    clang/lib/CodeGen/CGExprConstant.cpp
    clang/lib/CodeGen/CGPointerAuth.cpp
    clang/lib/CodeGen/CGVTT.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/lib/CodeGen/CodeGenModule.h
    clang/lib/CodeGen/ItaniumCXXABI.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Driver/ToolChains/Linux.cpp
    clang/lib/Frontend/CompilerInvocation.cpp
    clang/test/Driver/aarch64-ptrauth.c
    clang/test/Preprocessor/ptrauth_feature.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/PointerAuthentication.md 
b/clang/docs/PointerAuthentication.md
index fde6d00915369..375c76c2d3785 100644
--- a/clang/docs/PointerAuthentication.md
+++ b/clang/docs/PointerAuthentication.md
@@ -1389,6 +1389,17 @@ override the schema used for the v-table pointer of the 
base type of
 polymorphic class hierarchy. This attribute permits the configuration of the
 key, address diversity mode, and any extra constant discriminator to be used.
 
+Like object v-table pointers, pointers to virtual tables stored in VTTs are
+signed with the `DA` key. By default, no additional address or type
+discrimination is applied. When `-fptrauth-vtt-vtable-pointer-discrimination`
+is enabled, they are additionally discriminated by address and/or type,
+as controlled by the `-fptrauth-vtable-pointer-{address,type}-discrimination`
+options. Address discrimination uses the address of the corresponding VTT 
entry.
+Type discrimination uses the string hash (see 
[`ptrauth_string_discriminator`](#ptrauth-string-discriminator))
+of the mangled v-table identifier of the current class with an appended `_VTT`
+suffix. Unlike object v-table pointers, explicit schema customization for VTT
+entries is currently not supported.
+
 Virtual functions in a C++ virtual table are signed with the `IA` key, address
 diversity, and a constant discriminator equal to the string hash (see
 [`ptrauth_string_discriminator`](#ptrauth-string-discriminator)) of the 
mangled name of the function which

diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 89a8aa0e30463..f719672e8a4e5 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -493,6 +493,10 @@ features cannot lower the translation-unit ABI level;
 
 #### Arm and AArch64 Support
 
+- Added support for pointer authentication discrimination of C++ virtual table
+  pointers stored in VTTs via the `-fptrauth-vtt-vtable-pointer-discrimination`
+  option.
+
 #### Android Support
 
 #### Windows Support

diff  --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index bd4dd2ad06aac..42c9aa0fcf73b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1516,9 +1516,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.
-  uint16_t
-  getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD);
+  /// vtable pointers using the given discriminator type.
+  uint16_t getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD,
+                                                    bool IsVTTEntry);
 
   /// 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 e8ac435b451b0..f945b60b6966d 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/Basic/PointerAuthOptions.h 
b/clang/include/clang/Basic/PointerAuthOptions.h
index 2aa8d70088dbc..17ae1d2835dda 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -54,6 +54,10 @@ constexpr unsigned PointerAuthKeyNone = -1;
 /// the vtable type discriminator for classes derived from std::type_info.
 constexpr uint16_t StdTypeInfoVTablePointerConstantDiscrimination = 0xB1EA;
 
+// Type discriminator suffix to be added to a mangled v-table identifier to
+// ensure that VTT vtable pointer entries get distinct type discriminators.
+constexpr llvm::StringLiteral VTTVTablePointerDiscriminatorSuffix = "_VTT";
+
 class PointerAuthSchema {
 public:
   enum class Kind : unsigned {

diff  --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 5177656bece56..c2e8aaa7d3e1c 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5079,6 +5079,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 5539a39d6edaf..47028c616e45c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3373,13 +3373,17 @@ 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 << VTTVTablePointerDiscriminatorSuffix;
   return llvm::getPointerAuthStableSipHash(Str);
 }
 

diff  --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 96f7d43d69959..f6c4ca1ae6ba8 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -7371,7 +7371,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 257de0145855b..48e80910ce577 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -854,7 +854,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 28d3289dfe04f..6889899107266 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 =
@@ -627,26 +636,28 @@ 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;
 
+  if (IsVTTEntry)
+    return computeVTPointerAuthentication(Record, IsVTTEntry);
+
   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 (Existing != VTablePtrAuthInfos.end())
+    return Existing->getSecond();
+
+  std::optional<PointerAuthQualifier> Authentication =
+      computeVTPointerAuthentication(Record, IsVTTEntry);
+  VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));
   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 = getVTablePointerAuthentication(Record, IsVTTEntry);
   if (!Authentication)
     return std::nullopt;
 

diff  --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp
index 989a07d09d50e..bfc873ec59f52 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,18 @@ 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.getVTablePointerAuthentication(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 783f97dc354eb..1dbc8988cf38f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4679,6 +4679,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 54b08b588dfde..49892b6202192 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -720,7 +720,8 @@ class CodeGenModule : public CodeGenTypeCache {
   llvm::DenseMap<const CXXRecordDecl *, std::optional<PointerAuthQualifier>>
       VTablePtrAuthInfos;
   std::optional<PointerAuthQualifier>
-  computeVTPointerAuthentication(const CXXRecordDecl *ThisClass);
+  computeVTPointerAuthentication(const CXXRecordDecl *ThisClass,
+                                 bool IsVTTEntry);
 
   AtomicOptions AtomicOpts;
 
@@ -1161,13 +1162,14 @@ 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);
+  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 297dccd8110d7..c17813140b10f 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,12 +2232,9 @@ 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 596df3ce9df92..fc54caf642a1a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1712,6 +1712,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 1ab385a9ea001..89af9847e5ae5 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -520,6 +520,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 6562cb3a9b135..56b39dc672aa6 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1476,8 +1476,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 =
@@ -3588,6 +3595,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)
@@ -3621,6 +3630,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 b503acaba28ee..1fc6d224c500d 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 \
@@ -59,12 +61,13 @@
 // RUN: %clang -### -c --target=aarch64-linux-pauthtest %s 2>&1 | \
 // RUN:   FileCheck %s --check-prefix=PAUTHABI1 
--implicit-check-not='"-fptrauth-function-pointer-type-discrimination"'
 // 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" 
"-fptrauth-elf-got" "-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" 
"-fptrauth-elf-got" "-faarch64-jump-table-hardening"
 // PAUTHABI1-SAME: "-target-abi" "pauthtest"
 
 // 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-ptrauth-elf-got -fno-aarch64-jump-table-hardening %s 2>&1 | \
@@ -72,6 +75,7 @@
 // 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-ptrauth-elf-got -fno-aarch64-jump-table-hardening %s 2>&1 | \
@@ -94,14 +98,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() {}


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

Reply via email to