llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Oliver Hunt (ojhunt)

<details>
<summary>Changes</summary>

When records contain fields with pointer authentication, even simple copies can 
require
additional work be performed. This patch contains the core functionality 
required to
handle user defined structs, as well as the implicitly constructed structs for 
blocks, etc.

Co-authored-by: Ahmed Bougacha
Co-authored-by: Akira Hatanaka
Co-authored-by: John Mccall

---

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


13 Files Affected:

- (modified) clang/include/clang/AST/NonTrivialTypeVisitor.h (+2) 
- (modified) clang/include/clang/AST/Type.h (+3) 
- (modified) clang/lib/AST/ASTContext.cpp (+3) 
- (modified) clang/lib/AST/Type.cpp (+6) 
- (modified) clang/lib/CodeGen/CGBlocks.cpp (+55-1) 
- (modified) clang/lib/CodeGen/CGBlocks.h (+1) 
- (modified) clang/lib/CodeGen/CGCall.cpp (+1-1) 
- (modified) clang/lib/CodeGen/CGNonTrivialStruct.cpp (+19) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+3) 
- (modified) clang/lib/Sema/SemaDecl.cpp (+6) 
- (added) clang/test/CodeGen/ptrauth-in-c-struct.c (+172) 
- (added) clang/test/CodeGen/ptrauth-qualifier-blocks.c (+107) 
- (modified) clang/test/Sema/ptrauth-qualifier.c (+43) 


``````````diff
diff --git a/clang/include/clang/AST/NonTrivialTypeVisitor.h 
b/clang/include/clang/AST/NonTrivialTypeVisitor.h
index cf320c8a478af..c06dfa06eb922 100644
--- a/clang/include/clang/AST/NonTrivialTypeVisitor.h
+++ b/clang/include/clang/AST/NonTrivialTypeVisitor.h
@@ -95,6 +95,8 @@ struct CopiedTypeVisitor {
       return asDerived().visitARCWeak(FT, std::forward<Ts>(Args)...);
     case QualType::PCK_Struct:
       return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
+    case QualType::PCK_PtrAuth:
+      return asDerived().visitPtrAuth(FT, std::forward<Ts>(Args)...);
     case QualType::PCK_Trivial:
       return asDerived().visitTrivial(FT, std::forward<Ts>(Args)...);
     case QualType::PCK_VolatileTrivial:
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 20ff529c7e0c6..b85fc45cf9562 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1507,6 +1507,9 @@ class QualType {
     /// with the ARC __weak qualifier.
     PCK_ARCWeak,
 
+    /// The type is an address-discriminated signed pointer type.
+    PCK_PtrAuth,
+
     /// The type is a struct containing a field whose type is neither
     /// PCK_Trivial nor PCK_VolatileTrivial.
     /// Note that a C++ struct type does not necessarily match this; C++ 
copying
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2836d68b05ff6..b1ecd9d63702b 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -8372,6 +8372,9 @@ bool ASTContext::BlockRequiresCopying(QualType Ty,
     return true;
   }
 
+  if (Ty.hasAddressDiscriminatedPointerAuth())
+    return true;
+
   // The block needs copy/destroy helpers if Ty is non-trivial to destructively
   // move or destroy.
   if (Ty.isNonTrivialToPrimitiveDestructiveMove() || Ty.isDestructedType())
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 67cd690af7499..632b3f3a37111 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2801,6 +2801,10 @@ static bool isTriviallyCopyableTypeImpl(const QualType 
&type,
   if (type.hasNonTrivialObjCLifetime())
     return false;
 
+  QualType::PrimitiveCopyKind PCK = type.isNonTrivialToPrimitiveCopy();
+  if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial)
+    return false;
+
   // C++11 [basic.types]p9 - See Core 2094
   //   Scalar types, trivially copyable class types, arrays of such types, and
   //   cv-qualified versions of these types are collectively
@@ -2968,6 +2972,8 @@ QualType::PrimitiveCopyKind 
QualType::isNonTrivialToPrimitiveCopy() const {
   case Qualifiers::OCL_Weak:
     return PCK_ARCWeak;
   default:
+    if (hasAddressDiscriminatedPointerAuth())
+      return PCK_PtrAuth;
     return Qs.hasVolatile() ? PCK_VolatileTrivial : PCK_Trivial;
   }
 }
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index faef6a5fbe1f5..ba0d87fdc5d43 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -1591,6 +1591,10 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture 
&CI, QualType T,
     return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
   }
 
