https://github.com/ojhunt updated 
https://github.com/llvm/llvm-project/pull/137580

>From 07b6275740646c6ac0ffd95518e7e9fa8f1e8717 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Sun, 27 Apr 2025 22:33:44 -0700
Subject: [PATCH 1/2] [clang] Add support for __ptrauth being applied to
 integer types

This adds support for the __ptrauth qualifier to be applied to
pointer sized integer types.
---
 clang/docs/PointerAuthentication.rst          |  11 +-
 clang/include/clang/AST/Type.h                |  12 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  10 +-
 clang/lib/AST/ASTContext.cpp                  |   3 +
 clang/lib/AST/Type.cpp                        |   6 +
 clang/lib/CodeGen/CGExprConstant.cpp          |   4 +
 clang/lib/CodeGen/CGExprScalar.cpp            |   2 +-
 clang/lib/CodeGen/CGPointerAuth.cpp           |  17 +-
 clang/lib/Sema/SemaDeclCXX.cpp                |   2 +-
 clang/lib/Sema/SemaType.cpp                   |  10 +-
 clang/lib/Sema/TreeTransform.h                |  12 +-
 .../ptrauth-restricted-intptr-qualifier.c     | 219 ++++++++++++++++++
 clang/test/Sema/ptrauth-qualifier.c           |   6 +-
 clang/test/SemaCXX/ptrauth-triviality.cpp     |  48 ++++
 14 files changed, 329 insertions(+), 33 deletions(-)
 create mode 100644 clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c

diff --git a/clang/docs/PointerAuthentication.rst 
b/clang/docs/PointerAuthentication.rst
index 41818d43ac687..b9341a9c3b6a8 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -284,13 +284,14 @@ __ptrauth Qualifier
 ^^^^^^^^^^^^^^^^^^^
 
 ``__ptrauth(key, address, discriminator)`` is an extended type
-qualifier which causes so-qualified objects to hold pointers signed using the
-specified schema rather than the default schema for such types.
+qualifier which causes so-qualified objects to hold pointers or pointer sized
+integers signed using the specified schema rather than the default schema for
+such types.
 
 In the current implementation in Clang, the qualified type must be a C pointer
-type, either to a function or to an object.  It currently cannot be an
-Objective-C pointer type, a C++ reference type, or a block pointer type; these
-restrictions may be lifted in the future.
+type, either to a function or to an object, or a pointer sized integer.  It
+currently cannot be an Objective-C pointer type, a C++ reference type, or a
+block pointer type; these restrictions may be lifted in the future.
 
 The qualifier's operands are as follows:
 
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 773796a55eaa1..435a9de68f774 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2560,7 +2560,9 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
   bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
   bool isPointerType() const;
   bool isPointerOrReferenceType() const;
-  bool isSignableType() const;
+  bool isSignableType(const ASTContext &Ctx) const;
+  bool isSignablePointerType() const;
+  bool isSignableIntegerType(const ASTContext &Ctx) const;
   bool isAnyPointerType() const;   // Any C pointer or ObjC object pointer
   bool isCountAttributedType() const;
   bool isBlockPointerType() const;
@@ -8222,7 +8224,13 @@ inline bool Type::isAnyPointerType() const {
   return isPointerType() || isObjCObjectPointerType();
 }
 
