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

This adds a function to ASTContext to query whether a type contains values with 
address discriminated pointer auth, and performs the required semantic checks 
to ensure correct reporting of relocatablity in those cases.

For the standardized version, __builtin_is_cpp_trivially_relocatable this means 
rejecting unions of types containing address discriminated values.

For the old deprecated __builtin_is_trivially_relocatable this means rejecting 
any type containing an address discriminated value.

This PR does not update the codegen for __builtin_trivially_relocate, that will 
be in a follow on PR that is much more complex.

>From f47680310ed68a9f8e8cb15bc1cd474740072463 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Thu, 12 Jun 2025 13:17:11 -0700
Subject: [PATCH] [clang] Fix PointerAuth semantics of
 cpp_trivially_relocatable

This adds a function to ASTContext to query whether a type contains
values with address discriminated pointer auth, and performs the
required semantic checks to ensure correct reporting of relocatablity
in those cases.

For the standardized version, __builtin_is_cpp_trivially_relocatable
this means rejecting unions of types containing address discriminated
values.

For the old deprecated __builtin_is_trivially_relocatable this means
rejecting any type containing an address discriminated value.

This PR does not update the codegen for __builtin_trivially_relocate,
that will be in a follow on PR that is much more complex.
---
 clang/include/clang/AST/ASTContext.h          |   4 +
 clang/lib/AST/ASTContext.cpp                  |  49 +++++++++
 clang/lib/Sema/SemaTypeTraits.cpp             |  14 +--
 .../SemaCXX/cxx2c-trivially-relocatable.cpp   |   1 +
 clang/test/SemaCXX/ptrauth-triviality.cpp     |  10 +-
 .../SemaCXX/trivially-relocatable-ptrauth.cpp | 102 ++++++++++++++++++
 6 files changed, 169 insertions(+), 11 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..826f5257b0463 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -628,10 +628,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
   getRelocationInfoForCXXRecord(const CXXRecordDecl *) const;
   void setRelocationInfoForCXXRecord(const CXXRecordDecl *,
                                      CXXRecordDeclRelocationInfo);
+  bool containsAddressDiscriminatedPointerAuth(QualType T);
 
 private:
   llvm::DenseMap<const CXXRecordDecl *, CXXRecordDeclRelocationInfo>
       RelocatableClasses;
+  llvm::DenseMap<const RecordDecl *, bool>
+      RecordContainsAddressDiscriminatedPointerAuth;
 
   ImportDecl *FirstLocalImport = nullptr;
   ImportDecl *LastLocalImport = nullptr;
@@ -3668,6 +3671,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/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b51f7622288df..34b540fd36efc 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1705,6 +1705,40 @@ void ASTContext::setRelocationInfoForCXXRecord(
   RelocatableClasses.insert({D, Info});
 }
 
+bool ASTContext::containsAddressDiscriminatedPointerAuth(QualType T) {
+  if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIntrinsics)
+    return false;
+
+  T = T.getCanonicalType();
+  if (T.hasAddressDiscriminatedPointerAuth())
+    return true;
+  const RecordDecl *RD = T->getAsRecordDecl();
+  if (!RD)
+    return false;
+
+  auto SaveReturn = [this, RD](bool Result) {
+    RecordContainsAddressDiscriminatedPointerAuth.insert({RD, Result});
+    return Result;
+  };
+  if (auto Existing = RecordContainsAddressDiscriminatedPointerAuth.find(RD);
+      Existing != RecordContainsAddressDiscriminatedPointerAuth.end())
+    return Existing->second;
+  if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+    if (CXXRD->isPolymorphic() &&
+        hasAddressDiscriminatedVTableAuthentication(CXXRD))
+      return SaveReturn(true);
+    for (auto Base : CXXRD->bases()) {
+      if (containsAddressDiscriminatedPointerAuth(Base.getType()))
+        return SaveReturn(true);
+    }
+  }
+  for (auto *FieldDecl : RD->fields()) {
+    if (containsAddressDiscriminatedPointerAuth(FieldDecl->getType()))
+      return SaveReturn(true);
+  }
+  return SaveReturn(false);
+}
+
 void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
   assert(!Import->getNextLocalImport() &&
          "Import declaration already in the chain");
@@ -15121,6 +15155,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/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 1738ab4466001..43af236068655 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -188,15 +188,20 @@ static bool IsEligibleForTrivialRelocation(Sema &SemaRef,
       return false;
   }
 
+  bool IsUnion = D->isUnion();
   for (const FieldDecl *Field : D->fields()) {
-    if (Field->getType()->isDependentType())
+    QualType FieldType = Field->getType();
+    if (FieldType->isDependentType())
       continue;
-    if (Field->getType()->isReferenceType())
+    if (FieldType->isReferenceType())
       continue;
     // ... has a non-static data member of an object type that is not
     // of a trivially relocatable type
     if (!SemaRef.IsCXXTriviallyRelocatableType(Field->getType()))
       return false;
+    if (IsUnion &&
+        SemaRef.Context.containsAddressDiscriminatedPointerAuth(FieldType))
+      return false;
   }
   return !D->hasDeletedDestructor();
 }
@@ -322,9 +327,6 @@ bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
   if (BaseElementType.hasNonTrivialObjCLifetime())
     return false;
 
-  if (BaseElementType.hasAddressDiscriminatedPointerAuth())
-    return false;
-
   if (BaseElementType->isIncompleteType())
     return false;
 
@@ -670,7 +672,7 @@ static bool IsTriviallyRelocatableType(Sema &SemaRef, 
QualType T) {
   if (!BaseElementType->isObjectType())
     return false;
 
-  if (T.hasAddressDiscriminatedPointerAuth())
+  if (SemaRef.getASTContext().containsAddressDiscriminatedPointerAuth(T))
     return false;
 
   if (const auto *RD = BaseElementType->getAsCXXRecordDecl();
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