Skip to content

Conversation

@ojhunt
Copy link
Contributor

@ojhunt ojhunt commented Dec 14, 2025

This PR adds support for an 'options' parameter for the __ptrauth qualifier.
The initial version only exposes the authehntication modes:

  • "strip"
  • "sign-and-strip"
  • "sign-and-auth"

We also support parsing the options but not yet the implementation

  • "isa-pointer"
  • "authenticates-null-values"

The initial support for authentication mode controls exist to support ABI changes over time, and as a byproduct support basic initial tests for option parsing.

This PR adds support for an 'options' parameter for the __ptrauth
qualifier.
The initial version only exposes the authehntication modes:
 * "strip"
 * "sign-and-strip"
 * "sign-and-auth"

We also support parsing the options but not yet the implementation
 * "isa-pointer"
 * "authenticates-null-values"

The initial support for authentication mode controls exist to support
ABI changes over time, and as a byproduct support basic initial tests
for option parsing.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Dec 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 14, 2025

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang

Author: Oliver Hunt (ojhunt)

Changes

This PR adds support for an 'options' parameter for the __ptrauth qualifier.
The initial version only exposes the authehntication modes:

  • "strip"
  • "sign-and-strip"
  • "sign-and-auth"

We also support parsing the options but not yet the implementation

  • "isa-pointer"
  • "authenticates-null-values"

The initial support for authentication mode controls exist to support ABI changes over time, and as a byproduct support basic initial tests for option parsing.


Patch is 51.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/172187.diff

14 Files Affected:

  • (modified) clang/docs/PointerAuthentication.rst (+28-4)
  • (modified) clang/include/clang/Basic/Attr.td (+3-3)
  • (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+1-1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+12)
  • (modified) clang/include/clang/Basic/LangOptions.h (+11)
  • (modified) clang/lib/AST/TypePrinter.cpp (+33-1)
  • (modified) clang/lib/CodeGen/CGExprConstant.cpp (+17-7)
  • (modified) clang/lib/Parse/ParseDecl.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaType.cpp (+147-9)
  • (added) clang/test/CodeGen/ptrauth-stripping.c (+327)
  • (modified) clang/test/Parser/ptrauth-qualifier.c (+1-1)
  • (added) clang/test/Sema/ptrauth-qualifier-options.c (+108)
  • (modified) clang/test/Sema/ptrauth-qualifier.c (+33-6)
  • (added) clang/test/SemaCXX/ptrauth-qualifier-constexpr-options.cpp (+65)
diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst
index bf2520b32a3a4..899bca203a137 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -427,7 +427,7 @@ purposes they are all equivalent to ``ptrauth_calls``.
 ``__ptrauth`` qualifier
 ^^^^^^^^^^^^^^^^^^^^^^^
 
-``__ptrauth(key, address, discriminator)`` is an extended type
+``__ptrauth(key, address, discriminator, options)`` is an extended type
 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.
@@ -452,6 +452,9 @@ The qualifier's operands are as follows:
 
 - ``discriminator`` - a constant discriminator; must be a constant expression
 
+- ``options`` - a constant string expression containing a list of comma
+  separated authentication options; see ``ptrauth_qualifier_options``_
+
 See `Discriminators`_ for more information about discriminators.
 
 Currently the operands must be constant-evaluable even within templates. In the
@@ -463,9 +466,9 @@ qualifiers on a parameter (after parameter type adjustment) are ignored when
 deriving the type of the function.  The parameter will be passed using the
 default ABI for the unqualified pointer type.
 
-If ``x`` is an object of type ``__ptrauth(key, address, discriminator) T``,
-then the signing schema of the value stored in ``x`` is a key of ``key`` and
-a discriminator determined as follows:
+If ``x`` is an object of type ``__ptrauth(key, address, discriminator, options) T``,
+then the signing schema of the value stored in ``x`` is a key of ``key`` and a
+discriminator determined as follows:
 
 - if ``address`` is 0, then the discriminator is ``discriminator``;
 
@@ -527,6 +530,27 @@ rules of C++:
   indirectly. Thus, changing the address-sensitivity of a type may be
   ABI-breaking even if its size and alignment do not change.
 
