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

__ptrauth_restricted_intptr provides a mechanism to apply pointer 
authentication to pointer sized integer types.

>From 7af378bbec4c7cf3896f6f7bc95d816e398930f2 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Sun, 27 Apr 2025 22:33:44 -0700
Subject: [PATCH] [clang] Add `__ptrauth_restricted_intptr` qualifier

__ptrauth_restricted_intptr provides a mechanism to apply pointer
authentication to pointer sized integer types.
---
 clang/docs/PointerAuthentication.rst          |  14 ++
 clang/docs/ReleaseNotes.rst                   |   2 +-
 clang/include/clang/AST/Type.h                |  52 +++--
 clang/include/clang/Basic/Attr.td             |   3 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  31 ++-
 clang/include/clang/Basic/Features.def        |   1 +
 clang/include/clang/Basic/TokenKinds.def      |   1 +
 clang/include/clang/Sema/Sema.h               |   3 +-
 clang/lib/AST/ASTContext.cpp                  |   3 +
 clang/lib/AST/Type.cpp                        |   6 +
 clang/lib/AST/TypePrinter.cpp                 |   5 +-
 clang/lib/CodeGen/CGExprConstant.cpp          |   3 +
 clang/lib/CodeGen/CGExprScalar.cpp            |   2 +-
 clang/lib/CodeGen/CGPointerAuth.cpp           |  22 +-
 clang/lib/Parse/ParseDecl.cpp                 |   9 +-
 clang/lib/Sema/SemaCast.cpp                   |   2 +-
 clang/lib/Sema/SemaChecking.cpp               |  11 +-
 clang/lib/Sema/SemaDecl.cpp                   |   3 +-
 clang/lib/Sema/SemaDeclCXX.cpp                |   2 +-
 clang/lib/Sema/SemaObjCProperty.cpp           |   6 +-
 clang/lib/Sema/SemaType.cpp                   |  43 ++--
 clang/lib/Sema/TreeTransform.h                |  21 +-
 .../ptrauth-restricted-intptr-qualifier.c     | 220 ++++++++++++++++++
 .../ptrauth-restricted-intptr-qualifier.c     |  45 ++++
 clang/test/SemaCXX/ptrauth-triviality.cpp     |  44 ++++
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |   7 +-
 26 files changed, 487 insertions(+), 74 deletions(-)
 create mode 100644 clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c
 create mode 100644 clang/test/Sema/ptrauth-restricted-intptr-qualifier.c

diff --git a/clang/docs/PointerAuthentication.rst 
b/clang/docs/PointerAuthentication.rst
index 41818d43ac687..2278971d757c9 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -326,6 +326,20 @@ a discriminator determined as follows:
   is ``ptrauth_blend_discriminator(&x, discriminator)``; see
   `ptrauth_blend_discriminator`_.
 
+__ptrauth_restricted_intptr qualifier
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This is a variant of the ``__ptrauth`` qualifier, that applies to pointer sized
+integers. See the documentation for ``__ptrauth qualifier``.
+
+This feature exists to support older APIs that use [u]intptrs to hold opaque
+pointer types.
+
+Care must be taken to avoid using the signature bit components of the signed
+integers or subsequent authentication of the signed value may fail.
+
+Note: When applied to a global initialiser a signed uintptr can only be
+initialised with the value 0 or a global address.
+
 ``<ptrauth.h>``
 ~~~~~~~~~~~~~~~
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index eb2e8f2b8a6c0..fe9badf7ba97a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -608,7 +608,7 @@ Arm and AArch64 Support
   ARM targets, however this will now disable NEON instructions being 
generated. The ``simd`` option is
   also now printed when the ``--print-supported-extensions`` option is used.
 
--  Support for __ptrauth type qualifier has been added.
+-  Support for __ptrauth and __ptrauth_restricted_intptr type qualifiers has 
been added.
 
 - For AArch64, added support for generating executable-only code sections by 
