https://github.com/ojhunt created 
https://github.com/llvm/llvm-project/pull/143796

This reworks the way we compute relocatability and replaceability of types. We 
do this by having a single interface the provides a full `TypeRelocationInfo` 
for a QualType. This simplifies the reasoning for all cases, and reduces 
duplication of code.

We still limit our caching of results to CXXRecordDecls but i think it might be 
worth caching on canonical types in future, but for now I didn't want to change 
the caching semantics any further.

TypeRelocationInfo no longer permits raw field access as we can then ensure we 
maintain correct state over pointer auth and similar.

As a basic optimization we gate the additional required work on the existence 
pointer auth options.

>From 4065271030ae410c4a49fd48f6fe2f2a669f9ae5 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Wed, 11 Jun 2025 15:05:47 -0700
Subject: [PATCH] [clang] Fix PointerAuth semantics of
 __builtin_is_cpp_trivially_relocatable

This reworks the way we compute relocatability and replaceability of
types. We do this by having a single interface the provides a full
`TypeRelocationInfo` for a QualType. This simplifies the reasoning
for all cases, and reduces duplication of code.

We still limit our caching of results to CXXRecordDecls but i think
it might be worth caching on canonical types in future, but for now
I didn't want to change the caching semantics any further.

TypeRelocationInfo no longer permits raw field access as we can then
ensure we maintain correct state over pointer auth and similar.

As a basic optimization we gate the additional required work on the
existence pointer auth options.
---
 clang/include/clang/AST/ASTContext.h          |  60 +++++-
 clang/include/clang/Sema/Sema.h               |   7 +-
 clang/lib/AST/ASTContext.cpp                  |  29 ++-
 clang/lib/Sema/SemaDeclCXX.cpp                |   2 +-
 clang/lib/Sema/SemaTypeTraits.cpp             | 188 ++++++++++++------
 .../SemaCXX/cxx2c-trivially-relocatable.cpp   |   1 +
 clang/test/SemaCXX/ptrauth-triviality.cpp     |  10 +-
 .../SemaCXX/trivially-relocatable-ptrauth.cpp | 102 ++++++++++
 8 files changed, 313 insertions(+), 86 deletions(-)
 create mode 100644 clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 8d24d393eab09..4526189a83348 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -620,18 +620,61 @@ class ASTContext : public RefCountedBase<ASTContext> {
   ParameterIndexTable ParamIndices;
 
 public:
-  struct CXXRecordDeclRelocationInfo {
-    unsigned IsRelocatable;
-    unsigned IsReplaceable;
+  struct TypeRelocationInfo {
+    static TypeRelocationInfo invalid() {
+      TypeRelocationInfo Result;
+      Result.IsRelocatable = false;
+      Result.IsReplaceable = false;
+      return Result;
+    }
+
+    TypeRelocationInfo() {}
+    TypeRelocationInfo(bool IsRelocatable, bool IsReplaceable,
+                       bool HasAddressDiscriminatedValues)
+        : IsUnion(false), IsRelocatable(IsRelocatable),
+          IsReplaceable(IsReplaceable),
+          HasAddressDiscriminatedValues(HasAddressDiscriminatedValues) {}
+
+    void setIsUnion(bool Union) {
+      IsUnion = Union;
+      normalizeState();
+    }
+    void updateRelocatable(bool Relocatable) { IsRelocatable &= Relocatable; }
+    void updateReplaceable(bool Replaceable) { IsReplaceable &= Replaceable; }
+    void
+    updateContainsAddressDiscriminatedValues(bool AddressDiscriminatedValues) {
+      HasAddressDiscriminatedValues |= AddressDiscriminatedValues;
+      normalizeState();
+    }
+    void mergeWithSiblingMember(bool IsUnion, const TypeRelocationInfo &Other) 
{
+      updateRelocatable(Other.IsRelocatable);
+      updateReplaceable(Other.IsReplaceable);
+      normalizeState();
+    }
+    bool isRelocatable() const { return IsRelocatable; }
+    bool isReplaceable() const { return IsReplaceable; }
+    bool hasAddressDiscriminatedPointerAuth() const {
+      return HasAddressDiscriminatedValues;
+    }
+
+  private:
+    void normalizeState() {
+      if (!IsUnion || !HasAddressDiscriminatedValues)
+        return;
+      IsRelocatable = false;
+      IsReplaceable = false;
+    }
+    bool IsUnion = false;
+    bool IsRelocatable = true;
+    bool IsReplaceable = true;
+    bool HasAddressDiscriminatedValues = false;
   };
-  std::optional<CXXRecordDeclRelocationInfo>
+  std::optional<TypeRelocationInfo>
   getRelocationInfoForCXXRecord(const CXXRecordDecl *) const;
-  void setRelocationInfoForCXXRecord(const CXXRecordDecl *,
-                                     CXXRecordDeclRelocationInfo);
+  void setRelocationInfoForCXXRecord(const CXXRecordDecl *, 
TypeRelocationInfo);
 
 private:
-  llvm::DenseMap<const CXXRecordDecl *, CXXRecordDeclRelocationInfo>
-      RelocatableClasses;
+  llvm::DenseMap<const CXXRecordDecl *, TypeRelocationInfo> RelocationInfo;
 
   ImportDecl *FirstLocalImport = nullptr;
   ImportDecl *LastLocalImport = nullptr;
@@ -3668,6 +3711,7 @@ OPT_LIST(V)
   /// authentication policy for the specified record.
   const CXXRecordDecl *
   baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
+  bool hasAddressDiscriminatedVTableAuthentication(const CXXRecordDecl *Class);
   bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
                                StringRef MangledName);
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0dad07e55a820..5e405c604598a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4343,8 +4343,10 @@ class Sema final : public SemaBase {
   void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl,
                                 SourceRange BraceRange);
 
-  ASTContext::CXXRecordDeclRelocationInfo
-  CheckCXX2CRelocatableAndReplaceable(const clang::CXXRecordDecl *D);
+  ASTContext::TypeRelocationInfo
+  GetCXX2CTypeRelocationInfo(const clang::CXXRecordDecl *D);
+
+  ASTContext::TypeRelocationInfo GetCXX2CTypeRelocationInfo(QualType T);
 
   void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context);
 