-inline bool Type::isSignableType() const { return isPointerType(); }
+inline bool Type::isSignableType(const ASTContext &Ctx) const {
+  return isSignablePointerType() || isSignableIntegerType(Ctx);
+}
+
+inline bool Type::isSignablePointerType() const {
+  return isPointerType() || isObjCClassType() || isObjCQualifiedClassType();
+}
 
 inline bool Type::isBlockPointerType() const {
   return isa<BlockPointerType>(CanonicalType);
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e1b9ed0647bb9..034ef4ff57187 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1031,10 +1031,12 @@ def err_ptrauth_qualifier_invalid : Error<
   "%select{return type|parameter type|property}1 may not be qualified with 
'__ptrauth'; type is %0">;
 def err_ptrauth_qualifier_cast : Error<
   "cannot cast to '__ptrauth'-qualified type %0">;
-def err_ptrauth_qualifier_nonpointer : Error<
-  "'__ptrauth' qualifier only applies to pointer types; %0 is invalid">;
-def err_ptrauth_qualifier_redundant : Error<
-  "type %0 is already %1-qualified">;
+def err_ptrauth_qualifier_invalid_target
+    : Error<"'__ptrauth' qualifier only applies to pointer or pointer sized "
+            "integer"
+            " types; %0 is invalid">;
+def err_ptrauth_qualifier_redundant
+    : Error<"type %0 is already __ptrauth-qualified">;
 def err_ptrauth_arg_not_ice : Error<
   "argument to '__ptrauth' must be an integer constant expression">;
 def err_ptrauth_address_discrimination_invalid : Error<
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 1ed16748dff1a..93c77638e5310 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2943,6 +2943,9 @@ bool ASTContext::hasUniqueObjectRepresentations(
 
   // All integrals and enums are unique.
   if (Ty->isIntegralOrEnumerationType()) {
+    // Address discriminated integer types are not unique.
+    if (Ty.hasAddressDiscriminatedPointerAuth())
+      return false;
     // Except _BitInt types that have padding bits.
     if (const auto *BIT = Ty->getAs<BitIntType>())
       return getTypeSize(BIT) == BIT->getNumBits();
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 31e4bcd7535ea..0776d228a07ec 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5062,6 +5062,12 @@ AttributedType::stripOuterNullability(QualType &T) {
   return std::nullopt;
 }
 
+bool Type::isSignableIntegerType(const ASTContext &Ctx) const {
+  if (!isIntegralType(Ctx) || isEnumeralType())
+    return false;
+  return Ctx.getTypeSize(this) == Ctx.getTypeSize(Ctx.VoidPtrTy);
+}
+
 bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const {
   const auto *objcPtr = getAs<ObjCObjectPointerType>();
   if (!objcPtr)
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp 
b/clang/lib/CodeGen/CGExprConstant.cpp
index b21ebeee4bed1..ebe6bb80504b5 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2444,6 +2444,10 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, 
QualType DestType,
                                  EnablePtrAuthFunctionTypeDiscrimination)
         .tryEmit();
   case APValue::Int:
+    if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth();
+        PointerAuth &&
+        (PointerAuth.authenticatesNullValues() || Value.getInt() != 0))
+      return nullptr;
     return llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getInt());
   case APValue::FixedPoint:
     return llvm::ConstantInt::get(CGM.getLLVMContext(),
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index f639a87e3ad0b..b15e4d64744ae 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2300,7 +2300,7 @@ static bool isLValueKnownNonNull(CodeGenFunction &CGF, 
const Expr *E) {
 }
 
 bool CodeGenFunction::isPointerKnownNonNull(const Expr *E) {
-  assert(E->getType()->isSignableType());
+  assert(E->getType()->isSignableType(getContext()));
 
   E = E->IgnoreParens();
 
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp 
b/clang/lib/CodeGen/CGPointerAuth.cpp
index 474848c8324f3..bf22912988d38 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -175,7 +175,7 @@ CGPointerAuthInfo 
CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {
 /// pointer type.
 static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,
                                                    QualType PointerType) {
-  assert(PointerType->isSignableType());
+  assert(PointerType->isSignableType(CGM.getContext()));
 
   // Block pointers are currently not signed.
   if (PointerType->isBlockPointerType())
@@ -209,7 +209,7 @@ emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const 
LValue &LV,
 /// needlessly resigning the pointer.
 std::pair<llvm::Value *, CGPointerAuthInfo>
 CodeGenFunction::EmitOrigPointerRValue(const Expr *E) {
-  assert(E->getType()->isSignableType());
+  assert(E->getType()->isSignableType(getContext()));
 
   E = E->IgnoreParens();
   if (const auto *Load = dyn_cast<ImplicitCastExpr>(E)) {
@@ -291,7 +291,10 @@ static bool equalAuthPolicies(const CGPointerAuthInfo 
&Left,
   if (Left.isSigned() != Right.isSigned())
     return false;
   return Left.getKey() == Right.getKey() &&
-         Left.getAuthenticationMode() == Right.getAuthenticationMode();
+         Left.getAuthenticationMode() == Right.getAuthenticationMode() &&
+         Left.isIsaPointer() == Right.isIsaPointer() &&
+         Left.authenticatesNullValues() == Right.authenticatesNullValues() &&
+         Left.getDiscriminator() == Right.getDiscriminator();
 }
 
 // Return the discriminator or return zero if the discriminator is null.
@@ -642,10 +645,10 @@ llvm::Value 
*CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,
                                                        QualType SourceType,
                                                        QualType DestType) {
   CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
-  if (SourceType->isSignableType())
+  if (SourceType->isSignableType(getContext()))
     CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
 
-  if (DestType->isSignableType())
+  if (DestType->isSignableType(getContext()))
     NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
 
   if (!CurAuthInfo && !NewAuthInfo)
@@ -667,10 +670,10 @@ Address CodeGenFunction::authPointerToPointerCast(Address 
Ptr,
                                                   QualType SourceType,
                                                   QualType DestType) {
   CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
-  if (SourceType->isSignableType())
+  if (SourceType->isSignableType(getContext()))
     CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
 
-  if (DestType->isSignableType())
+  if (DestType->isSignableType(getContext()))
     NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
 
   if (!CurAuthInfo && !NewAuthInfo)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 7cce7ed1fa054..cbccb567e2adf 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -10888,7 +10888,7 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl 
&RD) {
       return;
     }
 
-    // Ill-formed if the field is an address-discriminated pointer.
+    // Ill-formed if the field is an address-discriminated value.
     if (FT.hasAddressDiscriminatedPointerAuth()) {
       PrintDiagAndRemoveAttr(6);
       return;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 294daef70c339..a8e85c885069e 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8379,15 +8379,14 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, 
QualType &T,
     return;
   }
 
-  if (!T->isSignableType() && !T->isDependentType()) {
-    S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T;
+  if (!T->isSignableType(Ctx) && !T->isDependentType()) {
+    S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_invalid_target) << T;
     Attr.setInvalid();
     return;
   }
 
   if (T.getPointerAuth()) {
-    S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant)
-        << T << Attr.getAttrName()->getName();
+    S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) << T;
     Attr.setInvalid();
     return;
   }
@@ -8402,7 +8401,8 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, 
QualType &T,
          "address discriminator arg should be either 0 or 1");
   PointerAuthQualifier Qual = PointerAuthQualifier::Create(
       Key, IsAddressDiscriminated, ExtraDiscriminator,
-      PointerAuthenticationMode::SignAndAuth, false, false);
+      PointerAuthenticationMode::SignAndAuth, /*IsIsaPointer=*/false,
+      /*AuthenticatesNullValues=*/false);
   T = S.Context.getPointerAuthType(T, Qual);
 }
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 8b4b79c6ec039..97d62d15a2c25 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5305,13 +5305,15 @@ QualType 
TreeTransform<Derived>::RebuildQualifiedType(QualType T,
   PointerAuthQualifier LocalPointerAuth = Quals.getPointerAuth();
   if (LocalPointerAuth.isPresent()) {
     if (T.getPointerAuth().isPresent()) {
-      SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_redundant)
-          << TL.getType() << "__ptrauth";
-      return QualType();
-    } else if (!T->isSignableType() && !T->isDependentType()) {
-      SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_nonpointer) << T;
+      SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_redundant) << TL.getType();
       return QualType();
     }