using the
   ``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 3e1fb05ad537c..6516c976e66c5 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -168,8 +168,13 @@ class PointerAuthQualifier {
     AuthenticatesNullValuesBits = 1,
     AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1)
                                   << AuthenticatesNullValuesShift,
-    KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
-    KeyBits = 10,
+    RestrictedIntegralShift =
+       AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
+    RestrictedIntegralBits = 1,
+    RestrictedIntegralMask = ((1 << RestrictedIntegralBits) - 1)
+                             << RestrictedIntegralShift,
+    KeyShift = RestrictedIntegralShift + RestrictedIntegralBits,
+    KeyBits = 9,
     KeyMask = ((1 << KeyBits) - 1) << KeyShift,
     DiscriminatorShift = KeyShift + KeyBits,
     DiscriminatorBits = 16,
@@ -178,32 +183,33 @@ class PointerAuthQualifier {
 
   // bits:     |0      |1      |2..3              |4          |
   //           |Enabled|Address|AuthenticationMode|ISA pointer|
-  // bits:     |5                |6..15|   16...31   |
-  //           |AuthenticatesNull|Key  |Discriminator|
+  // bits:     |5                |6                 |7..15|   16...31   |
+  //           |AuthenticatesNull|RestrictedIntegral|Key  |Discriminator|
   uint32_t Data = 0;
 
   // The following static assertions check that each of the 32 bits is present
   // exactly in one of the constants.
   static_assert((EnabledBits + AddressDiscriminatedBits +
                  AuthenticationModeBits + IsaPointerBits +
-                 AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) ==
-                    32,
+                 AuthenticatesNullValuesBits + RestrictedIntegralBits +
+                 KeyBits + DiscriminatorBits) == 32,
                 "PointerAuthQualifier should be exactly 32 bits");
   static_assert((EnabledMask + AddressDiscriminatedMask +
                  AuthenticationModeMask + IsaPointerMask +
-                 AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) ==
-                    0xFFFFFFFF,
+                 AuthenticatesNullValuesMask + RestrictedIntegralMask +
+                 KeyMask + DiscriminatorMask) == 0xFFFFFFFF,
                 "All masks should cover the entire bits");
   static_assert((EnabledMask ^ AddressDiscriminatedMask ^
                  AuthenticationModeMask ^ IsaPointerMask ^
-                 AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) ==
-                    0xFFFFFFFF,
+                 AuthenticatesNullValuesMask ^ RestrictedIntegralMask ^
+                 KeyMask ^ DiscriminatorMask) == 0xFFFFFFFF,
                 "All masks should cover the entire bits");
 
   PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated,
                        unsigned ExtraDiscriminator,
                        PointerAuthenticationMode AuthenticationMode,