+  if (T.hasAddressDiscriminatedPointerAuth())
+    return std::make_pair(
+        BlockCaptureEntityKind::AddressDiscriminatedPointerAuth, Flags);
+
   Flags = BLOCK_FIELD_IS_OBJECT;
   bool isBlockPointer = T->isBlockPointerType();
   if (isBlockPointer)
@@ -1611,6 +1615,10 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture 
&CI, QualType T,
     return std::make_pair(!isBlockPointer ? BlockCaptureEntityKind::ARCStrong
                                           : 
BlockCaptureEntityKind::BlockObject,
                           Flags);
+  case QualType::PCK_PtrAuth:
+    return std::make_pair(
+        BlockCaptureEntityKind::AddressDiscriminatedPointerAuth,
+        BlockFieldFlags());
   case QualType::PCK_Trivial:
   case QualType::PCK_VolatileTrivial: {
     if (!T->isObjCRetainableType())
@@ -1713,6 +1721,13 @@ static std::string getBlockCaptureStr(const 
CGBlockInfo::Capture &Cap,
   case BlockCaptureEntityKind::ARCStrong:
     Str += "s";
     break;
+  case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth: {
+    auto PtrAuth = CaptureTy.getPointerAuth();
+    assert(PtrAuth && PtrAuth.isAddressDiscriminated());
+    Str += "p" + llvm::to_string(PtrAuth.getKey()) + "d" +
+           llvm::to_string(PtrAuth.getExtraDiscriminator());
+    break;
+  }
   case BlockCaptureEntityKind::BlockObject: {
     const VarDecl *Var = CI.getVariable();
     unsigned F = Flags.getBitMask();
@@ -1829,6 +1844,7 @@ static void pushCaptureCleanup(BlockCaptureEntityKind 
CaptureKind,
     }
     break;
   }
+  case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth:
   case BlockCaptureEntityKind::None:
     break;
   }
@@ -1925,6 +1941,14 @@ CodeGenFunction::GenerateCopyHelperFunction(const 
CGBlockInfo &blockInfo) {
     case BlockCaptureEntityKind::ARCWeak:
       EmitARCCopyWeak(dstField, srcField);
       break;
+    case BlockCaptureEntityKind::AddressDiscriminatedPointerAuth: {
+      QualType Type = CI.getVariable()->getType();
+      PointerAuthQualifier PointerAuth = Type.getPointerAuth();
+      assert(PointerAuth && PointerAuth.isAddressDiscriminated());
+      EmitPointerAuthCopy(PointerAuth, Type, dstField, srcField);
+      // We don't need to push cleanups for ptrauth types.
+      continue;
+    }
     case BlockCaptureEntityKind::NonTrivialCStruct: {
       // If this is a C struct that requires non-trivial copy construction,
       // emit a call to its copy constructor.
@@ -2261,6 +2285,33 @@ class CXXByrefHelpers final : public BlockByrefHelpers {
   }
 };
 
+/// Emits the copy/dispose helpers for a __block variable with
+/// address-discriminated pointer authentication.
+class AddressDiscriminatedByrefHelpers final : public BlockByrefHelpers {
+  QualType VarType;
+
+public:
+  AddressDiscriminatedByrefHelpers(CharUnits Alignment, QualType Type)
+      : BlockByrefHelpers(Alignment), VarType(Type) {
+    assert(Type.hasAddressDiscriminatedPointerAuth());
+  }
+
+  void emitCopy(CodeGenFunction &CGF, Address DestField,
+                Address SrcField) override {
+    CGF.EmitPointerAuthCopy(VarType.getPointerAuth(), VarType, DestField,
+                            SrcField);
+  }
+
+  bool needsDispose() const override { return false; }
+  void emitDispose(CodeGenFunction &CGF, Address Field) override {
+    llvm_unreachable("should never be called");
+  }
+
+  void profileImpl(llvm::FoldingSetNodeID &ID) const override {
+    ID.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
+  }
+};
+
 /// Emits the copy/dispose helpers for a __block variable that is a non-trivial
 /// C struct.
 class NonTrivialCStructByrefHelpers final : public BlockByrefHelpers {
@@ -2462,7 +2513,10 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType 
&byrefType,
     return ::buildByrefHelpers(
         CGM, byrefInfo, CXXByrefHelpers(valueAlignment, type, copyExpr));
   }
-
+  if (type.hasAddressDiscriminatedPointerAuth()) {
+    return ::buildByrefHelpers(
+        CGM, byrefInfo, AddressDiscriminatedByrefHelpers(valueAlignment, 
type));
+  }
   // If type is a non-trivial C struct type that is non-trivial to
   // destructly move or destroy, build the copy and dispose helpers.
   if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct ||
diff --git a/clang/lib/CodeGen/CGBlocks.h b/clang/lib/CodeGen/CGBlocks.h
index 8d10c4f69b202..b2e850046ab9a 100644
--- a/clang/lib/CodeGen/CGBlocks.h
+++ b/clang/lib/CodeGen/CGBlocks.h
@@ -146,6 +146,7 @@ class BlockByrefInfo {
 enum class BlockCaptureEntityKind {
   None,
   CXXRecord, // Copy or destroy
+  AddressDiscriminatedPointerAuth,
   ARCWeak,
   ARCStrong,
   NonTrivialCStruct,
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 8cb27420dd911..836f34e5b347d 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -4857,7 +4857,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, 
const Expr *E,
 
   if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
       cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue &&
-      !type->isArrayParameterType()) {
+      !type->isArrayParameterType() && !type.isNonTrivialToPrimitiveCopy()) {
     LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
     assert(L.isSimple());
     args.addUncopiedAggregate(L, type);
diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp 
b/clang/lib/CodeGen/CGNonTrivialStruct.cpp
index c634b5c010e2d..e0983ef256e71 100644
--- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp
+++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp
@@ -266,6 +266,18 @@ struct GenBinaryFuncName : 
CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>,
     this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" +
                     llvm::to_string(getFieldSize(FD, FT, this->Ctx)));
   }
+
+  void visitPtrAuth(QualType FT, const FieldDecl *FD,
+                    CharUnits CurStructOffset) {
+    this->appendStr("_pa");
+    PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
+    this->appendStr(llvm::to_string(PtrAuth.getKey()) + "_");
+    this->appendStr(llvm::to_string(PtrAuth.getExtraDiscriminator()) + "_");
+    if (PtrAuth.authenticatesNullValues())
+      this->appendStr("anv_");
+    CharUnits FieldOffset = CurStructOffset + this->getFieldOffset(FD);
+    this->appendStr(llvm::to_string(FieldOffset.getQuantity()));
+  }
 };
 
 struct GenDefaultInitializeFuncName
@@ -568,6 +580,13 @@ struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>,
     RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation());
     this->CGF->EmitStoreThroughLValue(SrcVal, DstLV);
   }