+    if (!T->isDependentType()) {
+      if (!T->isSignableType(SemaRef.getASTContext())) {
+        SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_invalid_target) << T;
+        return QualType();
+      }
+    }
   }
   // C++ [dcl.fct]p7:
   //   [When] adding cv-qualifications on top of the function type [...] the
diff --git a/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c 
b/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c
new file mode 100644
index 0000000000000..dcce5764e2217
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c
@@ -0,0 +1,219 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm %s -O0 -o - | FileCheck %s
+
+#define __ptrauth(...) __ptrauth(__VA_ARGS__)
+
+__INTPTR_TYPE__ __ptrauth(1, 0, 56) g1 = 0;
+// CHECK: @g1 = global i64 0
+__INTPTR_TYPE__ __ptrauth(1, 1, 1272) g2 = 0;
+// CHECK: @g2 = global i64 0
+extern __UINTPTR_TYPE__ test_int;
+__UINTPTR_TYPE__ __ptrauth(3, 1, 23) g3 = (__UINTPTR_TYPE__)&test_int;
+// CHECK: @test_int = external global i64
+// CHECK: @g3 = global i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 3, i64 
23, ptr @g3) to i64)
+
+__INTPTR_TYPE__ __ptrauth(1, 1, 712) ga[3] = {0,0,(__UINTPTR_TYPE__)&test_int};
+
+// CHECK: @ga = global [3 x i64] [i64 0, i64 0, i64 ptrtoint (ptr ptrauth (ptr 
@test_int, i32 1, i64 712, ptr getelementptr inbounds ([3 x i64], ptr @ga, i32 
0, i32 2)) to i64)]
+
+struct A {
+  __INTPTR_TYPE__ __ptrauth(1, 0, 431) f0;
+  __INTPTR_TYPE__ __ptrauth(1, 0, 9182) f1;
+  __INTPTR_TYPE__ __ptrauth(1, 0, 783) f2;
+};
+
+struct A gs1 = {0, 0, (__UINTPTR_TYPE__)&test_int};
+// CHECK: @gs1 = global %struct.A { i64 0, i64 0, i64 ptrtoint (ptr ptrauth 
(ptr @test_int, i32 1, i64 783) to i64) }
+
+struct B {
+  __INTPTR_TYPE__ __ptrauth(1, 1, 1276) f0;
+  __INTPTR_TYPE__ __ptrauth(1, 1, 23674) f1;
+  __INTPTR_TYPE__ __ptrauth(1, 1, 163) f2;
+};
+
+struct B gs2 = {0, 0, (__UINTPTR_TYPE__)&test_int};
+// CHECK: @gs2 = global %struct.B { i64 0, i64 0, i64 ptrtoint (ptr ptrauth 
(ptr @test_int, i32 1, i64 163, ptr getelementptr inbounds (%struct.B, ptr 
@gs2, i32 0, i32 2)) to i64) }
+
+// CHECK-LABEL: i64 @test_read_globals
+__INTPTR_TYPE__ test_read_globals() {
+  __INTPTR_TYPE__ result = g1 + g2 + g3;
+  // CHECK: [[A:%.*]] = load i64, ptr @g1
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[A]], i32 1, i64 
56)
+  // CHECK: [[B:%.*]] = load i64, ptr @g2
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr 
@g2 to i64), i64 1272)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[B]], i32 1, i64 
[[BLENDED]])
+  // CHECK: [[VALUE:%.*]] = load i64, ptr @g3
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr 
@g3 to i64), i64 23)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 3, 
i64 [[BLENDED]])
+
+  for (int i = 0; i < 3; i++) {
+    result += ga[i];
+  }
+  // CHECK: for.cond:
+  // CHECK: [[TEMP:%.*]] = load i32, ptr [[IDX_ADDR:%.*]]
+
+  // CHECK: for.body:
+  // CHECK: [[IDX:%.*]] = load i32, ptr [[IDX_ADDR]]
+  // CHECK: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
+  // CHECK: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x i64], ptr @ga, i64 
0, i64 [[IDXPROM]]
+  // CHECK: [[VALUE:%.*]] = load i64, ptr [[ARRAYIDX]]
+  // CHECK: [[CASTIDX:%.*]] = ptrtoint ptr [[ARRAYIDX]] to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTIDX]], 
i64 712)
+  // CHECK: resign.nonnull6:
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLENDED]])
+  // CHECK: resign.cont7
+
+  result += gs1.f0 + gs1.f1 + gs1.f2;
+  // CHECK: resign.cont10:
+  // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw 
(%struct.A, ptr @gs1, i32 0, i32 1
+  // CHECK: resign.nonnull11:
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, 
i64 9182)
+  // CHECK: resign.cont12:
+  // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw 
(%struct.A, ptr @gs1, i32 0, i32 2)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, 
i64 783)
+  result += gs2.f0 + gs2.f1 + gs2.f2;
+  // CHECK: [[ADDR:%.*]] = load i64, ptr @gs2
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr 
@gs2 to i64), i64 1276)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, 
i64 [[BLENDED]])
+  // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw 
(%struct.B, ptr @gs2, i32 0, i32 1)
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr 
getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 1) to i64), i64 
23674)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, 
i64 [[BLENDED]])
+  // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw 
(%struct.B, ptr @gs2, i32 0, i32 2)
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr 
getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 2) to i64), i64 163)
+
+  return result;
+}
+
+// CHECK-LABEL: void @test_write_globals
+void test_write_globals(int i, __INTPTR_TYPE__ j) {
+  g1 = i;
+  g2 = j;
+  g3 = 0;
+  ga[0] = i;
+  ga[1] = j;
+  ga[2] = 0;
+  gs1.f0 = i;
+  gs1.f1 = j;
+  gs1.f2 = 0;
+  gs2.f0 = i;
+  gs2.f1 = j;
+  gs2.f2 = 0;
+}
+
+// CHECK-LABEL: define void @test_set_A
+void test_set_A(struct A *a, __INTPTR_TYPE__ x, int y) {
+  a->f0 = x;
+  // CHECK: [[XADDR:%.*]] = load i64, ptr %x.addr
+  // CHECK: [[SIGNED_X:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[XADDR]], i32 
1, i64 431)
+  a->f1 = y;
+  // CHECK: [[Y:%.*]] = load i32, ptr %y.addr
+  // CHECK: [[CONV:%.*]] = sext i32 [[Y]] to i64
+  // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CONV]], i32 1, 
i64 9182)
+  a->f2 = 0;
+  // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+  // CHECK: [[F2:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 
0, i32 2
+  // CHECK: store i64 0, ptr [[F2]]
+}
+
+// CHECK-LABEL: define void @test_set_B
+void test_set_B(struct B *b, __INTPTR_TYPE__ x, int y) {
+  b->f0 = x;
+  // CHECK: [[X:%.*]] = load i64, ptr %x.addr
+  // CHECK: [[F0_ADDR:%.*]] = ptrtoint ptr %f0 to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[F0_ADDR]], 
i64 1276)
+  // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[X]], i32 1, i64 
[[BLENDED]])
+  b->f1 = y;
+  // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+  // CHECK: [[F1_ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], 
i32 0, i32 1
+  // CHECK: [[Y:%.*]] = load i32, ptr %y.addr, align 4
+  // CHECK: [[CONV:%.*]] = sext i32 [[Y]] to i64
+  // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[F1_ADDR]] to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], 
i64 23674)
+  // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CONV]], i32 1, 
i64 [[BLENDED]])
+  b->f2 = 0;
+  // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+  // CHECK: [[F2_ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], 
i32 0, i32 2
+  // CHECK: store i64 0, ptr [[F2_ADDR]]
+}
+
+// CHECK-LABEL: define i64 @test_get_A
+__INTPTR_TYPE__ test_get_A(struct A *a) {
+  return a->f0 + a->f1 + a->f2;
+  // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+  // CHECK: [[F0_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], 
i32 0, i32 0
+  // CHECK: [[F0:%.*]] = load i64, ptr [[F0_ADDR]]
+  // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F0]], i32 1, i64 
431)
+  // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+  // CHECK: [[F1_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], 
i32 0, i32 1
+  // CHECK: [[F1:%.*]] = load i64, ptr [[F1_ADDR]]
+  // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F1]], i32 1, i64 
9182)
+  // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+  // CHECK: [[F2_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], 
i32 0, i32 2
+  // CHECK: [[F2:%.*]] = load i64, ptr [[F2_ADDR]]
+  // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F2]], i32 1, i64 
783)
+}
+
+// CHECK-LABEL: define i64 @test_get_B
+__INTPTR_TYPE__ test_get_B(struct B *b) {
+  return b->f0 + b->f1 + b->f2;
+  // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+  // CHECK: [[F0:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 
0, i32 0
+  // CHECK: [[VALUE:%.*]] = load i64, ptr [[F0]]
+  // CHECK: [[CASTF0:%.*]] = ptrtoint ptr %f0 to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTF0]], i64 
1276)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLENDED]])
+  // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+  // CHECK: [[ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], 
i32 0, i32 1
+  // CHECK: [[VALUE:%.*]] = load i64, ptr [[ADDR]]
+  // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], 
i64 23674)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLENDED]])
+  // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+  // CHECK: [[ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], 
i32 0, i32 2
+  // CHECK: [[VALUE:%.*]] = load i64, ptr [[ADDR]]
+  // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], 
i64 163)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLENDED]])
+}
+
+// CHECK-LABEL: define void @test_resign
+void test_resign(struct A* a, const struct B *b) {
+  a->f0 = b->f0;
+  // CHECK: [[A:%.*]] = load ptr, ptr %a.addr, align 8
+  // CHECK: [[F0:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 
0, i32 0
+  // CHECK: [[B:%.*]] = load ptr, ptr %b.addr, align 8
+  // CHECK: [[F01:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 
0, i32 0
+  // CHECK: [[F01VALUE:%.*]] = load i64, ptr [[F01]]
+  // CHECK: [[CASTF01:%.*]] = ptrtoint ptr %f01 to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTF01]], 
i64 1276)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[F01VALUE]], 
i32 1, i64 [[BLENDED]], i32 1, i64 431)
+}
+
+// CHECK-LABEL: define i64 @other_test
+__INTPTR_TYPE__ other_test(__INTPTR_TYPE__ i) {
+  __INTPTR_TYPE__ __ptrauth(1, 1, 42) j = 0;
+  // CHECK: [[J_ADDR:%.*]] = ptrtoint ptr %j to i64
+  // CHECK: store i64 0, ptr %j
+  __INTPTR_TYPE__ __ptrauth(1, 1, 43) k = 1234;
+  // CHECK: [[ADDR:%.*]] = ptrtoint ptr %k to i64
+  // CHECK: [[JBLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 
43)
+  // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 1234, i32 1, i64 
[[JBLENDED]])
+  __INTPTR_TYPE__ __ptrauth(1, 1, 44) l = i;
+  // CHECK: [[I:%.*]] = load i64, ptr %i.addr
+  // CHECK: [[ADDR:%.*]] = ptrtoint ptr %l to i64
+  // CHECK: [[LBLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 
44)
+  // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[I]], i32 1, i64 
[[LBLENDED]])
+  asm volatile ("" ::: "memory");
+  return j + k + l;
+  // CHECK: [[VALUE:%.*]] = load i64, ptr %j
+  // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr %j to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], 
i64 42)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLENDED]])
+  // CHECK: [[VALUE:%.*]] = load i64, ptr %k
+  // CHECK: [[CASTK:%.*]] = ptrtoint ptr %k to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTK]], i64 
43)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLENDED]])
+  // CHECK: [[VALUE:%.*]] = load i64, ptr %l
+  // CHECK: [[CASTL:%.*]] = ptrtoint ptr %l to i64
+  // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTL]], i64 
44)
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLENDED]])
+}
diff --git a/clang/test/Sema/ptrauth-qualifier.c 
b/clang/test/Sema/ptrauth-qualifier.c
index 2ec4471e519ca..a45c52957d770 100644
--- a/clang/test/Sema/ptrauth-qualifier.c
+++ b/clang/test/Sema/ptrauth-qualifier.c
@@ -24,8 +24,8 @@ typedef int *intp;
 int nonConstantGlobal = 5;
 
 __ptrauth(INVALID_KEY) int invalid2; // expected-error{{200 does not identify 
a valid pointer authentication key for the current target}}
-__ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' 
qualifier only applies to pointer types; 'int' is invalid}}
-__ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' 
qualifier only applies to pointer types; 'int' is invalid}}
+__ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' 
qualifier only applies to pointer or pointer sized integer types; 'int' is 
invalid}}
+__ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' 
qualifier only applies to pointer or pointer sized integer types; 'int' is 
invalid}}
 int * (__ptrauth(VALID_DATA_KEY) invalid5); // expected-error{{expected 
identifier or '('}} expected-error{{expected ')'}} expected-note {{to match 
this '('}}
 int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // 
expected-error{{type 'int *__ptrauth(2,0,0)' is already __ptrauth-qualified}}
 int * __ptrauth(VALID_DATA_KEY, 2) invalid7; // expected-error {{invalid 
address discrimination flag '2'; '__ptrauth' requires '0' or '1'}}
@@ -102,7 +102,7 @@ __attribute__((overloadable)) float overload_func(int * 
__ptrauth(VALID_DATA_KEY
 static_assert(_Generic(typeof(overload_func(&ptr0)), int : 1, default : 0));
 static_assert(_Generic(typeof(overload_func(&valid0)), float : 1, default : 
0));
 
-void func(int array[__ptrauth(VALID_DATA_KEY) 10]); // expected-error 
{{'__ptrauth' qualifier only applies to pointer types; 'int[10]' is invalid}}
+void func(int array[__ptrauth(VALID_DATA_KEY) 10]); // expected-error 
{{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 
'int[10]' is invalid}}
 
 struct S0 { // expected-note 4 {{struct S0' has subobjects that are 
non-trivial to copy}}
   intp __ptrauth(1, 1, 50) f0; // expected-note 4 {{f0 has type 
'__ptrauth(1,1,50) intp' (aka 'int *__ptrauth(1,1,50)') that is non-trivial to 
copy}}
diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp 
b/clang/test/SemaCXX/ptrauth-triviality.cpp
index 785e83aaaa545..60d1b57230f18 100644
--- a/clang/test/SemaCXX/ptrauth-triviality.cpp
+++ b/clang/test/SemaCXX/ptrauth-triviality.cpp
@@ -3,6 +3,8 @@
 
 #define AQ __ptrauth(1,1,50)
 #define IQ __ptrauth(1,0,50)
+#define AQ_IP __ptrauth(1,1,50)
+#define IQ_IP __ptrauth(1,0,50)
 #define AA 
[[clang::ptrauth_vtable_pointer(process_independent,address_discrimination,no_extra_discrimination)]]
 #define IA 
[[clang::ptrauth_vtable_pointer(process_independent,no_address_discrimination,type_discrimination)]]
 #define PA 
[[clang::ptrauth_vtable_pointer(process_dependent,no_address_discrimination,no_extra_discrimination)]]
@@ -134,3 +136,49 @@ static_assert(!__is_trivially_copyable(Holder<S5>));
 static_assert(__is_trivially_relocatable(Holder<S5>)); // 
expected-warning{{deprecated}}
 static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S5>));
 static_assert(!__is_trivially_equality_comparable(Holder<S5>));
+
+struct S6 {
+  __INTPTR_TYPE__ AQ_IP p_;
+  void *payload_;
+  bool operator==(const S6&) const = default;
+};
+static_assert(__is_trivially_constructible(S6));
+static_assert(!__is_trivially_constructible(S6, const S6&));
+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(!__is_trivially_equality_comparable(S6));
+
+static_assert(__is_trivially_constructible(Holder<S6>));
+static_assert(!__is_trivially_constructible(Holder<S6>, const Holder<S6>&));
+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(!__is_trivially_equality_comparable(Holder<S6>));
+
+struct S7 {
+  __INTPTR_TYPE__ IQ_IP p_;
+  void *payload_;
+  bool operator==(const S7&) const = default;
+};
+static_assert(__is_trivially_constructible(S7));
+static_assert(__is_trivially_constructible(S7, const S7&));
+static_assert(__is_trivially_assignable(S7&, const S7&));
+static_assert(__is_trivially_destructible(S7));
+static_assert(__is_trivially_copyable(S7));
+static_assert(__is_trivially_relocatable(S7)); // 
expected-warning{{deprecated}}
+static_assert(__builtin_is_cpp_trivially_relocatable(S7));
+static_assert(__is_trivially_equality_comparable(S7));
+
+static_assert(__is_trivially_constructible(Holder<S7>));
+static_assert(__is_trivially_constructible(Holder<S7>, const Holder<S7>&));
+static_assert(__is_trivially_assignable(Holder<S7>, const Holder<S7>&));
+static_assert(__is_trivially_destructible(Holder<S7>));
+static_assert(__is_trivially_copyable(Holder<S7>));
+static_assert(__is_trivially_relocatable(Holder<S7>)); // 
expected-warning{{deprecated}}
+static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S7>));
+static_assert(__is_trivially_equality_comparable(Holder<S7>));

>From 0879a5f2e98d4228310cbac9686c57ae3262b46c Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Fri, 9 May 2025 11:48:58 -0700
Subject: [PATCH 2/2] Address punctuation and layout of diagnostics

---
 .../include/clang/Basic/DiagnosticSemaKinds.td  | 17 +++++++++--------
 clang/test/Sema/ptrauth-qualifier.c             |  2 +-
 .../SemaCXX/ptrauth-template-parameters.cpp     |  2 +-
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 034ef4ff57187..89b2d664d66a0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1028,21 +1028,22 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : 
Error<
 
 // __ptrauth qualifier
 def err_ptrauth_qualifier_invalid : Error<
-  "%select{return type|parameter type|property}1 may not be qualified with 
'__ptrauth'; type is %0">;
+  "%select{return type|parameter type|property}1 may not be qualified with "
+  "'__ptrauth'; type is %0">;
 def err_ptrauth_qualifier_cast : Error<
   "cannot cast to '__ptrauth'-qualified type %0">;
-def err_ptrauth_qualifier_invalid_target
-    : Error<"'__ptrauth' qualifier only applies to pointer or pointer sized "
-            "integer"
-            " types; %0 is invalid">;
-def err_ptrauth_qualifier_redundant
-    : Error<"type %0 is already __ptrauth-qualified">;
+def err_ptrauth_qualifier_invalid_target : Error<
+  "'__ptrauth' qualifier only applies to pointer or pointer sized integer "
+  "types; %0 is invalid">;
+def err_ptrauth_qualifier_redundant: Error<
+  "type %0 is already '__ptrauth'-qualified">;
 def err_ptrauth_arg_not_ice : Error<
   "argument to '__ptrauth' must be an integer constant expression">;
 def err_ptrauth_address_discrimination_invalid : Error<
   "invalid address discrimination flag '%0'; '__ptrauth' requires '0' or '1'">;
 def err_ptrauth_extra_discriminator_invalid : Error<
-  "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between 
'0' and '%1'">;
+  "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between 
"
+  "'0' and '%1'">;
 
 /// main()
 // static main() is not an error in C, just in C++.
diff --git a/clang/test/Sema/ptrauth-qualifier.c 
b/clang/test/Sema/ptrauth-qualifier.c
index a45c52957d770..5d932b724f07a 100644
--- a/clang/test/Sema/ptrauth-qualifier.c
+++ b/clang/test/Sema/ptrauth-qualifier.c
@@ -27,7 +27,7 @@ __ptrauth(INVALID_KEY) int invalid2; // expected-error{{200 
does not identify a
 __ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' 
qualifier only applies to pointer or pointer sized integer types; 'int' is 
invalid}}
 __ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' 
qualifier only applies to pointer or pointer sized integer types; 'int' is 
invalid}}
 int * (__ptrauth(VALID_DATA_KEY) invalid5); // expected-error{{expected 
identifier or '('}} expected-error{{expected ')'}} expected-note {{to match 
this '('}}
-int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // 
expected-error{{type 'int *__ptrauth(2,0,0)' is already __ptrauth-qualified}}
+int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // 
expected-error{{type 'int *__ptrauth(2,0,0)' is already '__ptrauth'-qualified}}
 int * __ptrauth(VALID_DATA_KEY, 2) invalid7; // expected-error {{invalid 
address discrimination flag '2'; '__ptrauth' requires '0' or '1'}}
 int * __ptrauth(VALID_DATA_KEY, -1) invalid8; // expected-error {{invalid 
address discrimination flag '-1'; '__ptrauth' requires '0' or '1'}}
 int * __ptrauth(VALID_DATA_KEY, 1, -1) invalid9; // expected-error {{invalid 
extra discriminator flag '-1'; '__ptrauth' requires a value between '0' and 
'65535'}}
diff --git a/clang/test/SemaCXX/ptrauth-template-parameters.cpp 
b/clang/test/SemaCXX/ptrauth-template-parameters.cpp
index ee23d3f2ec456..99899ad11dbe5 100644
--- a/clang/test/SemaCXX/ptrauth-template-parameters.cpp
+++ b/clang/test/SemaCXX/ptrauth-template-parameters.cpp
@@ -3,7 +3,7 @@
 
 template <typename T> struct G {
   T __ptrauth(0,0,1234) test;
-  // expected-error@-1 2 {{type '__ptrauth(0,0,1234) T' is already 
__ptrauth-qualified}}
+  // expected-error@-1 2 {{type '__ptrauth(0,0,1234) T' is already 
'__ptrauth'-qualified}}
 };
 
 template <typename T> struct Indirect {

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

Reply via email to