-                       bool IsIsaPointer, bool AuthenticatesNullValues)
+                       bool IsIsaPointer, bool AuthenticatesNullValues,
+                       bool IsRestrictedIntegral)
       : Data(EnabledMask |
              (IsAddressDiscriminated
                   ? llvm::to_underlying(AddressDiscriminatedMask)
@@ -212,8 +218,8 @@ class PointerAuthQualifier {
              (llvm::to_underlying(AuthenticationMode)
               << AuthenticationModeShift) |
              (ExtraDiscriminator << DiscriminatorShift) |
-             (IsIsaPointer << IsaPointerShift) |
-             (AuthenticatesNullValues << AuthenticatesNullValuesShift)) {
+             (AuthenticatesNullValues << AuthenticatesNullValuesShift) |
+             (IsRestrictedIntegral << RestrictedIntegralShift)) {
     assert(Key <= KeyNoneInternal);
     assert(ExtraDiscriminator <= MaxDiscriminator);
     assert((Data == 0) ==
@@ -237,13 +243,13 @@ class PointerAuthQualifier {
   static PointerAuthQualifier
   Create(unsigned Key, bool IsAddressDiscriminated, unsigned 
ExtraDiscriminator,
          PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer,
-         bool AuthenticatesNullValues) {
+         bool AuthenticatesNullValues, bool IsRestrictedIntegral) {
     if (Key == PointerAuthKeyNone)
       Key = KeyNoneInternal;
     assert(Key <= KeyNoneInternal && "out-of-range key value");
     return PointerAuthQualifier(Key, IsAddressDiscriminated, 
ExtraDiscriminator,
                                 AuthenticationMode, IsIsaPointer,
-                                AuthenticatesNullValues);
+                                AuthenticatesNullValues, IsRestrictedIntegral);
   }
 
   bool isPresent() const {
@@ -290,6 +296,10 @@ class PointerAuthQualifier {
     return hasKeyNone() ? PointerAuthQualifier() : *this;
   }
 
+  bool isRestrictedIntegral() const {
+    return (Data & RestrictedIntegralMask) >> RestrictedIntegralShift;
+  }
+
   friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
     return Lhs.Data == Rhs.Data;
   }
@@ -2563,7 +2573,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 +8228,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/Attr.td 
b/clang/include/clang/Basic/Attr.td
index dcdcff8c46fe2..50bfe76a86619 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3578,7 +3578,8 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
 }
 
 def PointerAuth : TypeAttr {
-  let Spellings = [CustomKeyword<"__ptrauth">];
+  let Spellings = [CustomKeyword<"__ptrauth">,
+                   CustomKeyword<"__ptrauth_restricted_intptr">];
   let Args = [IntArgument<"Key">,
               BoolArgument<"AddressDiscriminated", 1>,
               IntArgument<"ExtraDiscriminator", 1>];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4c96142e28134..79e26ff9293f0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1021,20 +1021,27 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : 
Error<
   "supported with ptrauth indirect gotos">;
 
 // __ptrauth qualifier
-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_invalid
+    : Error<
+          "%select{return type|parameter type|property}0 may not be qualified "
+          "with '%select{__ptrauth_restricted_intptr|__ptrauth}1'; type is 
%2">;
+def err_ptrauth_qualifier_cast : Error<"cannot cast to "
+                                       
"'%select{__ptrauth_restricted_intptr|__"
+                                       "ptrauth}0'-qualified type %1">;
+def err_ptrauth_qualifier_invalid_target
+    : Error<"'%select{__ptrauth_restricted_intptr|__ptrauth}0' qualifier only "
+            "applies to %select{pointer sized integer|pointer}0 types; %1 is "
+            "invalid">;
 def err_ptrauth_qualifier_redundant : Error<
   "type %0 is already %1-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'">;
+def err_ptrauth_arg_not_ice
+    : Error<"argument to '%0' must be an integer constant expression">;
+def err_ptrauth_address_discrimination_invalid
+    : Error<
+          "invalid address discrimination flag '%0'; '%1' requires '0' or 
'1'">;
+def err_ptrauth_extra_discriminator_invalid
+    : Error<"invalid extra discriminator flag '%0'; '%1' requires a value "
+            "between '0' and '%2'">;
 
 /// main()
 // static main() is not an error in C, just in C++.
diff --git a/clang/include/clang/Basic/Features.def 
b/clang/include/clang/Basic/Features.def
index 14bff8a68846d..c859167e47e57 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -108,6 +108,7 @@ FEATURE(dataflow_sanitizer, 
LangOpts.Sanitize.has(SanitizerKind::DataFlow))
 FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
 FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
 EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics)
+EXTENSION(ptrauth_restricted_intptr_qualifier, LangOpts.PointerAuthIntrinsics)
 FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
 FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
 FEATURE(ptrauth_vtable_pointer_address_discrimination, 
LangOpts.PointerAuthVTPtrAddressDiscrimination)
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index 868e851342eb8..85c0f58181c98 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -349,6 +349,7 @@ KEYWORD(__func__                    , KEYALL)
 KEYWORD(__objc_yes                  , KEYALL)
 KEYWORD(__objc_no                   , KEYALL)
 KEYWORD(__ptrauth                   , KEYALL)
+KEYWORD(__ptrauth_restricted_intptr , KEYALL)
 
 // C2y
 UNARY_EXPR_OR_TYPE_TRAIT(_Countof, CountOf, KEYNOCXX)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0c77c5b5ca30a..e438194230cf7 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3599,7 +3599,8 @@ class Sema final : public SemaBase {
     PADAK_ExtraDiscPtrAuth,
   };
 
-  bool checkPointerAuthDiscriminatorArg(Expr *Arg, PointerAuthDiscArgKind Kind,
+  bool checkPointerAuthDiscriminatorArg(const AttributeCommonInfo &AttrInfo,
+                                        Expr *Arg, PointerAuthDiscArgKind Kind,
                                         unsigned &IntVal);
 
   /// Diagnose function specifiers on a declaration of an identifier that
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c95e733f30494..73051f46444f8 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2924,6 +2924,9 @@ bool ASTContext::hasUniqueObjectRepresentations(
 
   // All integrals and enums are unique.
   if (Ty->isIntegralOrEnumerationType()) {
+    // Address discriminated __ptrauth_restricted_intptr 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 111a642173418..4bf4a02d47fbd 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5056,6 +5056,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/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index cba1a2d98d660..fe4283abc7017 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2534,7 +2534,10 @@ void PointerAuthQualifier::print(raw_ostream &OS,
   if (!isPresent())
     return;
 
-  OS << "__ptrauth(";
+  if (isRestrictedIntegral())
+    OS << "__ptrauth_restricted_intptr(";
+  else
+    OS << "__ptrauth(";
   OS << getKey();
   OS << "," << unsigned(isAddressDiscriminated()) << ","
      << getExtraDiscriminator() << ")";
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp 
b/clang/lib/CodeGen/CGExprConstant.cpp
index b21ebeee4bed1..d196e39ea374c 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2444,6 +2444,9 @@ 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 8dbbcdaef25d8..ff84e3c3f87e9 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2287,7 +2287,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 0a183a8524c17..01f43630edce3 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.
@@ -590,8 +593,9 @@ CodeGenModule::computeVTPointerAuthentication(const 
CXXRecordDecl *ThisClass) {
   }
   return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator,
                                       PointerAuthenticationMode::SignAndAuth,
-                                      /* IsIsaPointer */ false,
-                                      /* AuthenticatesNullValues */ false);
+                                      /*IsIsaPointer=*/false,
+                                      /*AuthenticatesNullValues=*/false,
+                                      /*IsRestrictedIntegral=*/false);
 }
 
 std::optional<PointerAuthQualifier>
@@ -642,10 +646,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 +671,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/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 69d40baaf4298..4db4c8670cc31 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3401,11 +3401,12 @@ void Parser::DistributeCLateParsedAttrs(Decl *Dcl,
 }
 
 /// type-qualifier:
-///    ('__ptrauth') '(' constant-expression
+///    ('__ptrauth' | '__ptrauth_restricted_intptr') '(' constant-expression
 ///                   (',' constant-expression)[opt]
 ///                   (',' constant-expression)[opt] ')'
 void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) {
-  assert(Tok.is(tok::kw___ptrauth));
+  assert(Tok.is(tok::kw___ptrauth) ||
+         Tok.is(tok::kw___ptrauth_restricted_intptr));
 
   IdentifierInfo *KwName = Tok.getIdentifierInfo();
   SourceLocation KwLoc = ConsumeToken();
@@ -4308,6 +4309,7 @@ void Parser::ParseDeclarationSpecifiers(
 
     // __ptrauth qualifier.
     case tok::kw___ptrauth:
+    case tok::kw___ptrauth_restricted_intptr:
       ParsePtrauthQualifier(DS.getAttributes());
       continue;
 
@@ -6025,6 +6027,7 @@ bool Parser::isTypeSpecifierQualifier() {
   case tok::kw___pascal:
   case tok::kw___unaligned:
   case tok::kw___ptrauth:
+  case tok::kw___ptrauth_restricted_intptr:
 
   case tok::kw__Nonnull:
   case tok::kw__Nullable:
@@ -6315,6 +6318,7 @@ bool Parser::isDeclarationSpecifier(
   case tok::kw___pascal:
   case tok::kw___unaligned:
   case tok::kw___ptrauth:
+  case tok::kw___ptrauth_restricted_intptr:
 
   case tok::kw__Nonnull:
   case tok::kw__Nullable:
@@ -6581,6 +6585,7 @@ void Parser::ParseTypeQualifierListOpt(
 
     // __ptrauth qualifier.
     case tok::kw___ptrauth:
+    case tok::kw___ptrauth_restricted_intptr:
       ParsePtrauthQualifier(DS.getAttributes());
       EndLoc = PrevTokLocation;
       continue;
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 14e16bc39eb3a..2881b6bb9bdd0 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -175,7 +175,7 @@ namespace {
       // Destination type may not be qualified with __ptrauth.
       if (DestType.getPointerAuth()) {
         Self.Diag(DestRange.getBegin(), diag::err_ptrauth_qualifier_cast)
-            << DestType << DestRange;
+            << DestType->isSignablePointerType() << DestType << DestRange;
       }
     }
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9c9372d9ee2b0..561f6309de226 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1550,7 +1550,8 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, 
unsigned &Result) {
   return false;
 }
 
-bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
+bool Sema::checkPointerAuthDiscriminatorArg(const AttributeCommonInfo 
&AttrInfo,
+                                            Expr *Arg,
                                             PointerAuthDiscArgKind Kind,
                                             unsigned &IntVal) {
   if (!Arg) {
@@ -1559,8 +1560,10 @@ bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
   }
 
   std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context);
+  StringRef AttrName = AttrInfo.getAttrName()->getName();
   if (!Result) {
-    Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice);
+    Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice)
+        << AttrName;
     return false;
   }
 
@@ -1580,10 +1583,10 @@ bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
   if (*Result < 0 || *Result > Max) {
     if (IsAddrDiscArg)
       Diag(Arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid)
-          << Result->getExtValue();
+          << Result->getExtValue() << AttrName;
     else
       Diag(Arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid)
-          << Result->getExtValue() << Max;
+          << Result->getExtValue() << AttrName << Max;
 
     return false;
   };
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b0ebf3e5f47c3..e4c5f1b3aae00 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15472,7 +15472,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, 
SourceLocation StartLoc,
 
   // __ptrauth is forbidden on parameters.
   if (T.getPointerAuth()) {
-    Diag(NameLoc, diag::err_ptrauth_qualifier_invalid) << T << 1;
+    Diag(NameLoc, diag::err_ptrauth_qualifier_invalid)
+        << 1 << T->isSignablePointerType() << T;
     New->setInvalidDecl();
   }
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d4e48a14d13c2..3b896e3518989 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -10621,7 +10621,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/SemaObjCProperty.cpp 
b/clang/lib/Sema/SemaObjCProperty.cpp
index 3e962fcb8b0e5..9bd19befc6d5b 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -180,9 +180,9 @@ Decl *SemaObjC::ActOnProperty(Scope *S, SourceLocation 
AtLoc,
                            0);
   TypeSourceInfo *TSI = SemaRef.GetTypeForDeclarator(FD.D);
   QualType T = TSI->getType();
-  if (T.getPointerAuth().isPresent()) {
-    Diag(AtLoc, diag::err_ptrauth_qualifier_invalid) << T << 2;
-  }
+  if (T.getPointerAuth().isPresent())
+    Diag(AtLoc, diag::err_ptrauth_qualifier_invalid)
+        << 2 << T->isSignablePointerType() << T;
   if (!getOwnershipRule(Attributes)) {
     Attributes |= deducePropertyOwnershipFromType(SemaRef, T);
   }
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 6e7ee8b5506ff..d22517be9d799 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2552,9 +2552,10 @@ bool Sema::CheckFunctionReturnType(QualType T, 
SourceLocation Loc) {
     return true;
   }
 
-  // __ptrauth is illegal on a function return type.
+  // __ptrauth[_restricted_intptr] is illegal on a function return type.
   if (T.getPointerAuth()) {
-    Diag(Loc, diag::err_ptrauth_qualifier_invalid) << T << 0;
+    Diag(Loc, diag::err_ptrauth_qualifier_invalid)
+        << 0 << T->isSignablePointerType() << T;
     return true;
   }
 
@@ -2664,8 +2665,9 @@ QualType Sema::BuildFunctionType(QualType T,
       Diag(Loc, diag::err_wasm_table_as_function_parameter);
       Invalid = true;
     } else if (ParamType.getPointerAuth()) {
-      // __ptrauth is illegal on a function return type.
-      Diag(Loc, diag::err_ptrauth_qualifier_invalid) << T << 1;
+      // __ptrauth[_restricted_intptr] is illegal on a function return type.
+      Diag(Loc, diag::err_ptrauth_qualifier_invalid)
+          << 1 << T->isSignablePointerType() << T;
       Invalid = true;
     }
 
@@ -4986,7 +4988,8 @@ static TypeSourceInfo 
*GetFullTypeForDeclarator(TypeProcessingState &state,
 
       // __ptrauth is illegal on a function return type.
       if (T.getPointerAuth()) {
-        S.Diag(DeclType.Loc, diag::err_ptrauth_qualifier_invalid) << T << 0;
+        S.Diag(DeclType.Loc, diag::err_ptrauth_qualifier_invalid)
+            << 0 << T->isSignablePointerType() << T;
       }
 
       if (LangOpts.OpenCL) {
@@ -8353,6 +8356,7 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, 
QualType &T,
 
   assert((Attr.getNumArgs() > 0 && Attr.getNumArgs() <= 3) &&
          "__ptrauth qualifier takes between 1 and 3 arguments");
+  StringRef AttrName = Attr.getAttrName()->getName();
   Expr *KeyArg = Attr.getArgAsExpr(0);
   Expr *IsAddressDiscriminatedArg =
       Attr.getNumArgs() >= 2 ? Attr.getArgAsExpr(1) : nullptr;
@@ -8368,26 +8372,37 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, 
QualType &T,
 
   bool IsInvalid = false;
   unsigned IsAddressDiscriminated, ExtraDiscriminator;
-  IsInvalid |= !S.checkPointerAuthDiscriminatorArg(IsAddressDiscriminatedArg,
+  IsInvalid |= !S.checkPointerAuthDiscriminatorArg(Attr, 
IsAddressDiscriminatedArg,
                                                    Sema::PADAK_AddrDiscPtrAuth,
                                                    IsAddressDiscriminated);
-  IsInvalid |= !S.checkPointerAuthDiscriminatorArg(
+  IsInvalid |= !S.checkPointerAuthDiscriminatorArg(Attr,
       ExtraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, ExtraDiscriminator);
 
   if (IsInvalid) {
     Attr.setInvalid();
     return;
   }
-
-  if (!T->isSignableType() && !T->isDependentType()) {
-    S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T;
-    Attr.setInvalid();
-    return;
+  bool IsRestrictedIntegral = false;
+  if (AttrName == "__ptrauth_restricted_intptr") {
+    IsRestrictedIntegral = true;
+    if (!T->isSignableIntegerType(Ctx) && !T->isDependentType()) {
+      S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_invalid_target)
+          << 0 << T;
+      Attr.setInvalid();
+      return;
+    }
+  } else {
+    if (!T->isSignablePointerType() && !T->isDependentType()) {
+      S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_invalid_target)
+          << 1 << T;
+      Attr.setInvalid();
+      return;
+    }
   }
 
   if (T.getPointerAuth()) {
     S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant)
-        << T << Attr.getAttrName()->getName();
+        << T << AttrName;
     Attr.setInvalid();
     return;
   }
@@ -8402,7 +8417,7 @@ 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, IsRestrictedIntegral);
   T = S.Context.getPointerAuthType(T, Qual);
 }
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5e83f83603335..805f4bcc1a496 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5292,12 +5292,25 @@ QualType 
TreeTransform<Derived>::RebuildQualifiedType(QualType T,
   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;
+          << TL.getType()
+          << (LocalPointerAuth.isRestrictedIntegral()
+                  ? "__ptrauth_restricted_intptr"
+                  : "__ptrauth");
       return QualType();
     }
+    if (!T->isDependentType()) {
+      if (Quals.getPointerAuth().isRestrictedIntegral()) {
+        if (!T->isSignableIntegerType(SemaRef.getASTContext())) {
+          SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_invalid_target)
+              << /*IsPtrauth=*/0 << T;
+          return QualType();
+        }
+      } else if (!T->isSignablePointerType()) {
+        SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_invalid_target)
+            << /*IsPtrauth=*/1 << 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..2667fb01ebcee
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c
@@ -0,0 +1,220 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm %s -O0 -o - | FileCheck %s
+#if !__has_extension(ptrauth_restricted_intptr_qualifier)
+#error ptrauth_restricted_intptr_qualifier should exist
+#endif
+
+__INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 0, 56) g1 = 0;
+// CHECK: @g1 = global i64 0
+__INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 1272) g2 = 0;
+// CHECK: @g2 = global i64 0
+extern __UINTPTR_TYPE__ test_int;
+__UINTPTR_TYPE__ __ptrauth_restricted_intptr(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_restricted_intptr(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_restricted_intptr(1, 0, 431) f0;
+  __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 0, 9182) f1;
+  __INTPTR_TYPE__ __ptrauth_restricted_intptr(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_restricted_intptr(1, 1, 1276) f0;
+  __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 23674) f1;
+  __INTPTR_TYPE__ __ptrauth_restricted_intptr(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_restricted_intptr(1, 1, 42) j = 0;
+  // CHECK: [[J_ADDR:%.*]] = ptrtoint ptr %j to i64
+  // CHECK: store i64 0, ptr %j
+  __INTPTR_TYPE__ __ptrauth_restricted_intptr(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_restricted_intptr(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-restricted-intptr-qualifier.c 
b/clang/test/Sema/ptrauth-restricted-intptr-qualifier.c
new file mode 100644
index 0000000000000..a73aab7bd73c0
--- /dev/null
+++ b/clang/test/Sema/ptrauth-restricted-intptr-qualifier.c
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify 
-fptrauth-intrinsics %s
+#if !__has_extension(ptrauth_restricted_intptr_qualifier)
+#error ptrauth_restricted_intptr_qualifier should exist
+#endif
+
+int *__ptrauth_restricted_intptr(0) a;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'int *' is invalid}}
+
+char __ptrauth_restricted_intptr(0) b;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'char' is invalid}}
+unsigned char __ptrauth_restricted_intptr(0) c;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'unsigned char' is invalid}}
+short __ptrauth_restricted_intptr(0) d;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'short' is invalid}}
+unsigned short __ptrauth_restricted_intptr(0) e;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'unsigned short' is invalid}}
+int __ptrauth_restricted_intptr(0) f;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'int' is invalid}}
+unsigned int __ptrauth_restricted_intptr(0) g;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'unsigned int' is invalid}}
+__int128_t __ptrauth_restricted_intptr(0) h;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; '__int128_t' (aka '__int128') is invalid}}
+unsigned short __ptrauth_restricted_intptr(0) i;
+// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to 
pointer sized integer types; 'unsigned short' is invalid}}
+
+unsigned long long __ptrauth_restricted_intptr(0) j;
+long long __ptrauth_restricted_intptr(0) k;
+__SIZE_TYPE__ __ptrauth_restricted_intptr(0) l;
+const unsigned long long __ptrauth_restricted_intptr(0) m;
+const long long __ptrauth_restricted_intptr(0) n;
+const __SIZE_TYPE__ __ptrauth_restricted_intptr(0) o;
+
+struct S1 {
+  __SIZE_TYPE__ __ptrauth_restricted_intptr(0) f0;
+};
+struct S2 {
+  int *__ptrauth_restricted_intptr(0) f0;
+  // expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies 
to pointer sized integer types; 'int *' is invalid}}
+};
+
+void x(unsigned long long __ptrauth_restricted_intptr(0) f0);
+// expected-error@-1{{parameter type may not be qualified with 
'__ptrauth_restricted_intptr'; type is '__ptrauth_restricted_intptr(0,0,0) 
unsigned long long'}}
+
+unsigned long long __ptrauth_restricted_intptr(0) y();
+// expected-error@-1{{return type may not be qualified with 
'__ptrauth_restricted_intptr'; type is '__ptrauth_restricted_intptr(0,0,0) 
unsigned long long'}}
diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp 
b/clang/test/SemaCXX/ptrauth-triviality.cpp
index baadadca9f64f..08407d4cdeb1f 100644
--- a/clang/test/SemaCXX/ptrauth-triviality.cpp
+++ b/clang/test/SemaCXX/ptrauth-triviality.cpp
@@ -4,6 +4,8 @@
 
 #define AQ __ptrauth(1,1,50)
 #define IQ __ptrauth(1,0,50)