+  void visitPtrAuth(QualType FT, const FieldDecl *FD, CharUnits CurStackOffset,
+                    std::array<Address, 2> Addrs) {
+    PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
+    Addrs[DstIdx] = this->getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
+    Addrs[SrcIdx] = this->getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
+    this->CGF->EmitPointerAuthCopy(PtrAuth, FT, Addrs[DstIdx], Addrs[SrcIdx]);
+  }
 };
 
 // These classes that emit the special functions for a non-trivial struct.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b2b26a2c39cf2..9c9372d9ee2b0 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -9443,6 +9443,9 @@ struct SearchNonTrivialToCopyField
   void visitARCWeak(QualType FT, SourceLocation SL) {
     S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
   }
+  void visitPtrAuth(QualType FT, SourceLocation SL) {
+    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
+  }
   void visitStruct(QualType FT, SourceLocation SL) {
     for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields())
       visit(FD->getType(), FD->getLocation());
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 46933c5c43168..3b42cdc4def46 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -13395,6 +13395,12 @@ struct DiagNonTrivalCUnionCopyVisitor
         asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
   }
 
+  void visitPtrAuth(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+    if (InNonTrivialUnion)
+      S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+          << 1 << 2 << QT << FD->getName();
+  }
+
   void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT,
                 const FieldDecl *FD, bool InNonTrivialUnion) {}
   void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) 
{}
diff --git a/clang/test/CodeGen/ptrauth-in-c-struct.c 
b/clang/test/CodeGen/ptrauth-in-c-struct.c
new file mode 100644
index 0000000000000..4bd605a842b05
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-in-c-struct.c
@@ -0,0 +1,172 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fblocks -fptrauth-calls 
-fptrauth-returns -fptrauth-intrinsics -emit-llvm -o - %s | FileCheck %s
+
+#define AQ1_50 __ptrauth(1,1,50)
+#define AQ2_30 __ptrauth(2,1,30)
+#define IQ __ptrauth(1,0,50)
+
+typedef void (^BlockTy)(void);
+
+// CHECK: %[[STRUCT_SA:.*]] = type { i32, ptr }
+// CHECK: %[[STRUCT_SA2:.*]] = type { i32, ptr }
+// CHECK: %[[STRUCT_SI:.*]] = type { ptr }
+
+typedef struct {
+  int f0;
+  int * AQ1_50 f1; // Signed using address discrimination.
+} SA;
+
+typedef struct {
+  int f0;
+  int * AQ2_30 f1; // Signed using address discrimination.
+} SA2;
+
+typedef struct {
+  int * IQ f; // No address discrimination.
+} SI;
+
+SA getSA(void);
+void calleeSA(SA);
+
+int g0;
+
+// CHECK: define void @test_copy_constructor_SA(ptr noundef %{{.*}})
+// CHECK: call void @__copy_constructor_8_8_t0w4_pa1_50_8(
+
+// CHECK: define linkonce_odr hidden void 
@__copy_constructor_8_8_t0w4_pa1_50_8(ptr noundef %[[DST:.*]], ptr noundef 
%[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca ptr, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca ptr, align 8
+// CHECK: store ptr %[[DST]], ptr %[[DST_ADDR]], align 8
+// CHECK: store ptr %[[SRC]], ptr %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load ptr, ptr %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load ptr, ptr %[[SRC_ADDR]], align 8
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, ptr %[[V0]], i64 8
+// CHECK: %[[V9:.*]] = getelementptr inbounds i8, ptr %[[V1]], i64 8
+// CHECK: %[[V11:.*]] = load ptr, ptr %[[V9]], align 8
+// CHECK: %[[V12:.*]] = ptrtoint ptr %[[V9]] to i64
+// CHECK: %[[V13:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V12]], i64 50)
+// CHECK: %[[V14:.*]] = ptrtoint ptr %[[V6]] to i64
+// CHECK: %[[V15:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V14]], i64 50)
+// CHECK: %[[V17:.*]] = ptrtoint ptr %[[V11]] to i64
+// CHECK: %[[V18:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V17]], i32 1, i64 
%[[V13]], i32 1, i64 %[[V15]])
+
+void test_copy_constructor_SA(SA *s) {
+  SA t = *s;
+}
+
+// CHECK: define void @test_copy_constructor_SA2(ptr noundef %{{.*}})
+// CHECK: call void @__copy_constructor_8_8_t0w4_pa2_30_8(
+
+// CHECK: define linkonce_odr hidden void 
@__copy_constructor_8_8_t0w4_pa2_30_8(ptr noundef %[[DST:.*]], ptr noundef 
%[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca ptr, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca ptr, align 8
+// CHECK: store ptr %[[DST]], ptr %[[DST_ADDR]], align 8
+// CHECK: store ptr %[[SRC]], ptr %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load ptr, ptr %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load ptr, ptr %[[SRC_ADDR]], align 8
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, ptr %[[V0]], i64 8
+// CHECK: %[[V9:.*]] = getelementptr inbounds i8, ptr %[[V1]], i64 8
+// CHECK: %[[V11:.*]] = load ptr, ptr %[[V9]], align 8
+// CHECK: %[[V12:.*]] = ptrtoint ptr %[[V9]] to i64
+// CHECK: %[[V13:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V12]], i64 30)
+// CHECK: %[[V14:.*]] = ptrtoint ptr %[[V6]] to i64
+// CHECK: %[[V15:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V14]], i64 30)
+// CHECK: %[[V17:.*]] = ptrtoint ptr %[[V11]] to i64
+// CHECK: %[[V18:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V17]], i32 2, i64 
%[[V13]], i32 2, i64 %[[V15]])
+
+void test_copy_constructor_SA2(SA2 *s) {
+  SA2 t = *s;
+}
+
+// CHECK: define void @test_copy_assignment_SA(
+// CHECK: call void @__copy_assignment_8_8_t0w4_pa1_50_8(
+
+// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_t0w4_pa1_50_8(
+
+void test_copy_assignment_SA(SA *d, SA *s) {
+  *d = *s;
+}
+
+// CHECK: define void @test_move_constructor_SA(
+// CHECK: define internal void @__Block_byref_object_copy_(
+// CHECK: define linkonce_odr hidden void 
@__move_constructor_8_8_t0w4_pa1_50_8(
+
+void test_move_constructor_SA(void) {
+  __block SA t;
+  BlockTy b = ^{ (void)t; };
+}
+
+// CHECK: define void @test_move_assignment_SA(
+// CHECK: call void @__move_assignment_8_8_t0w4_pa1_50_8(
+// CHECK: define linkonce_odr hidden void @__move_assignment_8_8_t0w4_pa1_50_8(
+
+void test_move_assignment_SA(SA *p) {
+  *p = getSA();
+}
+
+// CHECK: define void @test_parameter_SA(ptr noundef %{{.*}})
+// CHECK-NOT: call
+// CHECK: ret void
+
+void test_parameter_SA(SA a) {
+}
+
+// CHECK: define void @test_argument_SA(ptr noundef %[[A:.*]])
+// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SA]], align 8
+// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8
+// CHECK: call void @__copy_constructor_8_8_t0w4_pa1_50_8(ptr %[[AGG_TMP]], 
ptr %[[V0]])
+// CHECK: call void @calleeSA(ptr noundef %[[AGG_TMP]])
+// CHECK-NOT: call
+// CHECK: ret void
+
+void test_argument_SA(SA *a) {
+  calleeSA(*a);
+}
+
+// CHECK: define void @test_return_SA(ptr dead_on_unwind noalias writable 
sret(%struct.SA) align 8 %[[AGG_RESULT:.*]], ptr noundef %[[A:.*]])
+// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8
+// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8
+// CHECK: call void @__copy_constructor_8_8_t0w4_pa1_50_8(ptr %[[AGG_RESULT]], 
ptr %[[V0]])
+// CHECK-NOT: call
+// CHECK: ret void
+
+SA test_return_SA(SA *a) {
+  return *a;
+}
+
+// CHECK: define void @test_copy_constructor_SI(
+// CHECK-NOT: call
+// CHECK: call void @llvm.memcpy.p0.p0.i64(
+// CHECK-NOT: call
+// CHECK: ret void
+
+void test_copy_constructor_SI(SI *s) {
+  SI t = *s;
+}
+
+// CHECK: define void @test_parameter_SI(i64 %{{.*}})
+// CHECK-NOT: call
+// CHECK: ret void
+
+void test_parameter_SI(SI a) {
+}
+
+// CHECK-LABEL: define void @test_array(
+// CHECK: %[[F1:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %{{.*}}, 
i32 0, i32 1
+// CHECK: %[[V0:.*]] = ptrtoint ptr %[[F1]] to i64
+// CHECK: %[[V1:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V0]], i64 50)
+// CHECK: %[[V2:.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @g0 to 
i64), i32 1, i64 %[[V1]])
+// CHECK: %[[V3:.*]] = inttoptr i64 %[[V2]] to ptr
+// CHECK: store ptr %[[V3]], ptr %[[F1]], align 8
+// CHECK: %[[F12:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr 
%{{.*}}, i32 0, i32 1
+// CHECK: %[[V4:.*]] = ptrtoint ptr %[[F12]] to i64
+// CHECK: %[[V5:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V4]], i64 50)
+// CHECK: %[[V6:.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @g0 to 
i64), i32 1, i64 %[[V5]])
+// CHECK: %[[V7:.*]] = inttoptr i64 %[[V6]] to ptr
+// CHECK: store ptr %[[V7]], ptr %[[F12]], align 8
+
+void test_array(void) {
+  const SA a[] = {{0, &g0}, {1, &g0}};
+}
diff --git a/clang/test/CodeGen/ptrauth-qualifier-blocks.c 
b/clang/test/CodeGen/ptrauth-qualifier-blocks.c
new file mode 100644
index 0000000000000..62da59cf327f6
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-qualifier-blocks.c
@@ -0,0 +1,107 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls 
-fptrauth-intrinsics -fblocks -emit-llvm %s  -o - | FileCheck %s
+
+struct A {
+  int value;
+};
+struct A *createA(void);
+
+void use_block(int (^)(void));
+
+// CHECK-LABEL: define void @test_block_nonaddress_capture(
+void test_block_nonaddress_capture() {
+  // CHECK: [[VAR:%.*]] = alloca ptr,
+  // CHECK: [[BLOCK:%.*]] = alloca
+  //   flags - no copy/dispose required
+  // CHECK: store i32 1073741824, ptr
+  // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds {{.*}} [[BLOCK]], i32 0, 
i32 5
+  // CHECK: [[LOAD:%.*]] = load ptr, ptr [[VAR]],
+  // CHECK: store ptr [[LOAD]], ptr [[CAPTURE]]
+  struct A * __ptrauth(1, 0, 15) ptr = createA();
+  use_block(^{ return ptr->value; });
+}
+// CHECK-LABEL: define internal i32 
@__test_block_nonaddress_capture_block_invoke
+// CHECK: call i64 @llvm.ptrauth.auth(i64 {{%.*}}, i32 1, i64 15)
+
+// CHECK-LABEL: define void @test_block_address_capture(
+void test_block_address_capture() {
+  // CHECK: [[VAR:%.*]] = alloca ptr,
+  // CHECK: [[BLOCK:%.*]] = alloca
+  //   flags - copy/dispose required
+  // CHECK: store i32 1107296256, ptr
+  // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds {{.*}} [[BLOCK]], i32 0, 
i32 5
+  // CHECK: [[LOAD:%.*]] = load ptr, ptr [[VAR]],
+  // CHECK: [[T0:%.*]] = ptrtoint ptr [[VAR]] to i64
+  // CHECK: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 30)
+  // CHECK: [[T0:%.*]] = ptrtoint ptr [[CAPTURE]] to i64
+  // CHECK: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 30)
+  // CHECK: [[T0:%.*]] = icmp ne ptr [[LOAD]], null
+  // CHECK: br i1 [[T0]]
+  // CHEC...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/136783
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to