+``ptrauth_qualifier_options``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The options parameter to the ``__ptrauth`` qualifier is a string of comma
+separated modifiers to the normal authentication behavior. Currently supported
+options are
+
+- Authentication mode: This is one of ``strip``, ``sign-and-strip``, and
+  ``sign-and-auth``. The ability to modify this behavior is intended to support
+  staging ABI changes. The ``strip`` mode results in the PAC bits of a value
+  being stripped from any value and disabled any other authentication
+  operations. ``sign-and-strip`` strips an authenticated on read, but will
+  ensure a correct signature is set on assignment. Finally ``sign-and-auth`` is
+  the default mode, and provides full protection for the value.
+
+- ``authenticates-null-values``: By default the __ptrauth qualifier does not
+  sign the zero value. This permits fast implementation of null checks in the
+  common case where a null value is safe. The ``authenticates-null-values``
+  option overrides this behavior, and permits null values to be protected with
+  pointer authentication.
+
 ``<ptrauth.h>``
 ~~~~~~~~~~~~~~~
 
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 0b006142cbb74..d0d65fbe166f0 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3750,9 +3750,9 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
 
 def PointerAuth : TypeAttr {
   let Spellings = [CustomKeyword<"__ptrauth">];
-  let Args = [IntArgument<"Key">,
-              BoolArgument<"AddressDiscriminated", 1>,
-              IntArgument<"ExtraDiscriminator", 1>];
+  let Args = [IntArgument<"Key">, BoolArgument<"AddressDiscriminated", 1>,
+              IntArgument<"ExtraDiscriminator", 1>,
+              StringArgument<"Options", 1>];
   let Documentation = [PtrAuthDocs];
 }
 
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 442a90ec2472d..6abadc6d4655e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1771,7 +1771,7 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning<
   InGroup<CudaCompat>;
 
 def err_ptrauth_qualifier_bad_arg_count : Error<
-  "'__ptrauth' qualifier must take between 1 and 3 arguments">;
+  "'__ptrauth' qualifier must take between 1 and 4 arguments">;
 
 def warn_cuda_attr_lambda_position : Warning<
   "nvcc does not allow '__%0__' to appear after the parameter list in lambdas">,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 381d1fb063eba..c285e2d1e2a0d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1048,6 +1048,18 @@ def err_ptrauth_extra_discriminator_invalid : Error<
   "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between "
   "'0' and '%1'">;
 
+// __ptrauth qualifier options string
+def note_ptrauth_evaluating_options
+    : Note<"options parameter evaluated to '%0'">;
+def err_ptrauth_invalid_option : Error<"'__ptrauth' options parameter %0">;
+def err_ptrauth_unknown_authentication_option
+    : Error<"unknown '__ptrauth' authentication option '%0'">;
+def err_ptrauth_repeated_authentication_option
+    : Error<"repeated '__ptrauth' authentication %select{mode|option}0%select{, prior "
+            "mode was '%2'| '%1'}0">;
+def err_ptrauth_option_missing_comma
+    : Error<"missing comma after '%0' option in '__ptrauth' qualifier">;
+
 /// main()
 // static main() is not an error in C, just in C++.
 def warn_static_main : Warning<"'main' should not be declared static">,
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 4fa2dcffc75b6..0d1d94d63d076 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -67,6 +67,17 @@ enum class PointerAuthenticationMode : unsigned {
   SignAndAuth
 };
 