+#define AQ_IP __ptrauth_restricted_intptr(1,1,50)
+#define IQ_IP __ptrauth_restricted_intptr(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)]]
@@ -121,3 +123,45 @@ static_assert(__is_trivially_destructible(Holder<S5>));
 static_assert(!__is_trivially_copyable(Holder<S5>));
 static_assert(!__is_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));
+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>));
+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));
+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>));
+static_assert(__is_trivially_equality_comparable(Holder<S7>));
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index f22fcbab557a0..39c9f0fab923f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -642,6 +642,11 @@ static TypePayloadClang GetPtrAuthMofidierPayload(const 
DWARFDIE &die) {
   auto getAttr = [&](llvm::dwarf::Attribute Attr, unsigned defaultValue = 0) {
     return die.GetAttributeValueAsUnsigned(Attr, defaultValue);
   };
+  bool is_restricted_integral = false;
+  if (Type *res_type = die.GetDWARF()->ResolveType(die))
+    if (auto *ptr_type = (clang::Type *)res_type->GetForwardCompilerType()
+                             .GetOpaqueQualType())
+      is_restricted_integral = !ptr_type->isPointerType();
   const unsigned key = getAttr(DW_AT_LLVM_ptrauth_key);
   const bool addr_disc = getAttr(DW_AT_LLVM_ptrauth_address_discriminated);
   const unsigned extra = getAttr(DW_AT_LLVM_ptrauth_extra_discriminator);
@@ -667,7 +672,7 @@ static TypePayloadClang GetPtrAuthMofidierPayload(const 
DWARFDIE &die) {
   }
   auto ptr_auth = clang::PointerAuthQualifier::Create(
       key, addr_disc, extra, authentication_mode, isapointer,
-      authenticates_null_values);
+      authenticates_null_values, is_restricted_integral);
   return TypePayloadClang(ptr_auth.getAsOpaqueValue());
 }
 

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

Reply via email to