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

A number of builtins report some variation of "this type is compatibile with 
some bitwise equivalent operation", but this is not true for address 
discriminated values. We had address a number of cases, but not all of them. 
This PR corrects the remaining builtins.

Fixes #154394

>From 36d76976f6e713c50204bfa159e870615427b729 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Wed, 20 Aug 2025 01:28:29 -0700
Subject: [PATCH] [clang][PAC] Fix builtins that claim Address discriminated
 types are copyable

A number of builtins report some variation of "this type is compatibile with
some bitwise equivalent operation", but this is not true for address 
discriminated
values. We had address a number of cases, but not all of them. This PR corrects
the remaining builtins.

Fixes #154394
---
 clang/include/clang/AST/ASTContext.h       |  12 +-
 clang/lib/AST/ASTContext.cpp               |   6 +-
 clang/lib/AST/DeclCXX.cpp                  |   6 +
 clang/lib/AST/Type.cpp                     |  13 ++
 clang/test/SemaCXX/ptrauth-type-traits.cpp | 143 +++++++++++++++++++++
 5 files changed, 171 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/SemaCXX/ptrauth-type-traits.cpp

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 7c2566a09665d..d5944c19b1c15 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -640,7 +640,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// contain data that is address discriminated. This includes
   /// implicitly authenticated values like vtable pointers, as well as
   /// explicitly qualified fields.
-  bool containsAddressDiscriminatedPointerAuth(QualType T) {
+  bool containsAddressDiscriminatedPointerAuth(QualType T) const {
     if (!isPointerAuthenticationAvailable())
       return false;
     return findPointerAuthContent(T) != PointerAuthContent::None;
@@ -654,8 +654,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
   bool containsNonRelocatablePointerAuth(QualType T) {
     if (!isPointerAuthenticationAvailable())
       return false;
-    return findPointerAuthContent(T) ==
-           PointerAuthContent::AddressDiscriminatedData;
+    return findPointerAuthContent(T) !=
+           PointerAuthContent::None;
   }
 
 private:
@@ -673,8 +673,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
   bool isPointerAuthenticationAvailable() const {
     return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics;
   }
-  PointerAuthContent findPointerAuthContent(QualType T);
-  llvm::DenseMap<const RecordDecl *, PointerAuthContent>
+  PointerAuthContent findPointerAuthContent(QualType T) const;
+  mutable llvm::DenseMap<const RecordDecl *, PointerAuthContent>
       RecordContainsAddressDiscriminatedPointerAuth;
 
   ImportDecl *FirstLocalImport = nullptr;
@@ -3720,7 +3720,7 @@ OPT_LIST(V)
   /// Resolve the root record to be used to derive the vtable pointer
   /// authentication policy for the specified record.
   const CXXRecordDecl *
-  baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
+  baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const;
 
   bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
                                StringRef MangledName);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2f2685495a8f1..69c1489eef76b 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1708,7 +1708,7 @@ void ASTContext::setRelocationInfoForCXXRecord(
 }
 
 static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication(
-    ASTContext &Context, const CXXRecordDecl *Class) {
+    const ASTContext &Context, const CXXRecordDecl *Class) {
   if (!Class->isPolymorphic())
     return false;
   const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class);
@@ -1723,7 +1723,7 @@ static bool 
primaryBaseHaseAddressDiscriminatedVTableAuthentication(
   return AddressDiscrimination == AuthAttr::AddressDiscrimination;
 }
 
-ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) {
+ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) 
const {
   assert(isPointerAuthenticationAvailable());
 
   T = T.getCanonicalType();
@@ -15175,7 +15175,7 @@ StringRef ASTContext::getCUIDHash() const {
 }
 
 const CXXRecordDecl *
-ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
+ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const {
   assert(ThisClass);
   assert(ThisClass->isPolymorphic());
   const CXXRecordDecl *PrimaryBase = ThisClass;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 50b1a1d000090..5b032cb44ba76 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1438,6 +1438,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
         data().StructuralIfLiteral = false;
     }
 
+    if (!data().HasTrivialSpecialMembers && 
T.hasAddressDiscriminatedPointerAuth()) {
+      // Address discriminated fields mean that a class is no longer
+      // standard layout.
+      data().HasTrivialSpecialMembers = true;
+    }
+
     // C++14 [meta.unary.prop]p4:
     //   T is a class type [...] with [...] no non-static data members other
     //   than subobjects of zero size
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 5fbf1999ed725..1071a372162aa 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2771,6 +2771,11 @@ bool QualType::isCXX98PODType(const ASTContext &Context) 
const {
     return false;
 
   QualType CanonicalType = getTypePtr()->CanonicalType;
+
+  // Any type that is, or contains, address discriminated data is non-POD
+  if (CanonicalType.hasAddressDiscriminatedPointerAuth())// 
Context.containsAddressDiscriminatedPointerAuth(*this))
+    return false;
+
   switch (CanonicalType->getTypeClass()) {
     // Everything not explicitly mentioned is not POD.
   default:
@@ -2829,6 +2834,10 @@ bool QualType::isTrivialType(const ASTContext &Context) 
const {
   if (CanonicalType->isDependentType())
     return false;
 
+  // Any type that is, or contains, address discriminated data is non-POD
+  if (CanonicalType.hasAddressDiscriminatedPointerAuth()) // 
Context.containsAddressDiscriminatedPointerAuth(CanonicalType))
+    return false;
+
   // C++0x [basic.types]p9:
   //   Scalar types, trivial class types, arrays of such types, and
   //   cv-qualified versions of these types are collectively called trivial
@@ -3179,6 +3188,10 @@ bool QualType::isCXX11PODType(const ASTContext &Context) 
const {
   if (BaseTy->isIncompleteType())
     return false;
 
+  // Any type that is, or contains, address discriminated data is non-POD
+  if (getCanonicalType().hasAddressDiscriminatedPointerAuth()) // 
Context.containsAddressDiscriminatedPointerAuth(*this))
+    return false;
+
   // As an extension, Clang treats vector types as Scalar types.
   if (BaseTy->isScalarType() || BaseTy->isVectorType())
     return true;
diff --git a/clang/test/SemaCXX/ptrauth-type-traits.cpp 
b/clang/test/SemaCXX/ptrauth-type-traits.cpp
new file mode 100644
index 0000000000000..602ac3790a557
--- /dev/null
+++ b/clang/test/SemaCXX/ptrauth-type-traits.cpp
@@ -0,0 +1,143 @@
+// RUN: %clang_cc1 -triple arm64               -std=c++26 
-Wno-deprecated-builtins \
+// RUN:                                        -fsyntax-only -verify %s 
+// RUN: %clang_cc1 -triple arm64-apple-darwin -fptrauth-calls 
-fptrauth-intrinsics \
+// RUN:                                       
-fptrauth-vtable-pointer-address-discrimination \
+// RUN:                                       -std=c++26 
-Wno-deprecated-builtins \
+// RUN:                                       -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+#ifdef __PTRAUTH__
+
+#define NonAddressDiscriminatedVTablePtrAttr \
+  [[clang::ptrauth_vtable_pointer(process_independent, 
no_address_discrimination, no_extra_discrimination)]]
+#define AddressDiscriminatedVTablePtrAttr \
+  [[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, 
no_extra_discrimination)]]
+#define ADDR_DISC_ENABLED true
+#else
+#define NonAddressDiscriminatedVTablePtrAttr
+#define AddressDiscriminatedVTablePtrAttr
+#define ADDR_DISC_ENABLED false
+#define __ptrauth(...)
+#endif
+
+
+typedef int* __ptrauth(1,1,1) AddressDiscriminatedPtr;
+typedef __UINT64_TYPE__ __ptrauth(1,1,1) AddressDiscriminatedInt64;
+struct AddressDiscriminatedFields {
+  AddressDiscriminatedPtr ptr;
+};
+struct RelocatableAddressDiscriminatedFields trivially_relocatable_if_eligible 
{
+  AddressDiscriminatedPtr ptr;
+};
+struct AddressDiscriminatedFieldInBaseClass : AddressDiscriminatedFields {
+  void *newfield;
+};
+
+struct NonAddressDiscriminatedVTablePtrAttr NonAddressDiscriminatedVTablePtr {
+  virtual ~NonAddressDiscriminatedVTablePtr();
+  void *i;
+};
+
+struct NonAddressDiscriminatedVTablePtrAttr NonAddressDiscriminatedVTablePtr2 {
+  virtual ~NonAddressDiscriminatedVTablePtr2();
+  void *j;
+};
+
+struct NonAddressDiscriminatedVTablePtrAttr 
RelocatableNonAddressDiscriminatedVTablePtr trivially_relocatable_if_eligible {
+  virtual ~RelocatableNonAddressDiscriminatedVTablePtr();
+  void *i;
+};
+
+struct NonAddressDiscriminatedVTablePtrAttr 
RelocatableNonAddressDiscriminatedVTablePtr2 trivially_relocatable_if_eligible {
+  virtual ~RelocatableNonAddressDiscriminatedVTablePtr2();
+  void *j;
+};
+
+struct AddressDiscriminatedVTablePtrAttr AddressDiscriminatedVTablePtr {
+  virtual ~AddressDiscriminatedVTablePtr();
+  void *k;
+};
+
+struct AddressDiscriminatedVTablePtrAttr 
RelocatableAddressDiscriminatedVTablePtr trivially_relocatable_if_eligible {
+  virtual ~RelocatableAddressDiscriminatedVTablePtr();
+  void *k;
+};
+
+struct NoAddressDiscriminatedBaseClasses : NonAddressDiscriminatedVTablePtr,
+                                           NonAddressDiscriminatedVTablePtr2 {
+  void *l;
+};
+
+struct RelocatableNoAddressDiscriminatedBaseClasses 
trivially_relocatable_if_eligible :
+                                           NonAddressDiscriminatedVTablePtr,
+                                           NonAddressDiscriminatedVTablePtr2 {
+  void *l;
+};
+
+struct AddressDiscriminatedPrimaryBase : AddressDiscriminatedVTablePtr,
+                                         NonAddressDiscriminatedVTablePtr {
+  void *l;
+};
+struct AddressDiscriminatedSecondaryBase : NonAddressDiscriminatedVTablePtr,
+                                           AddressDiscriminatedVTablePtr {
+  void *l;
+};
+
+struct RelocatableAddressDiscriminatedPrimaryBase : 
RelocatableAddressDiscriminatedVTablePtr,
+                                         
RelocatableNonAddressDiscriminatedVTablePtr {
+  void *l;
+};
+struct RelocatableAddressDiscriminatedSecondaryBase : 
RelocatableNonAddressDiscriminatedVTablePtr,
+                                           
RelocatableAddressDiscriminatedVTablePtr {
+  void *l;
+};
+struct EmbdeddedAddressDiscriminatedPolymorphicClass {
+  AddressDiscriminatedVTablePtr field;
+};
+struct RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass 
trivially_relocatable_if_eligible {
+  AddressDiscriminatedVTablePtr field;
+};
+
+#define ASSERT_BUILTIN_EQUALS(Expression, Predicate, Info) \
+  static_assert((Expression) == (([](bool Polymorphic, bool AddrDisc, bool 
Relocatable, bool HasNonstandardLayout){ return (Predicate); })Info), 
#Expression);
+  //, #Expression " did not match " #Predicate);
+
+
+#define TEST_BUILTINS(Builtin, Predicate) \
+  ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedPtr), Predicate, (false, 
ADDR_DISC_ENABLED, true, false)) \
+  ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedInt64), Predicate, (false, 
ADDR_DISC_ENABLED, true, false))\
+  ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedFields), Predicate, 
(false, ADDR_DISC_ENABLED, true, false))\
+  ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedFields), 
Predicate, (false, ADDR_DISC_ENABLED, true, false))\
+  ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedFieldInBaseClass), 
Predicate, (false, ADDR_DISC_ENABLED, true, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(NonAddressDiscriminatedVTablePtr), Predicate, 
(true, false, false, false))\
+  ASSERT_BUILTIN_EQUALS(Builtin(NonAddressDiscriminatedVTablePtr2), Predicate, 
(true, false, false, false))\
+  ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNonAddressDiscriminatedVTablePtr), 
Predicate, (true, false, true, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNonAddressDiscriminatedVTablePtr2), 
Predicate, (true, false, true, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedVTablePtr), Predicate, 
(true, ADDR_DISC_ENABLED, false, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedVTablePtr), 
Predicate, (true, ADDR_DISC_ENABLED, true, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(NoAddressDiscriminatedBaseClasses), Predicate, 
(true, false, false, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNoAddressDiscriminatedBaseClasses), 
Predicate, (true, false, false, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedPrimaryBase), Predicate, 
(true, ADDR_DISC_ENABLED, false, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedSecondaryBase), Predicate, 
(true, ADDR_DISC_ENABLED, false, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedPrimaryBase), 
Predicate, (true, ADDR_DISC_ENABLED, true, true))\
+  ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedSecondaryBase), 
Predicate, (true, ADDR_DISC_ENABLED, true, true))\
+  
ASSERT_BUILTIN_EQUALS(Builtin(EmbdeddedAddressDiscriminatedPolymorphicClass), 
Predicate, (true, ADDR_DISC_ENABLED, false, true))\
+  
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass),
 Predicate, (true, ADDR_DISC_ENABLED, false, true))
+
+TEST_BUILTINS(__is_pod, !(Polymorphic || AddrDisc || HasNonstandardLayout))
+TEST_BUILTINS(__is_standard_layout, !(Polymorphic || HasNonstandardLayout))
+TEST_BUILTINS(__has_trivial_move_constructor, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__has_trivial_copy, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__has_trivial_assign, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__has_trivial_move_assign, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__is_trivial, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__is_trivially_copyable, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__is_trivially_copyable, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__is_trivially_relocatable, !((Polymorphic) || AddrDisc))
+TEST_BUILTINS(__builtin_is_cpp_trivially_relocatable, !((Polymorphic && 
!Relocatable) || AddrDisc))
+TEST_BUILTINS(__builtin_is_replaceable, !(Polymorphic || AddrDisc))
+TEST_BUILTINS(__is_bitwise_cloneable, !AddrDisc);
+
+#define ASSIGNABLE_WRAPPER(Type) __is_trivially_assignable(Type&, Type)
+TEST_BUILTINS(ASSIGNABLE_WRAPPER, !(Polymorphic || AddrDisc))

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

Reply via email to