https://github.com/vhscampos updated 
https://github.com/llvm/llvm-project/pull/176171

>From 4f775ae42fbc2729697b32ed5b5310a86f9cbfc4 Mon Sep 17 00:00:00 2001
From: Victor Campos <[email protected]>
Date: Tue, 13 Jan 2026 20:39:02 +0000
Subject: [PATCH 1/3] [Clang][AArch64] Command-line options for A-profile's
 Sign Return Address Hardening

This patch introduces a new command-line option to enable the AArch64
A-profile's Sign Return Address Hardening. It also introduces a new
function attribute with the same naming as the new command-line option.

At the time of this patch, this new option enables the hardening against
the PACMAN attack [1] using a load of the return address [2].

The new option, -mharden-pac-ret, can take one of two values:

 - none: disable hardening. (The default if the option is absent)
 - load-return-address: enables hardening using the mitigation based on
   load of return address.

The corresponding function attribute takes the option and its possible
values using the same naming.

1: https://pacmanattack.com
2: 
https://developer.arm.com/documentation/101754/0624/armclang-Reference/armclang-Command-line-Options/-mharden-pac-ret
---
 .../clang/Basic/DiagnosticDriverKinds.td      |  2 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 +++
 clang/include/clang/Basic/LangOptions.def     |  2 +
 clang/include/clang/Basic/LangOptions.h       | 12 ++++++
 clang/include/clang/Basic/TargetInfo.h        | 22 ++++++++++
 clang/include/clang/Options/Options.td        |  9 ++++
 clang/lib/Basic/Targets/AArch64.cpp           | 16 +++++++
 clang/lib/Basic/Targets/AArch64.h             |  2 +
 clang/lib/CodeGen/TargetInfo.cpp              |  4 ++
 clang/lib/CodeGen/Targets/AArch64.cpp         |  3 ++
 clang/lib/Driver/ToolChains/Clang.cpp         | 22 +++++++++-
 clang/lib/Sema/SemaDeclAttr.cpp               | 18 +++++++-
 .../aarch64-sign-return-address-harden.c      | 13 ++++++
 clang/test/Driver/aarch64-security-options.c  | 30 +++++++++++++
 clang/test/Driver/arm-security-options.c      | 19 ++++++++
 .../Frontend/aarch64-harden-pac-ret-err.c     |  3 ++
 .../aarch64-harden-pac-ret-attr-err-warn.c    | 21 +++++++++
 clang/test/Sema/aarch64-harden-pac-ret-attr.c | 43 +++++++++++++++++++
 18 files changed, 244 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CodeGen/aarch64-sign-return-address-harden.c
 create mode 100644 clang/test/Frontend/aarch64-harden-pac-ret-err.c
 create mode 100644 clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
 create mode 100644 clang/test/Sema/aarch64-harden-pac-ret-attr.c

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td 
b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index db0f521b73544..d16fbd45f104e 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -544,6 +544,8 @@ def warn_ignoring_verify_debuginfo_preserve_export : 
Warning<
   InGroup<UnusedCommandLineArgument>;
 def warn_unsupported_branch_protection: Warning <
   "invalid branch protection option '%0' in '%1'">, InGroup<BranchProtection>;
+def warn_harden_pac_ret_requires_pac_ret: Warning<
+  "ignoring '-mharden-pac-ret' as it requires return address signing">, 
InGroup<UnusedCommandLineArgument>;
 def err_sls_hardening_arm_not_supported : Error<
   "-mharden-sls is only supported on armv7-a or later">;
 def warn_drv_large_data_threshold_invalid_code_model: Warning<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5cbbc7d130c99..fdfe7792441b9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3384,6 +3384,11 @@ def err_invalid_branch_protection_spec : Error<
   "invalid or misplaced branch protection specification '%0'">;
 def warn_unsupported_branch_protection_spec : Warning<
   "unsupported branch protection specification '%0'">, 
InGroup<BranchProtection>;
+def warn_attribute_harden_pac_ret_requires_pac_ret: Warning<
+  "'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' 
attribute ignored">,
+  InGroup<IgnoredAttributes>;
+def err_invalid_harden_pac_ret_spec : Error<
+  "invalid or misplaced pac-ret hardening specification '%0'">;
 def err_attribute_invalid_atomic_argument : Error<
   "invalid argument '%0' to atomic attribute; valid options are: "
   "'remote_memory', 'fine_grained_memory', 'ignore_denormal_mode' (optionally "
diff --git a/clang/include/clang/Basic/LangOptions.def 
b/clang/include/clang/Basic/LangOptions.def
index 8cba1dbaee24e..f3c5613d3dab7 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -454,6 +454,8 @@ ENUM_LANGOPT(SignReturnAddressScope, 
SignReturnAddressScopeKind, 2, SignReturnAd
              "Scope of return address signing")
 ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, 
SignReturnAddressKeyKind::AKey, NotCompatible,
              "Key used for return address signing")
+ENUM_LANGOPT(SignReturnAddressHardening, SignReturnAddressHardeningKind, 1,
+             SignReturnAddressHardeningKind::None, NotCompatible, "Hardening 
of return address signing")
 LANGOPT(BranchTargetEnforcement, 1, 0, NotCompatible, "Branch-target 
enforcement enabled")
 LANGOPT(BranchProtectionPAuthLR, 1, 0, NotCompatible, "Use PC as a diversifier 
using PAuthLR NOP instructions.")
 LANGOPT(GuardedControlStack, 1, 0, NotCompatible, "Guarded control stack 
enabled")
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index ebd0436fa154b..c0e82b3edd2cb 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -299,6 +299,13 @@ class LangOptionsBase {
     BKey
   };
 
+  enum class SignReturnAddressHardeningKind {
+    /// Regular return address signing.
+    None,
+    /// Hardened return address signing with load of return address.
+    LoadReturnAddress
+  };
+
   enum class ThreadModelKind {
     /// POSIX Threads.
     POSIX,
@@ -728,6 +735,11 @@ class LangOptions : public LangOptionsBase {
     return getSignReturnAddressScope() == SignReturnAddressScopeKind::All;
   }
 
+  bool hasSignReturnAddressHardening() const {
+    return getSignReturnAddressHardening() !=
+           SignReturnAddressHardeningKind::None;
+  }
+
   bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
 
   bool hasDefaultVisibilityExportMapping() const {
diff --git a/clang/include/clang/Basic/TargetInfo.h 
b/clang/include/clang/Basic/TargetInfo.h
index 83467b8e93b6a..10779518275b4 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -62,10 +62,12 @@ struct ParsedTargetAttr {
   StringRef CPU;
   StringRef Tune;
   StringRef BranchProtection;
+  StringRef SignReturnAddrHardening;
   StringRef Duplicate;
   bool operator ==(const ParsedTargetAttr &Other) const {
     return Duplicate == Other.Duplicate && CPU == Other.CPU &&
            Tune == Other.Tune && BranchProtection == Other.BranchProtection &&
+           SignReturnAddrHardening == Other.SignReturnAddrHardening &&
            Features == Other.Features;
   }
 };
@@ -1471,6 +1473,7 @@ class TargetInfo : public TransferrableTargetInfo,
   public:
     LangOptions::SignReturnAddressScopeKind SignReturnAddr;
     LangOptions::SignReturnAddressKeyKind SignKey;
+    LangOptions::SignReturnAddressHardeningKind SignReturnAddressHardening;
     bool BranchTargetEnforcement;
     bool BranchProtectionPAuthLR;
     bool GuardedControlStack;
@@ -1497,9 +1500,21 @@ class TargetInfo : public TransferrableTargetInfo,
       llvm_unreachable("Unexpected SignReturnAddressKeyKind");
     }
 
+    const char *getSignReturnAddressHardeningStr() const {
+      switch (SignReturnAddressHardening) {
+      case LangOptions::SignReturnAddressHardeningKind::None:
+        return "none";
+      case LangOptions::SignReturnAddressHardeningKind::LoadReturnAddress:
+        return "load-return-address";
+      }
+      llvm_unreachable("Unexpected SignReturnAddressHardeningKind");
+    }
+
     BranchProtectionInfo()
         : SignReturnAddr(LangOptions::SignReturnAddressScopeKind::None),
           SignKey(LangOptions::SignReturnAddressKeyKind::AKey),
+          SignReturnAddressHardening(
+              LangOptions::SignReturnAddressHardeningKind::None),
           BranchTargetEnforcement(false), BranchProtectionPAuthLR(false),
           GuardedControlStack(false) {}
 
@@ -1513,6 +1528,7 @@ class TargetInfo : public TransferrableTargetInfo,
       SignKey = LangOpts.isSignReturnAddressWithAKey()
                     ? LangOptions::SignReturnAddressKeyKind::AKey
                     : LangOptions::SignReturnAddressKeyKind::BKey;
+      SignReturnAddressHardening = LangOpts.getSignReturnAddressHardening();
       BranchTargetEnforcement = LangOpts.BranchTargetEnforcement;
       BranchProtectionPAuthLR = LangOpts.BranchProtectionPAuthLR;
       GuardedControlStack = LangOpts.GuardedControlStack;
@@ -1535,6 +1551,12 @@ class TargetInfo : public TransferrableTargetInfo,
     return false;
   }
 
+  /// Validate the Return Address Signing Hardening specification
+  virtual std::optional<LangOptions::SignReturnAddressHardeningKind>
+  validateSignReturnAddressHardening(StringRef Spec) const {
+    return std::nullopt;
+  }
+
   /// Perform initialization based on the user configured
   /// set of features (e.g., +sse4).
   ///
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 2f57a5b13b917..3ac001d05be82 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5521,6 +5521,15 @@ def msign_return_address_EQ : Joined<["-"], 
"msign-return-address=">,
   Visibility<[ClangOption, CC1Option]>,
   Group<m_Group>, Values<"none,all,non-leaf">,
   HelpText<"Select return address signing scope">;
+
+def mharden_pac_ret_EQ : Joined<["-"], "mharden-pac-ret=">,
+  Visibility<[ClangOption, CC1Option]>,
+  Flags<[TargetSpecific]>, Group<m_Group>,
+  HelpText<"Select the return address signing hardening scheme. <arg> must be: 
none, load-return-address">,
+  Values<"none,load-return-address">, NormalizedValues<["None", 
"LoadReturnAddress"]>,
+  NormalizedValuesScope<"LangOptions::SignReturnAddressHardeningKind">,
+  MarshallingInfoEnum<LangOpts<"SignReturnAddressHardening">, "None">;
+
 let Flags = [TargetSpecific] in {
 def mbranch_protection_EQ : Joined<["-"], "mbranch-protection=">,
   Group<m_Group>,
diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index fe407e9fc1789..639540fc13d87 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -276,6 +276,17 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef 
Spec, StringRef,
   return true;
 }
 
+std::optional<LangOptions::SignReturnAddressHardeningKind>
+AArch64TargetInfo::validateSignReturnAddressHardening(StringRef Spec) const {
+  assert(!Spec.empty() && "Spec must not be empty");
+  return llvm::StringSwitch<
+             std::optional<LangOptions::SignReturnAddressHardeningKind>>(Spec)
+      .Case("load-return-address",
+            LangOptions::SignReturnAddressHardeningKind::LoadReturnAddress)
+      .Case("none", LangOptions::SignReturnAddressHardeningKind::None)
+      .Default(std::nullopt);
+}
+
 bool AArch64TargetInfo::isValidCPUName(StringRef Name) const {
   return llvm::AArch64::parseCpu(Name).has_value();
 }
@@ -1290,6 +1301,11 @@ ParsedTargetAttr 
AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
       continue;
     }
 
+    if (Feature.starts_with("harden-pac-ret=")) {
+      Ret.SignReturnAddrHardening = Feature.split('=').second.trim();
+      continue;
+    }
+
     if (Feature.starts_with("arch=")) {
       if (FoundArch)
         Ret.Duplicate = "arch=";
diff --git a/clang/lib/Basic/Targets/AArch64.h 
b/clang/lib/Basic/Targets/AArch64.h
index 2d3b8d2a8d950..c0e52319ba628 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -147,6 +147,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public 
TargetInfo {
                                 BranchProtectionInfo &BPI,
                                 const LangOptions &LO,
                                 StringRef &Err) const override;
+  std::optional<LangOptions::SignReturnAddressHardeningKind>
+  validateSignReturnAddressHardening(StringRef Spec) const override;
 
   bool isValidCPUName(StringRef Name) const override;
   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 342a3af0ac1ee..530304f9530ad 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -233,6 +233,10 @@ void TargetCodeGenInfo::setBranchProtectionFnAttributes(
   if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
     F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
     F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr());
+    if (BPI.SignReturnAddressHardening !=
+        LangOptions::SignReturnAddressHardeningKind::None)
+      F.addFnAttr("sign-return-address-harden",
+                  BPI.getSignReturnAddressHardeningStr());
   } else {
     if (F.hasFnAttribute("sign-return-address"))
       F.removeFnAttr("sign-return-address");
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp 
b/clang/lib/CodeGen/Targets/AArch64.cpp
index 963b74927036a..2d197e27dc115 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -160,6 +160,9 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
             Attr.BranchProtection, Attr.CPU, BPI, CGM.getLangOpts(), Error);
         assert(Error.empty());
       }
+      if (!Attr.SignReturnAddrHardening.empty())
+        Fn->addFnAttr("sign-return-address-harden",
+                      Attr.SignReturnAddrHardening);
     }
     setBranchProtectionFnAttributes(BPI, *Fn);
     setPointerAuthFnAttributes(CGM.getCodeGenOpts().PointerAuth, *Fn);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 4ca98600d6e93..f91e1fd367043 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1378,6 +1378,19 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
                      ? Args.getLastArg(options::OPT_msign_return_address_EQ,
                                        options::OPT_mbranch_protection_EQ)
                      : Args.getLastArg(options::OPT_mbranch_protection_EQ);
+  const Arg *HardenPACRetArg = 
Args.getLastArg(options::OPT_mharden_pac_ret_EQ);
+  const Driver &D = TC.getDriver();
+
+  if (HardenPACRetArg) {
+    if (!isAArch64) {
+      D.Diag(diag::err_drv_unsupported_opt_for_target)
+          << HardenPACRetArg->getSpelling() << TC.getTriple().str();
+      return;
+    }
+    if (!A)
+      D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
+  }
+
   if (!A) {
     if (Triple.isOSOpenBSD() && isAArch64) {
       CmdArgs.push_back("-msign-return-address=non-leaf");
@@ -1387,7 +1400,6 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
     return;
   }
 
-  const Driver &D = TC.getDriver();
   if (!(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass())))
     D.Diag(diag::warn_incompatible_branch_protection_option)
         << Triple.getArchName();
@@ -1466,6 +1478,14 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
 
   if (GuardedControlStack)
     CmdArgs.push_back("-mguarded-control-stack");
+
+  if (HardenPACRetArg) {
+    if (Scope == "none")
+      D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
+    else
+      CmdArgs.push_back(Args.MakeArgString(Twine("-mharden-pac-ret=") +
+                                           HardenPACRetArg->getValue()));
+  }
 }
 
 void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index d762bcd789bf5..a514be7fd217f 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3428,8 +3428,11 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, 
StringRef AttrStr) {
 
   TargetInfo::BranchProtectionInfo BPI{};
   StringRef DiagMsg;
-  if (ParsedAttrs.BranchProtection.empty())
+  if (ParsedAttrs.BranchProtection.empty()) {
+    if (!ParsedAttrs.SignReturnAddrHardening.empty())
+      Diag(LiteralLoc, diag::warn_attribute_harden_pac_ret_requires_pac_ret);
     return false;
+  }
   if (!Context.getTargetInfo().validateBranchProtection(
           ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI,
           Context.getLangOpts(), DiagMsg)) {
@@ -3442,6 +3445,19 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, 
StringRef AttrStr) {
   if (!DiagMsg.empty())
     Diag(LiteralLoc, diag::warn_unsupported_branch_protection_spec) << DiagMsg;
 
+  if (!ParsedAttrs.SignReturnAddrHardening.empty()) {
+    auto SignReturnAddrOption =
+        Context.getTargetInfo().validateSignReturnAddressHardening(
+            ParsedAttrs.SignReturnAddrHardening);
+    if (!SignReturnAddrOption)
+      return Diag(LiteralLoc, diag::err_invalid_harden_pac_ret_spec)
+             << ParsedAttrs.SignReturnAddrHardening;
+
+    if (BPI.SignReturnAddr == LangOptions::SignReturnAddressScopeKind::None)
+      return Diag(LiteralLoc,
+                  diag::warn_attribute_harden_pac_ret_requires_pac_ret);
+  }
+
   return false;
 }
 
diff --git a/clang/test/CodeGen/aarch64-sign-return-address-harden.c 
b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
new file mode 100644
index 0000000000000..6d4db64c5efde
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
@@ -0,0 +1,13 @@
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=none \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s 
-mbranch-protection=pac-ret \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s 
-mbranch-protection=pac-ret -mharden-pac-ret=none \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64 -S -emit-llvm -o - %s 
-mbranch-protection=pac-ret -mharden-pac-ret=load-return-address \
+// RUN: | FileCheck %s --check-prefixes=CHECK-HARDEN
+
+void foo() {}
+
+// CHECK-NO-HARDEN-NOT: attributes #0 = {{.*}}"sign-return-address-harden"
+// CHECK-HARDEN:        attributes #0 = 
{{.*}}"sign-return-address-harden"="load-return-address"
\ No newline at end of file
diff --git a/clang/test/Driver/aarch64-security-options.c 
b/clang/test/Driver/aarch64-security-options.c
index 146add2d1cf70..fbcf3d75071c6 100644
--- a/clang/test/Driver/aarch64-security-options.c
+++ b/clang/test/Driver/aarch64-security-options.c
@@ -32,6 +32,36 @@
 
 // WARN-NOT: warning: ignoring '-mbranch-protection=' option because the 
'aarch64' architecture does not support it [-Wbranch-protection]
 
+// RUN: %clang -target aarch64 -c %s -### -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mharden-pac-ret=load-return-address 
2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=none 
-mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=none 
-mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=pac-ret 
-mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-NONE
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=pac-ret 
-mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-NONE
+
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
+
+// NO-RA-HARDEN:        ignoring '-mharden-pac-ret' as it requires return 
address signing
+// NO-RA-HARDEN-NOT:    "-mharden-pac-ret"
+// NO-RA-HARDEN-LRA:    ignoring '-mharden-pac-ret' as it requires return 
address signing
+// RA-HARDEN-NONE:      "-mharden-pac-ret=none"
+// RA-HARDEN-LRA:       "-mharden-pac-ret=load-return-address"
+
 // RA-OFF: "-msign-return-address=none"
 // RA-NON-LEAF: "-msign-return-address=non-leaf"
 // RA-ALL: "-msign-return-address=all"
diff --git a/clang/test/Driver/arm-security-options.c 
b/clang/test/Driver/arm-security-options.c
index 613945c24eede..db1888bec52db 100644
--- a/clang/test/Driver/arm-security-options.c
+++ b/clang/test/Driver/arm-security-options.c
@@ -75,6 +75,23 @@
 // RUN: %clang -target arm-arm-none-eabi -march=armv7-r -c %s -### 
-mbranch-protection=bti 2>&1 | \
 // RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH
 
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8m.main -c %s -### 
-mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### 
-mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### 
-mbranch-protection=bti -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### 
-mbranch-protection=pac-ret -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### 
-mbranch-protection=pac-ret+bti -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### 
-mbranch-protection=pac-ret+leaf -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### 
-msign-return-address=all -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+// RUN: not %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### 
-msign-return-address=non-leaf -mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-HARDEN-INCOMPATIBLE-ARCH
+
 // RA-OFF: "-msign-return-address=none"
 // RA-NON-LEAF: "-msign-return-address=non-leaf"
 // RA-ALL: "-msign-return-address=all"
@@ -91,3 +108,5 @@
 // BAD-LEAF-COMBINATION: unsupported argument 'leaf' to option 
'-mbranch-protection='
 
 // INCOMPATIBLE-ARCH: '-mbranch-protection=' option is incompatible with the 
'{{.*}}' architecture
+
+// RA-HARDEN-INCOMPATIBLE-ARCH: unsupported option '-mharden-pac-ret=' for 
target 'arm-arm-none-eabi'
diff --git a/clang/test/Frontend/aarch64-harden-pac-ret-err.c 
b/clang/test/Frontend/aarch64-harden-pac-ret-err.c
new file mode 100644
index 0000000000000..9fc2cba7e8205
--- /dev/null
+++ b/clang/test/Frontend/aarch64-harden-pac-ret-err.c
@@ -0,0 +1,3 @@
+// RUN: not %clang_cc1 -fsyntax-only -triple aarch64 %s -mharden-pac-ret=foo 
2>&1 | FileCheck %s
+
+// CHECK: invalid value 'foo' in '-mharden-pac-ret=foo'
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c 
b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
new file mode 100644
index 0000000000000..3e218253137d6
--- /dev/null
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple aarch64 -verify -fsyntax-only %s
+
+__attribute__((target("harden-pac-ret=none"))) // expected-warning 
{{'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' 
attribute ignored}}
+void
+badvalue0(void) {}
+
+__attribute__((target("harden-pac-ret=load-return-address"))) // 
expected-warning {{'harden-pac-ret' attribute requires 
'branch-protection=pac-ret'; 'target' attribute ignored}}
+void
+badvalue1(void) {}
+
+__attribute__((target("branch-protection=bti,harden-pac-ret=none"))) // 
expected-warning {{'harden-pac-ret' attribute requires 
'branch-protection=pac-ret'; 'target' attribute ignored}}
+void
+badvalue2(void) {}
+
+__attribute__((target("branch-protection=bti,harden-pac-ret=load-return-address")))
 // expected-warning {{'harden-pac-ret' attribute requires 
'branch-protection=pac-ret'; 'target' attribute ignored}}
+void
+badvalue3(void) {}
+
+__attribute__((target("branch-protection=bti,harden-pac-ret=inexistent"))) // 
expected-error {{invalid or misplaced pac-ret hardening specification 
'inexistent'}}
+void
+badvalue4(void) {}
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr.c 
b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
new file mode 100644
index 0000000000000..c05e33ee28055
--- /dev/null
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm  -target-cpu generic 
-target-feature +v8.5a %s -o - \
+// RUN: | FileCheck %s --check-prefix=CHECK
+
+__attribute__ ((target("branch-protection=pac-ret,harden-pac-ret=none")))
+void f1() {}
+// CHECK: define{{.*}} void @f1() #[[#F1:]]
+
+__attribute__ 
((target("branch-protection=pac-ret,harden-pac-ret=load-return-address")))
+void f2() {}
+// CHECK: define{{.*}} void @f2() #[[#F2:]]
+
+__attribute__ ((target("branch-protection=pac-ret+leaf,harden-pac-ret=none")))
+void f3() {}
+// CHECK: define{{.*}} void @f3() #[[#F3:]]
+
+__attribute__ 
((target("branch-protection=pac-ret+leaf,harden-pac-ret=load-return-address")))
+void f4() {}
+// CHECK: define{{.*}} void @f4() #[[#F4:]]
+
+__attribute__ ((target("branch-protection=pac-ret+b-key,harden-pac-ret=none")))
+void f5() {}
+// CHECK: define{{.*}} void @f5() #[[#F5:]]
+
+__attribute__ 
((target("branch-protection=pac-ret+b-key,harden-pac-ret=load-return-address")))
+void f6() {}
+// CHECK: define{{.*}} void @f6() #[[#F6:]]
+
+__attribute__ 
((target("branch-protection=pac-ret+leaf+b-key,harden-pac-ret=none")))
+void f7() {}
+// CHECK: define{{.*}} void @f7() #[[#F7:]]
+
+__attribute__ 
((target("branch-protection=pac-ret+leaf+b-key,harden-pac-ret=load-return-address")))
+void f8() {}
+// CHECK: define{{.*}} void @f8() #[[#F8:]]
+
+// CHECK-DAG: attributes #[[#F1]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="none"
+// CHECK-DAG: attributes #[[#F2]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="load-return-address"
+// CHECK-DAG: attributes #[[#F3]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="none"
+// CHECK-DAG: attributes #[[#F4]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="load-return-address"
+// CHECK-DAG: attributes #[[#F5]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="none" "sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#F6]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="load-return-address" 
"sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#F7]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="none" "sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#F8]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="load-return-address" 
"sign-return-address-key"="b_key"

>From 97c8d752b6115d3a2e7d6e4c84c35ea0baa641bc Mon Sep 17 00:00:00 2001
From: Victor Campos <[email protected]>
Date: Mon, 13 Apr 2026 11:39:18 +0100
Subject: [PATCH 2/3] Address code reviews

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 clang/include/clang/Basic/LangOptions.h       |   5 -
 clang/include/clang/Basic/TargetInfo.h        |   4 +-
 clang/lib/Basic/Targets/AArch64.cpp           |   3 +-
 clang/lib/Basic/Targets/AArch64.h             |   2 +-
 clang/lib/CodeGen/TargetInfo.cpp              |  13 ++
 clang/lib/CodeGen/Targets/AArch64.cpp         |  13 +-
 clang/lib/Driver/ToolChains/Clang.cpp         | 127 +++++++++---------
 clang/lib/Sema/SemaDeclAttr.cpp               |  12 +-
 .../aarch64-sign-return-address-harden.c      |   8 ++
 clang/test/Driver/aarch64-security-options.c  |  17 ++-
 .../aarch64-harden-pac-ret-attr-err-warn.c    |   2 +-
 clang/test/Sema/aarch64-harden-pac-ret-attr.c |  31 +++--
 13 files changed, 144 insertions(+), 95 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdfe7792441b9..e963eb7d1399b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3388,7 +3388,7 @@ def warn_attribute_harden_pac_ret_requires_pac_ret: 
Warning<
   "'harden-pac-ret' attribute requires 'branch-protection=pac-ret'; 'target' 
attribute ignored">,
   InGroup<IgnoredAttributes>;
 def err_invalid_harden_pac_ret_spec : Error<
-  "invalid or misplaced pac-ret hardening specification '%0'">;
+  "invalid or misspelled pac-ret hardening specification '%0'">;
 def err_attribute_invalid_atomic_argument : Error<
   "invalid argument '%0' to atomic attribute; valid options are: "
   "'remote_memory', 'fine_grained_memory', 'ignore_denormal_mode' (optionally "
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index c0e82b3edd2cb..bc7deae9c5122 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -735,11 +735,6 @@ class LangOptions : public LangOptionsBase {
     return getSignReturnAddressScope() == SignReturnAddressScopeKind::All;
   }
 
-  bool hasSignReturnAddressHardening() const {
-    return getSignReturnAddressHardening() !=
-           SignReturnAddressHardeningKind::None;
-  }
-
   bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
 
   bool hasDefaultVisibilityExportMapping() const {
diff --git a/clang/include/clang/Basic/TargetInfo.h 
b/clang/include/clang/Basic/TargetInfo.h
index 10779518275b4..7d64a9d7bd4bb 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1551,9 +1551,9 @@ class TargetInfo : public TransferrableTargetInfo,
     return false;
   }
 
-  /// Validate the Return Address Signing Hardening specification
+  /// Parse the Return Address Signing Hardening specification.
   virtual std::optional<LangOptions::SignReturnAddressHardeningKind>
-  validateSignReturnAddressHardening(StringRef Spec) const {
+  parseSignReturnAddressHardening(StringRef Spec) const {
     return std::nullopt;
   }
 
diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index 639540fc13d87..da10cd384b963 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -277,8 +277,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef 
Spec, StringRef,
 }
 
 std::optional<LangOptions::SignReturnAddressHardeningKind>
-AArch64TargetInfo::validateSignReturnAddressHardening(StringRef Spec) const {
-  assert(!Spec.empty() && "Spec must not be empty");
+AArch64TargetInfo::parseSignReturnAddressHardening(StringRef Spec) const {
   return llvm::StringSwitch<
              std::optional<LangOptions::SignReturnAddressHardeningKind>>(Spec)
       .Case("load-return-address",
diff --git a/clang/lib/Basic/Targets/AArch64.h 
b/clang/lib/Basic/Targets/AArch64.h
index c0e52319ba628..9312b785dd20b 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -148,7 +148,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public 
TargetInfo {
                                 const LangOptions &LO,
                                 StringRef &Err) const override;
   std::optional<LangOptions::SignReturnAddressHardeningKind>
-  validateSignReturnAddressHardening(StringRef Spec) const override;
+  parseSignReturnAddressHardening(StringRef Spec) const override;
 
   bool isValidCPUName(StringRef Name) const override;
   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 530304f9530ad..9e0b7bb709cc9 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -230,6 +230,7 @@ void TargetCodeGenInfo::setBranchProtectionFnAttributes(
   // Called on already created and initialized function where attributes 
already
   // set from command line attributes but some might need to be removed as the
   // actual BPI is different.
+
   if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
     F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
     F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr());
@@ -244,6 +245,14 @@ void TargetCodeGenInfo::setBranchProtectionFnAttributes(
       F.removeFnAttr("sign-return-address-key");
   }
 
+  if (BPI.SignReturnAddressHardening ==
+      LangOptions::SignReturnAddressHardeningKind::None) {
+    F.removeFnAttr("sign-return-address-harden");
+  } else {
+    F.addFnAttr("sign-return-address-harden",
+                BPI.getSignReturnAddressHardeningStr());
+  }
+
   auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) {
     if (Set)
       F.addFnAttr(ModAttr);
@@ -266,6 +275,10 @@ void TargetCodeGenInfo::initBranchProtectionFnAttributes(
     FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr());
     FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr());
   }
+  if (BPI.SignReturnAddressHardening !=
+      LangOptions::SignReturnAddressHardeningKind::None)
+    FuncAttrs.addAttribute("sign-return-address-harden",
+                           BPI.getSignReturnAddressHardeningStr());
   if (BPI.BranchTargetEnforcement)
     FuncAttrs.addAttribute("branch-target-enforcement");
   if (BPI.BranchProtectionPAuthLR)
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp 
b/clang/lib/CodeGen/Targets/AArch64.cpp
index 2d197e27dc115..87219df5cbc83 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -159,10 +159,17 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo 
{
         (void)CGM.getTarget().validateBranchProtection(
             Attr.BranchProtection, Attr.CPU, BPI, CGM.getLangOpts(), Error);
         assert(Error.empty());
+
+        // Hardening is only accepted in the target attribute if PAC-RET is 
also
+        // present there. Invalid combinations are handled in Sema.
+        if (BPI.SignReturnAddr !=
+            LangOptions::SignReturnAddressScopeKind::None) {
+          if (auto Hardening = CGM.getTarget().parseSignReturnAddressHardening(
+                  Attr.SignReturnAddrHardening)) {
+            BPI.SignReturnAddressHardening = *Hardening;
+          }
+        }
       }
-      if (!Attr.SignReturnAddrHardening.empty())
-        Fn->addFnAttr("sign-return-address-harden",
-                      Attr.SignReturnAddrHardening);
     }
     setBranchProtectionFnAttributes(BPI, *Fn);
     setPointerAuthFnAttributes(CGM.getCodeGenOpts().PointerAuth, *Fn);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index f91e1fd367043..ed200b6ec3ec9 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1381,79 +1381,85 @@ static void CollectARMPACBTIOptions(const ToolChain 
&TC, const ArgList &Args,
   const Arg *HardenPACRetArg = 
Args.getLastArg(options::OPT_mharden_pac_ret_EQ);
   const Driver &D = TC.getDriver();
 
+  // Check CmdArgs because some toolchains bypass the driver args and add to
+  // the frontend args directly.
+  bool HasPtrauthReturns = llvm::is_contained(CmdArgs, "-fptrauth-returns") ||
+                           Args.hasArgNoClaim(options::OPT_fno_ptrauth_returns,
+                                              options::OPT_fptrauth_returns);
+
   if (HardenPACRetArg) {
     if (!isAArch64) {
       D.Diag(diag::err_drv_unsupported_opt_for_target)
           << HardenPACRetArg->getSpelling() << TC.getTriple().str();
       return;
     }
-    if (!A)
-      D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
+    StringRef ArgValue = HardenPACRetArg->getValue();
+    if (ArgValue != "none" && ArgValue != "load-return-address") {
+      D.Diag(diag::err_drv_unsupported_option_argument)
+          << HardenPACRetArg->getSpelling() << ArgValue;
+      return;
+    }
   }
 
-  if (!A) {
-    if (Triple.isOSOpenBSD() && isAArch64) {
-      CmdArgs.push_back("-msign-return-address=non-leaf");
-      CmdArgs.push_back("-msign-return-address-key=a_key");
-      CmdArgs.push_back("-mbranch-target-enforce");
-    }
+  if (!A && Triple.isOSOpenBSD() && isAArch64) {
+    CmdArgs.push_back("-msign-return-address=non-leaf");
+    CmdArgs.push_back("-msign-return-address-key=a_key");
+    CmdArgs.push_back("-mbranch-target-enforce");
     return;
   }
 
-  if (!(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass())))
+  if (A && !(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass())))
     D.Diag(diag::warn_incompatible_branch_protection_option)
         << Triple.getArchName();
 
-  StringRef Scope, Key;
-  bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack;
-
-  if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
-    Scope = A->getValue();
-    if (Scope != "none" && Scope != "non-leaf" && Scope != "all")
-      D.Diag(diag::err_drv_unsupported_option_argument)
-          << A->getSpelling() << Scope;
-    Key = "a_key";
-    IndirectBranches = Triple.isOSOpenBSD() && isAArch64;
-    BranchProtectionPAuthLR = false;
-    GuardedControlStack = false;
-  } else {
-    StringRef DiagMsg;
-    llvm::ARM::ParsedBranchProtection PBP;
-    bool EnablePAuthLR = false;
-
-    // To know if we need to enable PAuth-LR As part of the standard branch
-    // protection option, it needs to be determined if the feature has been
-    // activated in the `march` argument. This information is stored within the
-    // CmdArgs variable and can be found using a search.
-    if (isAArch64) {
-      auto isPAuthLR = [](const char *member) {
-        llvm::AArch64::ExtensionInfo pauthlr_extension =
-            llvm::AArch64::getExtensionByID(llvm::AArch64::AEK_PAUTHLR);
-        return pauthlr_extension.PosTargetFeature == member;
-      };
+  StringRef Scope = "none", Key;
+  bool IndirectBranches = false, BranchProtectionPAuthLR = false,
+       GuardedControlStack = false;
 
-      if (llvm::any_of(CmdArgs, isPAuthLR))
-        EnablePAuthLR = true;
+  if (A) {
+    if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
+      Scope = A->getValue();
+      if (Scope != "none" && Scope != "non-leaf" && Scope != "all")
+        D.Diag(diag::err_drv_unsupported_option_argument)
+            << A->getSpelling() << Scope;
+      Key = "a_key";
+      IndirectBranches = Triple.isOSOpenBSD() && isAArch64;
+      BranchProtectionPAuthLR = false;
+      GuardedControlStack = false;
+    } else {
+      StringRef DiagMsg;
+      llvm::ARM::ParsedBranchProtection PBP;
+      bool EnablePAuthLR = false;
+
+      // To know if we need to enable PAuth-LR As part of the standard branch
+      // protection option, it needs to be determined if the feature has been
+      // activated in the `march` argument. This information is stored within
+      // the CmdArgs variable and can be found using a search.
+      if (isAArch64) {
+        auto isPAuthLR = [](const char *member) {
+          llvm::AArch64::ExtensionInfo pauthlr_extension =
+              llvm::AArch64::getExtensionByID(llvm::AArch64::AEK_PAUTHLR);
+          return pauthlr_extension.PosTargetFeature == member;
+        };
+
+        if (llvm::any_of(CmdArgs, isPAuthLR))
+          EnablePAuthLR = true;
+      }
+      if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg,
+                                            EnablePAuthLR))
+        D.Diag(diag::err_drv_unsupported_option_argument)
+            << A->getSpelling() << DiagMsg;
+      if (!isAArch64 && PBP.Key == "b_key")
+        D.Diag(diag::warn_unsupported_branch_protection)
+            << "b-key" << A->getAsString(Args);
+      Scope = PBP.Scope;
+      Key = PBP.Key;
+      BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
+      IndirectBranches = PBP.BranchTargetEnforcement;
+      GuardedControlStack = PBP.GuardedControlStack;
     }
-    if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg,
-                                          EnablePAuthLR))
-      D.Diag(diag::err_drv_unsupported_option_argument)
-          << A->getSpelling() << DiagMsg;
-    if (!isAArch64 && PBP.Key == "b_key")
-      D.Diag(diag::warn_unsupported_branch_protection)
-          << "b-key" << A->getAsString(Args);
-    Scope = PBP.Scope;
-    Key = PBP.Key;
-    BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
-    IndirectBranches = PBP.BranchTargetEnforcement;
-    GuardedControlStack = PBP.GuardedControlStack;
-  }
-
-  Arg *PtrauthReturnsArg = Args.getLastArg(options::OPT_fptrauth_returns,
-                                           options::OPT_fno_ptrauth_returns);
-  bool HasPtrauthReturns =
-      PtrauthReturnsArg &&
-      PtrauthReturnsArg->getOption().matches(options::OPT_fptrauth_returns);
+  }
+
   // GCS is currently untested with ptrauth-returns, but enabling this could be
   // allowed in future after testing with a suitable system.
   if (Scope != "none" || BranchProtectionPAuthLR || GuardedControlStack) {
@@ -1465,8 +1471,9 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
           << A->getAsString(Args) << "-fptrauth-returns";
   }
 
-  CmdArgs.push_back(
-      Args.MakeArgString(Twine("-msign-return-address=") + Scope));
+  if (A)
+    CmdArgs.push_back(
+        Args.MakeArgString(Twine("-msign-return-address=") + Scope));
   if (Scope != "none")
     CmdArgs.push_back(
         Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
@@ -1480,7 +1487,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
     CmdArgs.push_back("-mguarded-control-stack");
 
   if (HardenPACRetArg) {
-    if (Scope == "none")
+    if (Scope == "none" && !HasPtrauthReturns)
       D.Diag(diag::warn_harden_pac_ret_requires_pac_ret);
     else
       CmdArgs.push_back(Args.MakeArgString(Twine("-mharden-pac-ret=") +
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index a514be7fd217f..9118f7bef778e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3426,13 +3426,15 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, 
StringRef AttrStr) {
              << Unsupported << None << CurFeature << Target;
   }
 
-  TargetInfo::BranchProtectionInfo BPI{};
-  StringRef DiagMsg;
   if (ParsedAttrs.BranchProtection.empty()) {
     if (!ParsedAttrs.SignReturnAddrHardening.empty())
       Diag(LiteralLoc, diag::warn_attribute_harden_pac_ret_requires_pac_ret);
     return false;
   }
+
+  TargetInfo::BranchProtectionInfo BPI{};
+  StringRef DiagMsg;
+
   if (!Context.getTargetInfo().validateBranchProtection(
           ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI,
           Context.getLangOpts(), DiagMsg)) {
@@ -3446,10 +3448,10 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, 
StringRef AttrStr) {
     Diag(LiteralLoc, diag::warn_unsupported_branch_protection_spec) << DiagMsg;
 
   if (!ParsedAttrs.SignReturnAddrHardening.empty()) {
-    auto SignReturnAddrOption =
-        Context.getTargetInfo().validateSignReturnAddressHardening(
+    auto SignReturnAddrHardenOpt =
+        Context.getTargetInfo().parseSignReturnAddressHardening(
             ParsedAttrs.SignReturnAddrHardening);
-    if (!SignReturnAddrOption)
+    if (!SignReturnAddrHardenOpt)
       return Diag(LiteralLoc, diag::err_invalid_harden_pac_ret_spec)
              << ParsedAttrs.SignReturnAddrHardening;
 
diff --git a/clang/test/CodeGen/aarch64-sign-return-address-harden.c 
b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
index 6d4db64c5efde..4b078bbc367b3 100644
--- a/clang/test/CodeGen/aarch64-sign-return-address-harden.c
+++ b/clang/test/CodeGen/aarch64-sign-return-address-harden.c
@@ -1,11 +1,19 @@
 // RUN: %clang -target aarch64 -S -emit-llvm -o - %s -mbranch-protection=none \
 // RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s 
-fno-ptrauth-returns \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
 // RUN: %clang -target aarch64 -S -emit-llvm -o - %s 
-mbranch-protection=pac-ret \
 // RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s 
-fptrauth-returns \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
 // RUN: %clang -target aarch64 -S -emit-llvm -o - %s 
-mbranch-protection=pac-ret -mharden-pac-ret=none \
 // RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s 
-fptrauth-returns -mharden-pac-ret=none \
+// RUN: | FileCheck %s --check-prefixes=CHECK-NO-HARDEN
 // RUN: %clang -target aarch64 -S -emit-llvm -o - %s 
-mbranch-protection=pac-ret -mharden-pac-ret=load-return-address \
 // RUN: | FileCheck %s --check-prefixes=CHECK-HARDEN
+// RUN: %clang -target aarch64-linux-pauthtest -S -emit-llvm -o - %s 
-fptrauth-returns -mharden-pac-ret=load-return-address \
+// RUN: | FileCheck %s --check-prefixes=CHECK-HARDEN
 
 void foo() {}
 
diff --git a/clang/test/Driver/aarch64-security-options.c 
b/clang/test/Driver/aarch64-security-options.c
index fbcf3d75071c6..321205abd8e1a 100644
--- a/clang/test/Driver/aarch64-security-options.c
+++ b/clang/test/Driver/aarch64-security-options.c
@@ -32,6 +32,9 @@
 
 // WARN-NOT: warning: ignoring '-mbranch-protection=' option because the 
'aarch64' architecture does not support it [-Wbranch-protection]
 
+// RUN: %clang -target aarch64 -c %s -### 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=ABSENT-RA-HARDEN
+
 // RUN: %clang -target aarch64 -c %s -### -mharden-pac-ret=none 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
 
@@ -56,11 +59,15 @@
 // RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=load-return-address 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
 
-// NO-RA-HARDEN:        ignoring '-mharden-pac-ret' as it requires return 
address signing
-// NO-RA-HARDEN-NOT:    "-mharden-pac-ret"
-// NO-RA-HARDEN-LRA:    ignoring '-mharden-pac-ret' as it requires return 
address signing
-// RA-HARDEN-NONE:      "-mharden-pac-ret=none"
-// RA-HARDEN-LRA:       "-mharden-pac-ret=load-return-address"
+// RUN: not %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=foo 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=BAD-HARDEN-PROTECTION
+
+// ABSENT-RA-HARDEN-NOT: "-mharden-pac-ret"
+// NO-RA-HARDEN:         ignoring '-mharden-pac-ret' as it requires return 
address signing
+// NO-RA-HARDEN-NOT:     "-mharden-pac-ret"
+// RA-HARDEN-NONE:       "-mharden-pac-ret=none"
+// RA-HARDEN-LRA:        "-mharden-pac-ret=load-return-address"
+// BAD-HARDEN-PROTECTION: unsupported argument 'foo' to option 
'-mharden-pac-ret='
 
 // RA-OFF: "-msign-return-address=none"
 // RA-NON-LEAF: "-msign-return-address=non-leaf"
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c 
b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
index 3e218253137d6..a98a80c85c819 100644
--- a/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr-err-warn.c
@@ -16,6 +16,6 @@ 
__attribute__((target("branch-protection=bti,harden-pac-ret=load-return-address"
 void
 badvalue3(void) {}
 
-__attribute__((target("branch-protection=bti,harden-pac-ret=inexistent"))) // 
expected-error {{invalid or misplaced pac-ret hardening specification 
'inexistent'}}
+__attribute__((target("branch-protection=bti,harden-pac-ret=inexistent"))) // 
expected-error {{invalid or misspelled pac-ret hardening specification 
'inexistent'}}
 void
 badvalue4(void) {}
diff --git a/clang/test/Sema/aarch64-harden-pac-ret-attr.c 
b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
index c05e33ee28055..28795003e3a5b 100644
--- a/clang/test/Sema/aarch64-harden-pac-ret-attr.c
+++ b/clang/test/Sema/aarch64-harden-pac-ret-attr.c
@@ -1,5 +1,8 @@
-// RUN: %clang_cc1 -triple aarch64 -emit-llvm  -target-cpu generic 
-target-feature +v8.5a %s -o - \
-// RUN: | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic 
-target-feature +v8.5a %s -o - | FileCheck %s
+
+// The following test that the function attributes take precedence over 
command-line options
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic 
-target-feature +v8.5a %s -msign-return-address=all -mharden-pac-ret=none -o - 
| FileCheck %s
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -target-cpu generic 
-target-feature +v8.5a %s -msign-return-address=all 
-mharden-pac-ret=load-return-address -o - | FileCheck %s
 
 __attribute__ ((target("branch-protection=pac-ret,harden-pac-ret=none")))
 void f1() {}
@@ -33,11 +36,19 @@ __attribute__ 
((target("branch-protection=pac-ret+leaf+b-key,harden-pac-ret=load
 void f8() {}
 // CHECK: define{{.*}} void @f8() #[[#F8:]]
 
-// CHECK-DAG: attributes #[[#F1]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="none"
-// CHECK-DAG: attributes #[[#F2]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="load-return-address"
-// CHECK-DAG: attributes #[[#F3]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="none"
-// CHECK-DAG: attributes #[[#F4]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="load-return-address"
-// CHECK-DAG: attributes #[[#F5]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="none" "sign-return-address-key"="b_key"
-// CHECK-DAG: attributes #[[#F6]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="load-return-address" 
"sign-return-address-key"="b_key"
-// CHECK-DAG: attributes #[[#F7]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="none" "sign-return-address-key"="b_key"
-// CHECK-DAG: attributes #[[#F8]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="load-return-address" 
"sign-return-address-key"="b_key"
+// These check patterns rely on the fact that "sign-return-address-harden" 
appears after "sign-return-address"
+
+// CHECK:     attributes #[[#F1]] = { {{.*}} "sign-return-address"="non-leaf"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK:     attributes #[[#F2]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="load-return-address"
+// CHECK:     attributes #[[#F3]] = { {{.*}} "sign-return-address"="all"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK:     attributes #[[#F4]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="load-return-address"
+// CHECK:     attributes #[[#F5]] = { {{.*}} "sign-return-address"="non-leaf"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK:     "sign-return-address-key"="b_key"
+// CHECK:     attributes #[[#F6]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-harden"="load-return-address" 
"sign-return-address-key"="b_key"
+// CHECK:     attributes #[[#F7]] = { {{.*}} "sign-return-address"="all"
+// CHECK-NOT: "sign-return-address-harden"
+// CHECK:     "sign-return-address-key"="b_key"
+// CHECK:     attributes #[[#F8]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-harden"="load-return-address" 
"sign-return-address-key"="b_key"

>From 63514f49bd2b1cf82f7d924c62ba12ff12ac7e29 Mon Sep 17 00:00:00 2001
From: Victor Campos <[email protected]>
Date: Thu, 16 Jul 2026 14:58:12 +0100
Subject: [PATCH 3/3] Changes:  - Emit error if
 -mharden-pac-ret=load-return-address is used alongside -mexecute-only.  - Add
 driver tests for the point above and also for the use of hardening with
 -fptrauth-returns.  - Create new doc page for the feature.

---
 clang/docs/ReturnAddressSigningHardening.rst | 178 +++++++++++++++++++
 clang/docs/index.rst                         |   2 +-
 clang/include/clang/Options/Options.td       |   2 +-
 clang/lib/Driver/ToolChains/Clang.cpp        |  14 +-
 clang/test/Driver/aarch64-security-options.c |  20 +++
 5 files changed, 211 insertions(+), 5 deletions(-)
 create mode 100644 clang/docs/ReturnAddressSigningHardening.rst

diff --git a/clang/docs/ReturnAddressSigningHardening.rst 
b/clang/docs/ReturnAddressSigningHardening.rst
new file mode 100644
index 0000000000000..063132d6e6f0b
--- /dev/null
+++ b/clang/docs/ReturnAddressSigningHardening.rst
@@ -0,0 +1,178 @@
+##################################
+ Return Address Signing Hardening
+##################################
+
+.. contents::
+   :local:
+
+**************
+ Introduction
+**************
+
+Return Address Signing Hardening is a mitigation against the PACMAN
+attack, which aims to bypass Pointer Authentication on AArch64 targets.
+The hardening mechanism described here is specific to pointer
+authentication of return addresses.
+
+Return Address Signing, also known as Pointer Authentication Code
+(PAC-RET), is a feature devised to protect programs against Return
+Oriented Programming (ROP), in which attackers may hijack the return
+address of functions in order to direct execution to malicious code.
+
+PAC-RET can be enabled via different command-line options:
+
+   -  ``-mbranch-protection=`` with ``pac-ret``, ``pac-ret+leaf`` or
+      ``standard`` as value.
+   -  ``-msign-return-address=`` with ``non-leaf`` or ``all`` as value.
+   -  ``-fptrauth-returns``.
+
+More information can be found in :doc:`Pointer Authentication
+<PointerAuthentication>`.
+
+Return Address Signing Hardening is a mechanism to strenghthen Return
+Address Signing against the PACMAN attack in AArch64 targets. It can be
+enabled with ``-mharden-pac-ret=load-return-address``.
+
+***************
+ PACMAN attack
+***************
+
+PACMAN is an attack that aims to extract valuable information about
+pointer authentication codes using side-channels in speculative
+execution.
+
+It is performed with the use of gadgets to try and guess PAC codes.
+These guesses raise no faults because they are done in speculation. By
+observing the effects of the guessed PAC code on the processor's cache,
+it might be possible to determine the valid PAC code for the address to
+which the attacker wants the program to return.
+
+A usual PACMAN gadget looks like this:
+
+.. code:: C
+
+   void function() {
+     ...
+     if (condition)
+       return;
+     ...
+   }
+
+Such code would be compiled to:
+
+.. code:: asm
+
+   paciasp
+   ...
+   cbz w0, .LBB0_2
+   autiasp
+   ret
+   ...
+
+This code segment may be used as a gadget. A speculative execution of
+this segment can happen as follows:
+
+   -  If the Link Register (LR) has the right PAC code, ``autiasp`` will
+      succeed and strip the PAC code out of the it. The processor's
+      instruction fetcher will then bring the code after the return into
+      the cache (that is, the instructions located at the address
+      pointed by LR).
+
+   -  If the LR has the wrong PAC code, ``autiasp`` will not succeed and
+      hence will write a predefined error value to the LR's higher bits.
+      Because of this, the instruction fetcher will not bring the code
+      after the return into the cache.
+
+This difference in behavior is what drives the PACMAN attack. An
+attacker can try to guess PAC codes and monitor cache behavior until the
+code after the return is observed to have been brought into the cache.
+
+Details can be found in https://pacmanattack.com.
+
+***********
+ Hardening
+***********
+
+In order to mitigate the PACMAN attack, a hardening mechanism can be
+enabled with ``-mharden-pac-ret=load-return-address``.
+
+.. code:: asm
+
+   paciasp
+   ...
+   cbz w0, .LBB0_2
+   autiasp
+   mov     x8, x30
+   xpaclri
+   ldr     w30, [x30]
+   ret     x8
+   ...
+
+The idea is to always bring the code after the return into cache (the
+instructions located at the address pointed by LR), therefore minimizing
+the difference between a speculative execution with a correct PAC code
+and with an incorrect one.
+
+   -  ``autiasp`` performs the authentication step.
+   -  ``mov x8, x30`` copies the return address (LR and x30 are
+      synonyms) to a temporary.
+   -  ``xpaclri`` strips the PAC code out of the return address in x30.
+   -  ``ldr w30, [x30]`` performs a load of the return address in x30.
+   -  ``ret x8`` returns to the authenticated return address.
+
+The load operation brings the code into the cache even if the
+authentication step fails. As a consequence, in either case the code is
+loaded into the cache. Furthermore, the return operation uses the
+original return address before stripping, so the return address
+protection is still kept in place in a normal non-speculative execution.
+
+If FEAT_PAUTH is present, the code sequence can use instructions only
+available with said feature with no change in semantics:
+
+.. code:: asm
+
+   autiasp
+   mov     x8, x30
+   xpaci   x8
+   ldr     w8, [x8]
+   ret
+
+*********************
+ Command-line option
+*********************
+
+Return address signing hardening can be enabled at module level with
+``-mharden-pac-ret=load-return-address``. It requires PAC-RET to be
+enabled at module level as well.
+
+********************
+ Function attribute
+********************
+
+In addition to the command-line option
+``-mharden-pac-ret=load-return-address``, the developer can enable the
+mitigation at function level with the use of the corresponding function
+attribute.
+
+.. code:: C
+
+   
__attribute__((target("branch-protection=pac-ret,harden-pac-ret=load-return-address")))
+   void function()  {
+     ...
+   }
+
+*********
+ Caveats
+*********
+
+The load of return address brings the code into the shared
+instruction/data cache, therefore this cache level can't be used as an
+oracle to find out whether the authentication succeeded or not. However,
+in the case of authentication success, the code is also fetched into the
+instruction cache. An attacker who is able to measure this cache level
+specifically may still be able to carry out the exploit.
+
+Another caveat is if the code at the return address contains a load
+operation within the speculation window. If this is the case, this load
+will only execute speculatively if authentication succeeds, thus opening
+the program up for exploitation despite the mitigation.
diff --git a/clang/docs/index.rst b/clang/docs/index.rst
index 70c8737a2fe0d..92120f9559a93 100644
--- a/clang/docs/index.rst
+++ b/clang/docs/index.rst
@@ -47,6 +47,7 @@ Using Clang as a Compiler
    ControlFlowIntegrity
    LTOVisibility
    PointerAuthentication
+   ReturnAddressSigningHardening
    SafeStack
    ShadowCallStack
    SourceBasedCodeCoverage
@@ -128,4 +129,3 @@ Indices and tables
 
 * :ref:`genindex`
 * :ref:`search`
-
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 3ac001d05be82..4268f0530816f 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5525,7 +5525,7 @@ def msign_return_address_EQ : Joined<["-"], 
"msign-return-address=">,
 def mharden_pac_ret_EQ : Joined<["-"], "mharden-pac-ret=">,
   Visibility<[ClangOption, CC1Option]>,
   Flags<[TargetSpecific]>, Group<m_Group>,
-  HelpText<"Select the return address signing hardening scheme. <arg> must be: 
none, load-return-address">,
+  HelpText<"Select the return address signing hardening scheme">,
   Values<"none,load-return-address">, NormalizedValues<["None", 
"LoadReturnAddress"]>,
   NormalizedValuesScope<"LangOptions::SignReturnAddressHardeningKind">,
   MarshallingInfoEnum<LangOpts<"SignReturnAddressHardening">, "None">;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index ed200b6ec3ec9..a1ba6f5aed527 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1383,9 +1383,10 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
 
   // Check CmdArgs because some toolchains bypass the driver args and add to
   // the frontend args directly.
-  bool HasPtrauthReturns = llvm::is_contained(CmdArgs, "-fptrauth-returns") ||
-                           Args.hasArgNoClaim(options::OPT_fno_ptrauth_returns,
-                                              options::OPT_fptrauth_returns);
+  bool HasPtrauthReturns =
+      llvm::is_contained(CmdArgs, "-fptrauth-returns") ||
+      Args.hasFlagNoClaim(options::OPT_fptrauth_returns,
+                          options::OPT_fno_ptrauth_returns, false);
 
   if (HardenPACRetArg) {
     if (!isAArch64) {
@@ -1399,6 +1400,13 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
           << HardenPACRetArg->getSpelling() << ArgValue;
       return;
     }
+    if (ArgValue != "none" &&
+        Args.hasFlagNoClaim(options::OPT_mexecute_only,
+                            options::OPT_mno_execute_only, false)) {
+      D.Diag(diag::err_drv_incompatible_options)
+          << HardenPACRetArg->getAsString(Args) << "-mexecute-only";
+      return;
+    }
   }
 
   if (!A && Triple.isOSOpenBSD() && isAArch64) {
diff --git a/clang/test/Driver/aarch64-security-options.c 
b/clang/test/Driver/aarch64-security-options.c
index 321205abd8e1a..dbac73d1f9769 100644
--- a/clang/test/Driver/aarch64-security-options.c
+++ b/clang/test/Driver/aarch64-security-options.c
@@ -13,6 +13,9 @@
 // RUN: %clang --target=aarch64 -c %s -### -mbranch-protection=standard        
                        2>&1 | \
 // RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A 
--check-prefix=BTE-ON --check-prefix=GCS-ON --check-prefix=WARN
 
+// RUN: not %clang -target arm64-apple-darwin -c %s -### 
-mbranch-protection=standard -fptrauth-returns 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-INCOMPATIBLE-PTRAUTHRETURNS
+
 // If the -msign-return-address and -mbranch-protection are both used, the
 // right-most one controls return address signing.
 // RUN: %clang --target=aarch64 -c %s -### -msign-return-address=non-leaf 
-mbranch-protection=none     2>&1 | \
@@ -43,15 +46,23 @@
 
 // RUN: %clang -target aarch64 -c %s -### -mbranch-protection=none 
-mharden-pac-ret=none 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+// RUN: %clang -target arm64-apple-darwin -c %s -### -fno-ptrauth-returns 
-mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
 
 // RUN: %clang -target aarch64 -c %s -### -mbranch-protection=none 
-mharden-pac-ret=load-return-address 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
+// RUN: %clang -target arm64-apple-darwin -c %s -### -fno-ptrauth-returns 
-mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=NO-RA-HARDEN
 
 // RUN: %clang -target aarch64 -c %s -### -mbranch-protection=pac-ret 
-mharden-pac-ret=none 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=RA-HARDEN-NONE
+// RUN: %clang -target arm64-apple-darwin -c %s -### -fptrauth-returns 
-mharden-pac-ret=none 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-NONE
 
 // RUN: %clang -target aarch64 -c %s -### -mbranch-protection=pac-ret 
-mharden-pac-ret=load-return-address 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
+// RUN: %clang -target arm64-apple-darwin -c %s -### -fptrauth-returns 
-mharden-pac-ret=load-return-address 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-LRA
 
 // RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=none 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=RA-HARDEN-NONE
@@ -61,6 +72,12 @@
 
 // RUN: not %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=foo 2>&1 | \
 // RUN: FileCheck %s --check-prefixes=BAD-HARDEN-PROTECTION
+// RUN: not %clang -target arm64-apple-darwin -c %s -### -fptrauth-returns 
-mharden-pac-ret=foo 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=BAD-HARDEN-PROTECTION
+
+// RUN: not %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=load-return-address -mexecute-only 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=RA-HARDEN-INCOMPATIBLE-EXEC-ONLY
+// RUN: %clang -target aarch64 -c %s -### -mbranch-protection=standard 
-mharden-pac-ret=none -mexecute-only
 
 // ABSENT-RA-HARDEN-NOT: "-mharden-pac-ret"
 // NO-RA-HARDEN:         ignoring '-mharden-pac-ret' as it requires return 
address signing
@@ -68,6 +85,7 @@
 // RA-HARDEN-NONE:       "-mharden-pac-ret=none"
 // RA-HARDEN-LRA:        "-mharden-pac-ret=load-return-address"
 // BAD-HARDEN-PROTECTION: unsupported argument 'foo' to option 
'-mharden-pac-ret='
+// RA-HARDEN-INCOMPATIBLE-EXEC-ONLY: the combination of 
'-mharden-pac-ret=load-return-address' and '-mexecute-only' is incompatible
 
 // RA-OFF: "-msign-return-address=none"
 // RA-NON-LEAF: "-msign-return-address=non-leaf"
@@ -76,6 +94,8 @@
 // KEY-A: "-msign-return-address-key=a_key"
 // KEY-NOT: "-msign-return-address-key"
 
+// RA-INCOMPATIBLE-PTRAUTHRETURNS: the combination of 
'-mbranch-protection=standard' and '-fptrauth-returns' is incompatible
+
 // BTE-OFF-NOT: "-mbranch-target-enforce"
 // BTE-ON: "-mbranch-target-enforce"
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to