@@ -8680,7 +8682,6 @@ class Sema final : public SemaBase {
   // FIXME: This is in Sema because it requires
   // overload resolution, can we move to ASTContext?
   bool IsCXXTriviallyRelocatableType(QualType T);
-  bool IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD);
 
   //// Determines if a type is replaceable
   /// according to the C++26 rules.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b51f7622288df..b4f1133e6adcd 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1687,22 +1687,22 @@ void ASTContext::getOverriddenMethods(
   Overridden.append(OverDecls.begin(), OverDecls.end());
 }
 
-std::optional<ASTContext::CXXRecordDeclRelocationInfo>
+std::optional<ASTContext::TypeRelocationInfo>
 ASTContext::getRelocationInfoForCXXRecord(const CXXRecordDecl *RD) const {
   assert(RD);
   CXXRecordDecl *D = RD->getDefinition();
-  auto it = RelocatableClasses.find(D);
-  if (it != RelocatableClasses.end())
+  auto it = RelocationInfo.find(D);
+  if (it != RelocationInfo.end())
     return it->getSecond();
   return std::nullopt;
 }
 
-void ASTContext::setRelocationInfoForCXXRecord(
-    const CXXRecordDecl *RD, CXXRecordDeclRelocationInfo Info) {
+void ASTContext::setRelocationInfoForCXXRecord(const CXXRecordDecl *RD,
+                                               TypeRelocationInfo Info) {
   assert(RD);
   CXXRecordDecl *D = RD->getDefinition();
-  assert(RelocatableClasses.find(D) == RelocatableClasses.end());
-  RelocatableClasses.insert({D, Info});
+  assert(RelocationInfo.find(D) == RelocationInfo.end());
+  RelocationInfo.insert({D, Info});
 }
 
 void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
@@ -15121,6 +15121,21 @@ ASTContext::baseForVTableAuthentication(const 
CXXRecordDecl *ThisClass) {
   return PrimaryBase;
 }
 
+bool ASTContext::hasAddressDiscriminatedVTableAuthentication(
+    const CXXRecordDecl *Class) {
+  assert(Class->isPolymorphic());
+  const CXXRecordDecl *BaseType = baseForVTableAuthentication(Class);
+  using AuthAttr = VTablePointerAuthenticationAttr;
+  const auto *ExplicitAuth = BaseType->getAttr<AuthAttr>();
+  if (!ExplicitAuth)
+    return LangOpts.PointerAuthVTPtrAddressDiscrimination;
+  AuthAttr::AddressDiscriminationMode AddressDiscrimination =
+      ExplicitAuth->getAddressDiscrimination();
+  if (AddressDiscrimination == AuthAttr::DefaultAddressDiscrimination)
+    return LangOpts.PointerAuthVTPtrAddressDiscrimination;
+  return AddressDiscrimination == AuthAttr::AddressDiscrimination;
+}
+
 bool ASTContext::useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
                                          StringRef MangledName) {
   auto *Method = cast<CXXMethodDecl>(VirtualMethodDecl.getDecl());
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 39d4d49a0fe79..8e79e975dc270 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -10615,7 +10615,7 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl 
&RD) {
       }
   }
 
-  if (IsCXXTriviallyRelocatableType(RD))
+  if (GetCXX2CTypeRelocationInfo(&RD).isRelocatable())
     return;
 
   // Ill-formed if the copy and move constructors are deleted.
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 1738ab4466001..e2f1322df42a1 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -226,12 +226,13 @@ static bool IsEligibleForReplacement(Sema &SemaRef, const 
CXXRecordDecl *D) {
   return !D->hasDeletedDestructor();
 }
 
-ASTContext::CXXRecordDeclRelocationInfo
-Sema::CheckCXX2CRelocatableAndReplaceable(const CXXRecordDecl *D) {
-  ASTContext::CXXRecordDeclRelocationInfo Info{false, false};
+ASTContext::TypeRelocationInfo
+Sema::GetCXX2CTypeRelocationInfo(const CXXRecordDecl *D) {
+  if (auto ExistingInfo = Context.getRelocationInfoForCXXRecord(D))
+    return *ExistingInfo;
 
   if (!getLangOpts().CPlusPlus || D->isInvalidDecl())
-    return Info;
+    return ASTContext::TypeRelocationInfo::invalid();
 
   assert(D->hasDefinition());
 
@@ -244,12 +245,11 @@ Sema::CheckCXX2CRelocatableAndReplaceable(const 
CXXRecordDecl *D) {
                *this, D, /*AllowUserDefined=*/true);
   };
 
-  auto IsUnion = [&, Is = std::optional<bool>{}]() mutable {
+  auto IsTrivialUnion = [&, Is = std::optional<bool>{}]() mutable {
     if (!Is.has_value())
       Is = D->isUnion() && !D->hasUserDeclaredCopyConstructor() &&
            !D->hasUserDeclaredCopyAssignment() &&
-           !D->hasUserDeclaredMoveOperation() &&
-           !D->hasUserDeclaredDestructor();
+           !D->hasUserDeclaredMoveOperation() && 
!D->hasUserDeclaredDestructor();
     return *Is;
   };
 
@@ -259,7 +259,9 @@ Sema::CheckCXX2CRelocatableAndReplaceable(const 
CXXRecordDecl *D) {
     return *Is;
   };
 
-  Info.IsRelocatable = [&] {
+  ASTContext::TypeRelocationInfo Info;
+
+  Info.updateRelocatable([&] {
     if (D->isDependentType())
       return false;
 
@@ -272,14 +274,14 @@ Sema::CheckCXX2CRelocatableAndReplaceable(const 
CXXRecordDecl *D) {
       return true;
 
     // is a union with no user-declared special member functions, or
-    if (IsUnion())
+    if (IsTrivialUnion())
       return true;
 
     // is default-movable.
     return IsDefaultMovable();
-  }();
+  }());
 
-  Info.IsReplaceable = [&] {
+  Info.updateReplaceable([&] {
     if (D->isDependentType())
       return false;
 
@@ -292,77 +294,133 @@ Sema::CheckCXX2CRelocatableAndReplaceable(const 
CXXRecordDecl *D) {
       return HasSuitableSMP();
 
     // is a union with no user-declared special member functions, or
-    if (IsUnion())
+    if (IsTrivialUnion())
       return HasSuitableSMP();
 
     // is default-movable.
     return IsDefaultMovable();
-  }();
-
+  }());
+
+  Info.setIsUnion(D->isUnion());
+
+  bool PtrauthMatters = LangOpts.PointerAuthIntrinsics ||
+                        LangOpts.PointerAuthVTPtrAddressDiscrimination;
+  if (PtrauthMatters) {
+    auto IsBottomRelocationInfo =
+        [](const ASTContext::TypeRelocationInfo &Info) {
+          return !Info.isReplaceable() && !Info.isRelocatable() &&
+                 Info.hasAddressDiscriminatedPointerAuth();
+        };
+
+    if (D->isPolymorphic())
+      Info.updateContainsAddressDiscriminatedValues(
+          Context.hasAddressDiscriminatedVTableAuthentication(D));
+    for (auto Base : D->bases()) {
+      if (IsBottomRelocationInfo(Info))
+        break;
+      bool BaseHasPtrauth = GetCXX2CTypeRelocationInfo(Base.getType())
+                                .hasAddressDiscriminatedPointerAuth();
+      Info.updateContainsAddressDiscriminatedValues(BaseHasPtrauth);
+    }
+    for (auto *FieldDecl : D->fields()) {
+      if (IsBottomRelocationInfo(Info))
+        break;
+      bool FieldHasPtrauth = GetCXX2CTypeRelocationInfo(FieldDecl->getType())
+                                 .hasAddressDiscriminatedPointerAuth();
+      Info.updateContainsAddressDiscriminatedValues(FieldHasPtrauth);
+    }
+  }
+  Context.setRelocationInfoForCXXRecord(D, Info);
   return Info;
 }
 
-bool Sema::IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD) {
-  if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info =
-          getASTContext().getRelocationInfoForCXXRecord(&RD))
-    return Info->IsRelocatable;
-  ASTContext::CXXRecordDeclRelocationInfo Info =
-      CheckCXX2CRelocatableAndReplaceable(&RD);
-  getASTContext().setRelocationInfoForCXXRecord(&RD, Info);
-  return Info.IsRelocatable;
-}
+ASTContext::TypeRelocationInfo Sema::GetCXX2CTypeRelocationInfo(QualType T) {
+  T = T.getCanonicalType();
+  enum class DirectRelocationInformation { Yes, No, Unknown };
+  DirectRelocationInformation Relocatable =
+      DirectRelocationInformation::Unknown;
+  DirectRelocationInformation Replaceable =
+      DirectRelocationInformation::Unknown;
+  DirectRelocationInformation ContainsAddressDiscriminatedValues =
+      DirectRelocationInformation::Unknown;
+
+  auto UpdateRelocatable = [&](DirectRelocationInformation DRI) {
+    if (Relocatable == DirectRelocationInformation::Unknown ||
+        Relocatable == DirectRelocationInformation::Yes)
+      Relocatable = DRI;
+  };
+  auto UpdateReplaceable = [&](DirectRelocationInformation DRI) {
+    if (Replaceable == DirectRelocationInformation::Unknown ||
+        Replaceable == DirectRelocationInformation::Yes)
+      Replaceable = DRI;
+  };
+  auto UpdateAddressDiscrimination = [&](DirectRelocationInformation DRI) {
+    if (ContainsAddressDiscriminatedValues ==
+            DirectRelocationInformation::Unknown ||
+        ContainsAddressDiscriminatedValues == DirectRelocationInformation::No)
+      ContainsAddressDiscriminatedValues = DRI;
+  };
 
-bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
+  if (T->isVariableArrayType()) {
+    UpdateRelocatable(DirectRelocationInformation::No);
+    UpdateReplaceable(DirectRelocationInformation::No);
+  }
 
-  QualType BaseElementType = getASTContext().getBaseElementType(Type);
+  if (T.isConstQualified() || T.isVolatileQualified())
+    UpdateReplaceable(DirectRelocationInformation::No);
 
-  if (Type->isVariableArrayType())
-    return false;
+  if (T.hasAddressDiscriminatedPointerAuth())
+    UpdateAddressDiscrimination(DirectRelocationInformation::Yes);
+
+  QualType BaseElementType =
+      SemaRef.getASTContext().getBaseElementType(T.getUnqualifiedType());
+
+  if (BaseElementType->isIncompleteType()) {
+    Relocatable = DirectRelocationInformation::No;
+    Replaceable = DirectRelocationInformation::No;
+  }
 
   if (BaseElementType.hasNonTrivialObjCLifetime())
-    return false;
+    UpdateRelocatable(DirectRelocationInformation::No);
 
-  if (BaseElementType.hasAddressDiscriminatedPointerAuth())
-    return false;
+  if (BaseElementType->isScalarType()) {
+    UpdateRelocatable(DirectRelocationInformation::Yes);
+    UpdateReplaceable(DirectRelocationInformation::Yes);
+    UpdateAddressDiscrimination(DirectRelocationInformation::No);
+  }
 
-  if (BaseElementType->isIncompleteType())
-    return false;
+  if (BaseElementType->isVectorType())
+    UpdateRelocatable(DirectRelocationInformation::Yes);
 
-  if (BaseElementType->isScalarType() || BaseElementType->isVectorType())
-    return true;
+  auto CreateInfo = [=]() -> ASTContext::TypeRelocationInfo {
+    ASTContext::TypeRelocationInfo Result;
+    return {Relocatable == DirectRelocationInformation::Yes,
+            Replaceable == DirectRelocationInformation::Yes,
+            ContainsAddressDiscriminatedValues ==
+                DirectRelocationInformation::Yes};
+  };
 
-  if (const auto *RD = BaseElementType->getAsCXXRecordDecl())
-    return IsCXXTriviallyRelocatableType(*RD);
+  if (BaseElementType->isIncompleteType())
+    return CreateInfo();
 
-  return false;
+  const CXXRecordDecl *RD = BaseElementType->getAsCXXRecordDecl();
+  if (!RD)
+    return CreateInfo();
+
+  ASTContext::TypeRelocationInfo Info = GetCXX2CTypeRelocationInfo(RD);
+  Info.updateRelocatable(Relocatable != DirectRelocationInformation::No);
+  Info.updateReplaceable(Replaceable != DirectRelocationInformation::No);
+  Info.updateContainsAddressDiscriminatedValues(
+      ContainsAddressDiscriminatedValues == DirectRelocationInformation::Yes);
+  return Info;
 }
 
-static bool IsCXXReplaceableType(Sema &S, const CXXRecordDecl *RD) {
-  if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info =
-          S.getASTContext().getRelocationInfoForCXXRecord(RD))
-    return Info->IsReplaceable;
-  ASTContext::CXXRecordDeclRelocationInfo Info =
-      S.CheckCXX2CRelocatableAndReplaceable(RD);
-  S.getASTContext().setRelocationInfoForCXXRecord(RD, Info);
-  return Info.IsReplaceable;
+bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
+  return GetCXX2CTypeRelocationInfo(Type).isRelocatable();
 }
 
 bool Sema::IsCXXReplaceableType(QualType Type) {
-  if (Type.isConstQualified() || Type.isVolatileQualified())
-    return false;
-
-  if (Type->isVariableArrayType())
-    return false;
-
-  QualType BaseElementType =
-      getASTContext().getBaseElementType(Type.getUnqualifiedType());
-  if (BaseElementType->isIncompleteType())
-    return false;
-  if (BaseElementType->isScalarType())
-    return true;
-  if (const auto *RD = BaseElementType->getAsCXXRecordDecl())
-    return ::IsCXXReplaceableType(*this, RD);
-  return false;
+  return GetCXX2CTypeRelocationInfo(Type).isReplaceable();
 }
 
 /// Checks that type T is not a VLA.
@@ -674,8 +732,14 @@ static bool IsTriviallyRelocatableType(Sema &SemaRef, 
QualType T) {
     return false;
 
   if (const auto *RD = BaseElementType->getAsCXXRecordDecl();
-      RD && !RD->isPolymorphic() && SemaRef.IsCXXTriviallyRelocatableType(*RD))
-    return true;
+      RD && !RD->isPolymorphic()) {
+    ASTContext::TypeRelocationInfo Info =
+        SemaRef.GetCXX2CTypeRelocationInfo(RD);
+    if (Info.hasAddressDiscriminatedPointerAuth())
+      return false;
+    if (Info.isRelocatable())
+      return true;
+  }
 
   if (const auto *RD = BaseElementType->getAsRecordDecl())
     return RD->canPassInRegisters();
diff --git a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp 
b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp
index 9d43994ee7661..7152a5937d9b7 100644
--- a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp
+++ b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++2c -verify %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-intrinsics 
-fptrauth-calls -std=c++2c -verify %s
 
 class Trivial {};
 static_assert(__builtin_is_cpp_trivially_relocatable(Trivial));
diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp 
b/clang/test/SemaCXX/ptrauth-triviality.cpp
index 60d1b57230f18..6f3650f7ac2e3 100644
--- a/clang/test/SemaCXX/ptrauth-triviality.cpp
+++ b/clang/test/SemaCXX/ptrauth-triviality.cpp
@@ -26,7 +26,7 @@ static_assert(!__is_trivially_assignable(S1, const S1&));
 static_assert(__is_trivially_destructible(S1));
 static_assert(!__is_trivially_copyable(S1));
 static_assert(!__is_trivially_relocatable(S1)); // 
expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(S1));
+static_assert(__builtin_is_cpp_trivially_relocatable(S1));
 static_assert(!__is_trivially_equality_comparable(S1));
 
 static_assert(__is_trivially_constructible(Holder<S1>));
@@ -35,7 +35,7 @@ static_assert(!__is_trivially_assignable(Holder<S1>, const 
Holder<S1>&));
 static_assert(__is_trivially_destructible(Holder<S1>));
 static_assert(!__is_trivially_copyable(Holder<S1>));
 static_assert(!__is_trivially_relocatable(Holder<S1>)); // 
expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(Holder<S1>));
+static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S1>));
 static_assert(!__is_trivially_equality_comparable(Holder<S1>));
 
 struct S2 {
@@ -83,7 +83,7 @@ static_assert(!__is_trivially_constructible(Holder<S3>, const 
Holder<S3>&));
 static_assert(!__is_trivially_assignable(Holder<S3>, const Holder<S3>&));
 static_assert(__is_trivially_destructible(Holder<S3>));
 static_assert(!__is_trivially_copyable(Holder<S3>));
-static_assert(__is_trivially_relocatable(Holder<S3>)); // 
expected-warning{{deprecated}}
+static_assert(!__is_trivially_relocatable(Holder<S3>)); // 
expected-warning{{deprecated}}
 static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S3>));
 static_assert(!__is_trivially_equality_comparable(Holder<S3>));
 