+static constexpr llvm::StringLiteral PointerAuthenticationOptionStrip = "strip";
+static constexpr llvm::StringLiteral PointerAuthenticationOptionSignAndStrip =
+    "sign-and-strip";
+static constexpr llvm::StringLiteral PointerAuthenticationOptionSignAndAuth =
+    "sign-and-auth";
+static constexpr llvm::StringLiteral PointerAuthenticationOptionIsaPointer =
+    "isa-pointer";
+static constexpr llvm::StringLiteral
+    PointerAuthenticationOptionAuthenticatesNullValues =
+        "authenticates-null-values";
+
 /// Bitfields of LangOptions, split out from LangOptions in order to ensure that
 /// this large collection of bitfields is a trivial class type.
 class LangOptionsBase {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index d2881d5ac518a..030168849c7e2 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2610,7 +2610,39 @@ void PointerAuthQualifier::print(raw_ostream &OS,
   OS << "__ptrauth(";
   OS << getKey();
   OS << "," << unsigned(isAddressDiscriminated()) << ","
-     << getExtraDiscriminator() << ")";
+     << getExtraDiscriminator();
+
+  bool HasAppendedOption = false;
+  auto AppendOption = [&](StringRef Option) {
+    OS << ",";
+    if (!HasAppendedOption)
+      OS << '"';
+    HasAppendedOption = true;
+    OS << Option;
+  };
+  switch (getAuthenticationMode()) {
+  case PointerAuthenticationMode::None:
+    llvm_unreachable("Mode is unauthenticated but claims to be present");
+    return;
+  case PointerAuthenticationMode::Strip:
+    AppendOption(PointerAuthenticationOptionStrip);
+    break;
+  case PointerAuthenticationMode::SignAndStrip:
+    AppendOption(PointerAuthenticationOptionSignAndStrip);
+    break;
+  case clang::PointerAuthenticationMode::SignAndAuth:
+    // Don't emit default auth
+    break;
+  }
+  if (isIsaPointer())
+    AppendOption(PointerAuthenticationOptionIsaPointer);
+  if (authenticatesNullValues())
+    AppendOption(PointerAuthenticationOptionAuthenticatesNullValues);
+
+  if (HasAppendedOption)
+    OS << '"';
+
+  OS << ")";
 }
 
 std::string Qualifiers::getAsString() const {
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 0eec4dba4824a..15ae2bf6f28c6 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2129,6 +2129,13 @@ class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
 
 }
 
+static bool shouldSignPointer(const PointerAuthQualifier &PointerAuth) {
+  PointerAuthenticationMode AuthenticationMode =
+      PointerAuth.getAuthenticationMode();
+  return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
+         AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
+}
+
 llvm::Constant *ConstantLValueEmitter::tryEmit() {
   const APValue::LValueBase &base = Value.getLValueBase();
 
@@ -2162,7 +2169,8 @@ llvm::Constant *ConstantLValueEmitter::tryEmit() {
 
   // Apply pointer-auth signing from the destination type.
   if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth();
-      PointerAuth && !result.HasDestPointerAuth) {
+      PointerAuth && !result.HasDestPointerAuth &&
+      shouldSignPointer(PointerAuth)) {
     value = Emitter.tryEmitConstantSignedPointer(value, PointerAuth);
     if (!value)
       return nullptr;
@@ -2210,8 +2218,9 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
     if (D->hasAttr<WeakRefAttr>())
       return CGM.GetWeakRefReference(D).getPointer();
 
-    auto PtrAuthSign = [&](llvm::Constant *C) {
-      if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth()) {
+    auto PtrAuthSign = [&](llvm::Constant *C, bool IsFunction) {
+      if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth();
+          PointerAuth && shouldSignPointer(PointerAuth)) {
         C = applyOffset(C);
         C = Emitter.tryEmitConstantSignedPointer(C, PointerAuth);
         return ConstantLValue(C, /*applied offset*/ true, /*signed*/ true);
@@ -2219,7 +2228,7 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
 
       CGPointerAuthInfo AuthInfo;
 
-      if (EnablePtrAuthFunctionTypeDiscrimination)
+      if (IsFunction && EnablePtrAuthFunctionTypeDiscrimination)
         AuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
 
       if (AuthInfo) {
@@ -2240,18 +2249,19 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
       llvm::Constant *C = CGM.getRawFunctionPointer(FD);
       if (FD->getType()->isCFIUncheckedCalleeFunctionType())
         C = llvm::NoCFIValue::get(cast<llvm::GlobalValue>(C));
-      return PtrAuthSign(C);
+      return PtrAuthSign(C, /*IsFunction=*/true);
     }
 
     if (const auto *VD = dyn_cast<VarDecl>(D)) {
       // We can never refer to a variable with local storage.
       if (!VD->hasLocalStorage()) {
         if (VD->isFileVarDecl() || VD->hasExternalStorage())
-          return CGM.GetAddrOfGlobalVar(VD);
+          return PtrAuthSign(CGM.GetAddrOfGlobalVar(VD), /*IsFunction=*/false);
 
         if (VD->isLocalVarDecl()) {
-          return CGM.getOrCreateStaticVarDecl(
+          llvm::Constant *C = CGM.getOrCreateStaticVarDecl(
               *VD, CGM.getLLVMLinkageVarDefinition(VD));
+          return PtrAuthSign(C, /*IsFunction=*/false);
         }
       }
     }
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 8688ccf41acb5..270c039dc6f40 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3172,7 +3172,7 @@ void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) {
   T.consumeClose();
   SourceLocation EndLoc = T.getCloseLocation();
 
-  if (ArgExprs.empty() || ArgExprs.size() > 3) {
+  if (ArgExprs.empty() || ArgExprs.size() > 4) {
     Diag(KwLoc, diag::err_ptrauth_qualifier_bad_arg_count);
     return;
   }
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index fd64d4456cbfa..880a30ea55b54 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8456,14 +8456,15 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
 /// Handle the __ptrauth qualifier.
 static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
                                    const ParsedAttr &Attr, Sema &S) {
-
-  assert((Attr.getNumArgs() > 0 && Attr.getNumArgs() <= 3) &&
-         "__ptrauth qualifier takes between 1 and 3 arguments");
+  assert((Attr.getNumArgs() > 0 && Attr.getNumArgs() <= 4) &&
+         "__ptrauth qualifier takes between 1 and 4 arguments");
   Expr *KeyArg = Attr.getArgAsExpr(0);
   Expr *IsAddressDiscriminatedArg =
       Attr.getNumArgs() >= 2 ? Attr.getArgAsExpr(1) : nullptr;
   Expr *ExtraDiscriminatorArg =
       Attr.getNumArgs() >= 3 ? Attr.getArgAsExpr(2) : nullptr;
+  Expr *AuthenticationOptionsArg =
+      Attr.getNumArgs() >= 4 ? Attr.getArgAsExpr(3) : nullptr;
 
   unsigned Key;
   if (S.checkConstantPointerAuthKey(KeyArg, Key)) {
@@ -8479,10 +8480,138 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
                                                    IsAddressDiscriminated);
   IsInvalid |= !S.checkPointerAuthDiscriminatorArg(
       ExtraDiscriminatorArg, PointerAuthDiscArgKind::Extra, ExtraDiscriminator);
+  std::string LastAuthenticationMode;
+  std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt;
+  bool IsIsaPointer = false;
+  bool AuthenticatesNullValues = false;
+
+  if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors()) {
+    StringRef OptionsString;
+    std::string EvaluatedString;
+    bool HasEvaluatedOptionsString = false;
+    const StringLiteral *OptionsStringLiteral =
+        dyn_cast<StringLiteral>(AuthenticationOptionsArg);
+    SourceRange AuthenticationOptionsRange =
+        AuthenticationOptionsArg->getSourceRange();
+    bool ReportedEvaluation = false;
+    auto ReportEvaluationOfExpressionIfNeeded = [&]() {
+      if (OptionsStringLiteral || !HasEvaluatedOptionsString ||
+          ReportedEvaluation)
+        return;
+      ReportedEvaluation = true;
+      S.Diag(AuthenticationOptionsRange.getBegin(),
+             diag::note_ptrauth_evaluating_options)
+          << OptionsString << AuthenticationOptionsRange;
+    };
+    auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason) {
+      S.Diag(AuthenticationOptionsRange.getBegin(),
+             diag::err_ptrauth_invalid_option)
+          << Reason;
+      Attr.setInvalid();
+      IsInvalid = true;
+      ReportEvaluationOfExpressionIfNeeded();
+    };
+    if (AuthenticationOptionsArg->isValueDependent() ||
+        AuthenticationOptionsArg->isTypeDependent()) {
+      DiagnoseInvalidOptionsParameter("is dependent");
+      return;
+    }
+    if (OptionsStringLiteral) {
+      OptionsString = OptionsStringLiteral->getString();
+      HasEvaluatedOptionsString = true;
+    } else {
+      Expr::EvalResult Eval;
+      bool Result = AuthenticationOptionsArg->EvaluateAsRValue(Eval, Ctx);
+      if (Result && Eval.Val.isLValue()) {
+        auto *BaseExpr = Eval.Val.getLValueBase().dyn_cast<const Expr *>();
+        const StringLiteral *EvaluatedStringLiteral =
+            dyn_cast<StringLiteral>(const_cast<Expr *>(BaseExpr));
+        if (EvaluatedStringLiteral) {
+          CharUnits StartOffset = Eval.Val.getLValueOffset();
+          EvaluatedString = EvaluatedStringLiteral->getString().drop_front(
+              StartOffset.getQuantity());
+          OptionsString = EvaluatedString;
+          HasEvaluatedOptionsString = true;
+        }
+      }
+    }
+    if (!HasEvaluatedOptionsString) {
+      DiagnoseInvalidOptionsParameter(
+          "must be a string of comma separated flags");
+      return;
+    }
+    for (char Ch : OptionsString) {
+      if (Ch != '-' && Ch != ',' && !isWhitespace(Ch) && !isalpha(Ch)) {
+        DiagnoseInvalidOptionsParameter("contains invalid characters");
+        return;
+      }
+    }
+    HasEvaluatedOptionsString = true;
+    OptionsString = OptionsString.trim();
+    llvm::SmallVector<StringRef> Options;
+    if (!OptionsString.empty())
+      OptionsString.split(Options, ',');
+
+    auto OptionHandler = [&](auto Value, auto *Option,
+                             std::string *LastOption = nullptr) {
+      return [&, Value, Option, LastOption](StringRef OptionString) {
+        if (!*Option) {
+          *Option = Value;
+          if (LastOption)
+            *LastOption = OptionString;
+          return true;
+        }
+        bool IsAuthenticationMode =
+            std::is_same_v<decltype(Value), PointerAuthenticationMode>;
+        S.Diag(AuthenticationOptionsRange.getBegin(),
+               diag::err_ptrauth_repeated_authentication_option)
+            << !IsAuthenticationMode << OptionString
+            << (LastOption ? *LastOption : "");
+        return false;
+      };
+    };
 
-  if (IsInvalid) {
-    Attr.setInvalid();
-    return;
+    for (unsigned Idx = 0; Idx < Options.size(); ++Idx) {
+      StringRef Option = Options[Idx].trim();
+      if (Option.empty()) {
+        bool IsLastOption = Idx == (Options.size() - 1);
+        DiagnoseInvalidOptionsParameter(
+            IsLastOption ? "has a trailing comma" : "contains an empty option");
+        continue;
+      }
+      auto SelectedHandler =
+          llvm::StringSwitch<std::function<bool(StringRef)>>(Option)
+              .Case(PointerAuthenticationOptionStrip,
+                    OptionHandler(PointerAuthenticationMode::Strip,
+                                  &AuthenticationMode, &LastAuthenticationMode))
+              .Case(PointerAuthenticationOptionSignAndStrip,
+                    OptionHandler(PointerAuthenticationMode::SignAndStrip,
+                                  &AuthenticationMode, &LastAuthenticationMode))
+              .Case(PointerAuthenticationOptionSignAndAuth,
+                    OptionHandler(PointerAuthenticationMode::SignAndAuth,
+                                  &AuthenticationMode, &LastAuthenticationMode))
+              .Case(PointerAuthenticationOptionIsaPointer,
+                    OptionHandler(true, &IsIsaPointer))
+              .Case(PointerAuthenticationOptionAuthenticatesNullValues,
+                    OptionHandler(true, &AuthenticatesNullValues))
+              .Default([&](StringRef Option) {
+                if (size_t WhitespaceIndex =
+                        Option.find_first_of(" \t\n\v\f\r");
+                    WhitespaceIndex != Option.npos) {
+                  StringRef LeadingOption = Option.slice(0, WhitespaceIndex);
+                  S.Diag(AuthenticationOptionsRange.getBegin(),
+                         diag::err_ptrauth_option_missing_comma)
+                      << LeadingOption;
+                } else {
+                  S.Diag(AuthenticationOptionsRange.getBegin(),
+                         diag::err_ptrauth_unknown_authentication_option)
+                      << Option;
+                }
+                return false;
+              });
+      if (!SelectedHandler(Option))
+        IsInvalid = true;
+    }
   }
 
   if (!T->isSignableType(Ctx) && !T->isDependentType()) {
@@ -8491,6 +8620,9 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
     return;
   }
 
+  if (!AuthenticationMode)
+    AuthenticationMode = PointerAuthenticationMode::SignAndAuth;
+
   if (T.getPointerAuth()) {
     S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) << T;
     Attr.setInvalid();
@@ -8503,13 +8635,19 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
     return;
   }
 
+  if (IsInvalid) {
+    Attr.setInvalid();
+    return;
+  }
+
   assert((!IsAddressDiscriminatedArg || IsAddressDiscriminated <= 1) &&
          "address discriminator arg should be either 0 or 1");
   PointerAuthQualifier Qual = PointerAuthQualifier::Create(
-      Key, IsAddressDiscriminated, ExtraDiscriminator,
-      PointerAuthenticationMode::SignAndAuth, /*IsIsaPointer=*/false,
-      /*AuthenticatesNullValues=*/false);
+      Key, IsAddressDiscriminated, ExtraDiscriminator, *AuthenticationMode,
+      IsIsaPointer, AuthenticatesNullValues);
+  assert(Qual.getAuthenticationMode() == *AuthenticationMode);
   T = S.Context.getPointerAuthType(T, Qual);
+  assert(T.getPointerAuth().getAuthenticationMode() == *AuthenticationMode);
 }
 
 /// HandleArmSveVectorBitsTypeAttr - The "arm_sve_vector_bits...
[truncated]

@ojhunt ojhunt closed this Dec 14, 2025
@ojhunt
Copy link
Contributor Author

ojhunt commented Dec 14, 2025

(messed up updating the existing PR)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants