Author: Oliver Hunt
Date: 2025-05-09T13:12:09-07:00
New Revision: 65a6cbde5bb074ce377cb1aa6145241ad1719c17

URL: 
https://github.com/llvm/llvm-project/commit/65a6cbde5bb074ce377cb1aa6145241ad1719c17
DIFF: 
https://github.com/llvm/llvm-project/commit/65a6cbde5bb074ce377cb1aa6145241ad1719c17.diff

LOG: [clang] Add support for `__ptrauth` being applied to integer types 
(#137580)

Allows the __ptrauth qualifier to be applied to pointer sized integer types,
updates Sema to ensure trivially copyable, etc correctly handle address
discriminated integers, and updates codegen to perform authentication
around arithmetic on the types.

Added: 
    clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c

Modified: 
    clang/docs/PointerAuthentication.rst
    clang/include/clang/AST/Type.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/Type.cpp
    clang/lib/CodeGen/CGExprConstant.cpp
    clang/lib/CodeGen/CGExprScalar.cpp
    clang/lib/CodeGen/CGPointerAuth.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaType.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/Sema/ptrauth-qualifier.c
    clang/test/SemaCXX/ptrauth-template-parameters.cpp
    clang/test/SemaCXX/ptrauth-triviality.cpp

Removed: 
    


################################################################################
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 242d7b72bd5b8..180f3623983de 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;
@@ -8216,7 +8218,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..89b2d664d66a0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1028,19 +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_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<
   "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/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 0ace0a55afd7a..d3767be62473e 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 9b37f25e723f7..82a8cc99cd265 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5075,6 +5075,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 fe564aaf3e59c..6ba45f42db4d1 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 8efec8b07e55e..6765008c99c4a 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 0af897ad9a540..335e21d927b76 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..5d932b724f07a 100644
--- a/clang/test/Sema/ptrauth-qualifier.c
+++ b/clang/test/Sema/ptrauth-qualifier.c
@@ -24,10 +24,10 @@ 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) __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'}}
@@ -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-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 {

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>));


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

Reply via email to