@@ -148,7 +148,7 @@ static_assert(!__is_trivially_assignable(S6, const S6&));
 static_assert(__is_trivially_destructible(S6));
 static_assert(!__is_trivially_copyable(S6));
 static_assert(!__is_trivially_relocatable(S6)); // 
expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(S6));
+static_assert(__builtin_is_cpp_trivially_relocatable(S6));
 static_assert(!__is_trivially_equality_comparable(S6));
 
 static_assert(__is_trivially_constructible(Holder<S6>));
@@ -157,7 +157,7 @@ static_assert(!__is_trivially_assignable(Holder<S6>, const 
Holder<S6>&));
 static_assert(__is_trivially_destructible(Holder<S6>));
 static_assert(!__is_trivially_copyable(Holder<S6>));
 static_assert(!__is_trivially_relocatable(Holder<S6>)); // 
expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(Holder<S6>));
+static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S6>));
 static_assert(!__is_trivially_equality_comparable(Holder<S6>));
 
 struct S7 {
diff --git a/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp 
b/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp
new file mode 100644
index 0000000000000..29722fadd4d17
--- /dev/null
+++ b/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 -triple arm64 -fptrauth-calls -fptrauth-intrinsics 
-std=c++26 -verify %s
+
+// This test intentionally does not enable the global address discrimination
+// of vtable pointers. This lets us configure them with different schemas
+// and verify that we're correctly tracking the existence of address 
discrimination
+
+// expected-no-diagnostics
+
+struct NonAddressDiscPtrauth {
+  void * __ptrauth(1, 0, 1234) p;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(NonAddressDiscPtrauth));
+
+struct AddressDiscPtrauth {
+  void * __ptrauth(1, 1, 1234) p;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(AddressDiscPtrauth));
+
+struct MultipleBaseClasses : NonAddressDiscPtrauth, AddressDiscPtrauth {
+
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(MultipleBaseClasses));
+
+struct MultipleMembers {
+   NonAddressDiscPtrauth field0;
+   AddressDiscPtrauth field1;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(MultipleMembers));
+
+struct UnionOfPtrauth {
+    union {
+        NonAddressDiscPtrauth field0;
+        AddressDiscPtrauth field1;
+    } u;
+};
+
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfPtrauth));
+
+struct 
[[clang::ptrauth_vtable_pointer(process_independent,address_discrimination,no_extra_discrimination)]]
 Polymorphic trivially_relocatable_if_eligible {
+  virtual ~Polymorphic();
+};
+
+struct Foo : Polymorphic {
+  Foo(const Foo&);
+  ~Foo();
+};
+
+
+static_assert(__builtin_is_cpp_trivially_relocatable(Polymorphic));
+
+struct 
[[clang::ptrauth_vtable_pointer(process_independent,no_address_discrimination,no_extra_discrimination)]]
 NonAddressDiscriminatedPolymorphic trivially_relocatable_if_eligible {
+  virtual ~NonAddressDiscriminatedPolymorphic();
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(NonAddressDiscriminatedPolymorphic));
+
+
+struct PolymorphicMembers {
+    Polymorphic field;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(PolymorphicMembers));
+
+struct UnionOfPolymorphic {
+  union trivially_relocatable_if_eligible {
+    Polymorphic p;
+    int i;
+  } u;
+};
+
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfPolymorphic));
+
+
+struct UnionOfNonAddressDiscriminatedPolymorphic {
+  union trivially_relocatable_if_eligible {
+    NonAddressDiscriminatedPolymorphic p;
+    int i;
+  } u;
+};
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfNonAddressDiscriminatedPolymorphic));
+
+struct UnionOfNonAddressDiscriminatedPtrauth {
+  union {
+    NonAddressDiscPtrauth p;
+    int i;
+  } u;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(UnionOfNonAddressDiscriminatedPtrauth));
+
+struct UnionOfAddressDisriminatedPtrauth {
+  union {
+    AddressDiscPtrauth p;
+    int i;
+  } u;
+};
+
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfAddressDisriminatedPtrauth));

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to