[clang] [clang][PAC] Fix builtins that claim address discriminated types are bitwise compatible (PR #154490)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 20 01:33:57 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Oliver Hunt (ojhunt)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/154490.diff
5 Files Affected:
- (modified) clang/include/clang/AST/ASTContext.h (+6-6)
- (modified) clang/lib/AST/ASTContext.cpp (+3-3)
- (modified) clang/lib/AST/DeclCXX.cpp (+6)
- (modified) clang/lib/AST/Type.cpp (+13)
- (added) clang/test/SemaCXX/ptrauth-type-traits.cpp (+143)
``````````diff
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))
``````````
</details>
https://github.com/llvm/llvm-project/pull/154490
More information about the cfe-commits
mailing list