https://github.com/ojhunt updated 
https://github.com/llvm/llvm-project/pull/147899

>From 3b0a91c3d4a4ae8ec7980d2201d94f59746fb769 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Wed, 9 Jul 2025 17:30:48 -0700
Subject: [PATCH] [clang][ObjC][PAC] Add ptrauth protections to objective-c

This PR introduces the use of pointer authentication to objective-c[++].

This includes:

* __ptrauth qualifier support for ivars
* protection of isa and super fields
* protection of SEL typed ivars
* protection of class_ro_t data
* protection of methodlist pointers and content
---
 clang/include/clang/AST/ASTContext.h          |   2 +
 clang/include/clang/Basic/Features.def        |   6 +
 clang/include/clang/Basic/LangOptions.def     |   5 +
 .../include/clang/Basic/PointerAuthOptions.h  |  35 +++++
 clang/include/clang/Driver/Options.td         |   3 +
 clang/lib/AST/ASTContext.cpp                  |  11 ++
 clang/lib/CodeGen/CGBlocks.cpp                |  21 ++-
 clang/lib/CodeGen/CGObjC.cpp                  |  52 ++++++-
 clang/lib/CodeGen/CGObjCMac.cpp               |  94 +++++++++----
 clang/lib/CodeGen/CodeGenModule.cpp           |   4 +-
 clang/lib/CodeGen/ConstantInitBuilder.cpp     |   2 +-
 clang/lib/Driver/ToolChains/Clang.cpp         |   7 +
 clang/lib/Frontend/CompilerInvocation.cpp     |  34 +++++
 clang/lib/Headers/ptrauth.h                   |  57 ++++++++
 clang/lib/Sema/SemaDeclObjC.cpp               |   8 ++
 clang/lib/Sema/SemaObjCProperty.cpp           |   9 ++
 clang/test/CodeGenObjC/arc.m                  |   8 +-
 .../test/CodeGenObjC/matrix-type-operators.m  |  10 +-
 .../test/CodeGenObjC/ptrauth-attr-exception.m |  17 +++
 clang/test/CodeGenObjC/ptrauth-block-isa.m    |  40 ++++++
 clang/test/CodeGenObjC/ptrauth-class-ro.m     |  24 ++++
 clang/test/CodeGenObjC/ptrauth-class.m        | 103 ++++++++++++++
 .../ptrauth-objc-interface-selector.m         | 130 ++++++++++++++++++
 .../test/CodeGenObjC/ptrauth-objc-isa-super.m |  57 ++++++++
 .../ptrauth-objc-method-list-pointer.m        |  17 +++
 .../CodeGenObjC/ptrauth-property-backing.m    |  80 +++++++++++
 .../ptrauth-objc-interface-selector.mm        |  90 ++++++++++++
 clang/test/SemaObjC/ptrauth-pointers.m        |  46 +++++++
 clang/test/SemaObjC/ptrauth-qualifier.m       |  39 +++++-
 29 files changed, 969 insertions(+), 42 deletions(-)
 create mode 100644 clang/test/CodeGenObjC/ptrauth-attr-exception.m
 create mode 100644 clang/test/CodeGenObjC/ptrauth-block-isa.m
 create mode 100644 clang/test/CodeGenObjC/ptrauth-class-ro.m
 create mode 100644 clang/test/CodeGenObjC/ptrauth-class.m
 create mode 100644 clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m
 create mode 100644 clang/test/CodeGenObjC/ptrauth-objc-isa-super.m
 create mode 100644 clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m
 create mode 100644 clang/test/CodeGenObjC/ptrauth-property-backing.m
 create mode 100644 clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm
 create mode 100644 clang/test/SemaObjC/ptrauth-pointers.m

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 2b9cd035623cc..8c27728c404dd 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2300,6 +2300,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
     return getTypeDeclType(getObjCSelDecl());
   }
 
+  PointerAuthQualifier getObjCMemberSelTypePtrAuth();
+
   /// Retrieve the typedef declaration corresponding to the predefined
   /// Objective-C 'Class' type.
   TypedefDecl *getObjCClassDecl() const;
diff --git a/clang/include/clang/Basic/Features.def 
b/clang/include/clang/Basic/Features.def
index 14bff8a68846d..c2e677e31e5a0 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -119,6 +119,12 @@ FEATURE(ptrauth_indirect_gotos, 
LangOpts.PointerAuthIndirectGotos)
 FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
 FEATURE(ptrauth_init_fini_address_discrimination, 
LangOpts.PointerAuthInitFiniAddressDiscrimination)
 FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT)
+
+FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa)
+FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel)
+FEATURE(ptrauth_objc_signable_class, true)
+FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls)
+
 EXTENSION(swiftcc,
   PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
   clang::TargetInfo::CCCR_OK)
diff --git a/clang/include/clang/Basic/LangOptions.def 
b/clang/include/clang/Basic/LangOptions.def
index 72321c204ce96..852188de18654 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -133,6 +133,11 @@ LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0, 
NotCompatible,
 LANGOPT(PointerAuthELFGOT, 1, 0, NotCompatible, "authenticate pointers from 
GOT")
 LANGOPT(AArch64JumpTableHardening, 1, 0, NotCompatible, "use hardened lowering 
for jump-table dispatch")
 
+LANGOPT(PointerAuthObjcIsa, 1, 0, NotCompatible, "authentication of isa and 
super pointers in ObjC instances")
+LANGOPT(PointerAuthObjcInterfaceSel, 1, 0, NotCompatible, "authentication of 
SEL fields of ObjC interfaces")
+LANGOPT(PointerAuthObjcInterfaceSelKey, 16, 0, NotCompatible, "authentication 
key for SEL fields of ObjC interfaces")
+LANGOPT(PointerAuthObjcClassROPointers, 1, 0, Benign, "class_ro_t pointer 
authentication")
+
 LANGOPT(DoubleSquareBracketAttributes, 1, 0, NotCompatible, "'[[]]' attributes 
extension for all language standard modes")
 LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental 
late parsing of attributes")
 
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h 
b/clang/include/clang/Basic/PointerAuthOptions.h
index a3a3e50bcde5d..fb6dddf3ae9ce 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -27,6 +27,26 @@ namespace clang {
 /// .fini_array. The value is ptrauth_string_discriminator("init_fini")
 constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
 
+/// Constant discriminator to be used with method list pointers. The value is
+/// ptrauth_string_discriminator("method_list_t")
+constexpr uint16_t MethodListPointerConstantDiscriminator = 0xC310;
+
+/// Constant discriminator to be used with objective-c isa pointers. The value
+/// is ptrauth_string_discriminator("isa")
+constexpr uint16_t IsaPointerConstantDiscriminator = 0x6AE1;
+
+/// Constant discriminator to be used with objective-c superclass pointers.
+/// The value is ptrauth_string_discriminator("objc_class:superclass")
+constexpr uint16_t SuperPointerConstantDiscriminator = 0xB5AB;
+
+/// Constant discriminator to be used with objective-c sel pointers. The value
+/// is ptrauth_string_discriminator("sel")
+constexpr uint16_t SelPointerConstantDiscriminator = 0x57c2;
+
+/// Constant discriminator to be used with objective-c class_ro_t pointers.
+/// The value is ptrauth_string_discriminator("class_data_bits")
+constexpr uint16_t ClassROConstantDiscriminator = 0x61F8;
+
 constexpr unsigned PointerAuthKeyNone = -1;
 
 /// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
@@ -202,6 +222,21 @@ struct PointerAuthOptions {
 
   /// The ABI for function addresses in .init_array and .fini_array
   PointerAuthSchema InitFiniPointers;
+
+  /// The ABI for Objective-C method lists.
+  PointerAuthSchema ObjCMethodListFunctionPointers;
+
+  /// The ABI for a reference to an Objective-C method list in _class_ro_t.
+  PointerAuthSchema ObjCMethodListPointer;
+
+  /// The ABI for Objective-C isa pointers.
+  PointerAuthSchema ObjCIsaPointers;
+
+  /// The ABI for Objective-C superclass pointers.
+  PointerAuthSchema ObjCSuperPointers;
+
+  /// The ABI for Objective-C class_ro_t pointers.
+  PointerAuthSchema ObjCClassROPointers;
 };
 
 } // end namespace clang
diff --git a/clang/include/clang/Driver/Options.td 
b/clang/include/clang/Driver/Options.td
index 77379f1130149..e2b347246f7ab 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4498,6 +4498,9 @@ defm ptrauth_init_fini_address_discrimination : 
OptInCC1FFlag<"ptrauth-init-fini
   "Enable address discrimination of function pointers in init/fini arrays">;
 defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication 
of pointers from GOT (ELF only)">;
 defm aarch64_jump_table_hardening: 
OptInCC1FFlag<"aarch64-jump-table-hardening", "Use hardened lowering for 
jump-table dispatch">;
+defm ptrauth_objc_isa : OptInCC1FFlag<"ptrauth-objc-isa", "Enable signing and 
authentication of Objective-C object's 'isa' field">;
+defm ptrauth_objc_interface_sel : OptInCC1FFlag<"ptrauth-objc-interface-sel", 
"Enable signing and authentication of Objective-C object's 'SEL' fields">;
+defm ptrauth_objc_class_ro : OptInCC1FFlag<"ptrauth-objc-class-ro", "Enable 
signing and authentication for ObjC class_ro pointers">;
 }
 
 def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 679812adcdf12..0499a81cd5231 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -9783,6 +9783,17 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() 
const {
   return ObjCProtocolClassDecl;
 }
 
+PointerAuthQualifier ASTContext::getObjCMemberSelTypePtrAuth() {
+  if (!getLangOpts().PointerAuthObjcInterfaceSel)
+    return PointerAuthQualifier();
+  return PointerAuthQualifier::Create(
+      getLangOpts().PointerAuthObjcInterfaceSelKey,
+      /*isAddressDiscriminated=*/true, SelPointerConstantDiscriminator,
+      PointerAuthenticationMode::SignAndAuth,
+      /*isIsaPointer=*/false,
+      /*authenticatesNullValues=*/false);
+}
+
 
//===----------------------------------------------------------------------===//
 // __builtin_va_list Construction Functions
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index f3ddf7bf9a463..1aba841eb5fc2 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -853,9 +853,24 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const 
CGBlockInfo &blockInfo) {
       offset += size;
       index++;
     };
+    auto addSignedHeaderField =
+        [&](llvm::Value *Value, const PointerAuthSchema &Schema,
+            GlobalDecl Decl, QualType Type, CharUnits Size, const Twine &Name) 
{
+          auto StorageAddress = projectField(index, Name);
+          if (Schema) {
+            auto AuthInfo = EmitPointerAuthInfo(
+                Schema, StorageAddress.emitRawPointer(*this), Decl, Type);
+            Value = EmitPointerAuthSign(AuthInfo, Value);
+          }
+          Builder.CreateStore(Value, StorageAddress);
+          offset += Size;
+          index++;
+        };
 
     if (!IsOpenCL) {
-      addHeaderField(isa, getPointerSize(), "block.isa");
+      addSignedHeaderField(
+          isa, CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers, GlobalDecl(),
+          QualType(), getPointerSize(), "block.isa");
       addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
                      getIntSize(), "block.flags");
       addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(),
@@ -1285,7 +1300,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule 
&CGM,
     if (IsWindows)
       fields.addNullPointer(CGM.Int8PtrPtrTy);
     else
-      fields.add(CGM.getNSConcreteGlobalBlock());
+      fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(),
+                              CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                              GlobalDecl(), QualType());
 
     // __flags
     BlockFlags flags = BLOCK_IS_GLOBAL;
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 6f87444d3f672..24b6ce7c1c70d 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -1193,16 +1193,23 @@ CodeGenFunction::generateObjCGetterBody(const 
ObjCImplementationDecl *classImpl,
     ivarAddr = ivarAddr.withElementType(bitcastType);
     llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
     load->setAtomic(llvm::AtomicOrdering::Unordered);
+    llvm::Value *ivarVal = load;
+    if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
+      CGPointerAuthInfo SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
+      CGPointerAuthInfo TargetInfo =
+          CGM.getPointerAuthInfoForType(getterMethod->getReturnType());
+      ivarVal = emitPointerAuthResign(ivarVal, ivar->getType(), SrcInfo,
+                                      TargetInfo, /*isKnownNonNull=*/false);
+    }
 
     // Store that value into the return address.  Doing this with a
     // bitcast is likely to produce some pretty ugly IR, but it's not
     // the *most* terrible thing in the world.
     llvm::Type *retTy = ConvertType(getterMethod->getReturnType());
     uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy);
-    llvm::Value *ivarVal = load;
     if (ivarSize > retTySize) {
       bitcastType = llvm::Type::getIntNTy(getLLVMContext(), retTySize);
-      ivarVal = Builder.CreateTrunc(load, bitcastType);
+      ivarVal = Builder.CreateTrunc(ivarVal, bitcastType);
     }
     Builder.CreateStore(ivarVal, ReturnValue.withElementType(bitcastType));
 
@@ -1214,6 +1221,16 @@ CodeGenFunction::generateObjCGetterBody(const 
ObjCImplementationDecl *classImpl,
   case PropertyImplStrategy::GetSetProperty: {
     llvm::FunctionCallee getPropertyFn =
         CGM.getObjCRuntime().GetPropertyGetFunction();
+
+    if (ivar->getType().getPointerAuth()) {
+      // This currently cannot be hit, but if we ever allow objc pointers
+      // to be signed, this will become possible. Reaching here would require
+      // a copy, weak, etc property backed by an authenticated pointer.
+      CGM.ErrorUnsupported(propImpl,
+                           "Obj-C getter requiring pointer authentication");
+      return;
+    }
+
     if (!getPropertyFn) {
       CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
       return;
@@ -1269,7 +1286,9 @@ CodeGenFunction::generateObjCGetterBody(const 
ObjCImplementationDecl *classImpl,
     LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
 
     QualType ivarType = ivar->getType();
-    switch (getEvaluationKind(ivarType)) {
+    auto EvaluationKind = getEvaluationKind(ivarType);
+    assert(!ivarType.getPointerAuth() || EvaluationKind == TEK_Scalar);
+    switch (EvaluationKind) {
     case TEK_Complex: {
       ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
       EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
@@ -1287,6 +1306,11 @@ CodeGenFunction::generateObjCGetterBody(const 
ObjCImplementationDecl *classImpl,
     case TEK_Scalar: {
       llvm::Value *value;
       if (propType->isReferenceType()) {
+        if (ivarType.getPointerAuth()) {
+          CGM.ErrorUnsupported(propImpl,
+                               "Obj-C getter for authenticated reference 
type");
+          return;
+        }
         value = LV.getAddress().emitRawPointer(*this);
       } else {
         // We want to load and autoreleaseReturnValue ARC __weak ivars.
@@ -1300,7 +1324,19 @@ CodeGenFunction::generateObjCGetterBody(const 
ObjCImplementationDecl *classImpl,
         // Otherwise we want to do a simple load, suppressing the
         // final autorelease.
         } else {
-          value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
+          if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
+            Address ivarAddr = LV.getAddress();
+            llvm::LoadInst *LoadInst = Builder.CreateLoad(ivarAddr, "load");
+            llvm::Value *Load = LoadInst;
+            auto SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
+            auto TargetInfo =
+                CGM.getPointerAuthInfoForType(getterMethod->getReturnType());
+            Load = emitPointerAuthResign(Load, ivarType, SrcInfo, TargetInfo,
+                                         /*isKnownNonNull=*/false);
+            value = Load;
+          } else
+            value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
+
           AutoreleaseResult = false;
         }
 
@@ -1490,6 +1526,14 @@ CodeGenFunction::generateObjCSetterBody(const 
ObjCImplementationDecl *classImpl,
 
     llvm::Value *load = Builder.CreateLoad(argAddr);
 
+    if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
+      QualType PropertyType = propImpl->getPropertyDecl()->getType();
+      CGPointerAuthInfo SrcInfo = CGM.getPointerAuthInfoForType(PropertyType);
+      CGPointerAuthInfo TargetInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
+      load = emitPointerAuthResign(load, ivar->getType(), SrcInfo, TargetInfo,
+                                   /*isKnownNonNull=*/false);
+    }
+
     // Perform an atomic store.  There are no memory ordering requirements.
     llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
     store->setAtomic(llvm::AtomicOrdering::Unordered);
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index a52c92cdbc83b..8e71a576552d3 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -1935,7 +1935,9 @@ CGObjCCommonMac::GenerateConstantNSString(const 
StringLiteral *Literal) {
   auto Fields = Builder.beginStruct(NSConstantStringType);
 
   // Class pointer.
-  Fields.add(Class);
+  Fields.addSignedPointer(Class,
+                          CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                          GlobalDecl(), QualType());
 
   // String pointer.
   llvm::Constant *C =
@@ -4975,10 +4977,7 @@ enum ImageInfoFlags {
   eImageInfo_GCOnly              = (1 << 2),
   eImageInfo_OptimizedByDyld     = (1 << 3), // This flag is set by the dyld 
shared cache.
 
-  // A flag indicating that the module has no instances of a @synthesize of a
-  // superclass variable. This flag used to be consumed by the runtime to work
-  // around miscompile by gcc.
-  eImageInfo_CorrectedSynthesize = (1 << 4), // This flag is no longer set by 
clang.
+  eImageInfo_SignedClassRO       = (1 << 4), // Reused (was 
_CorrectedSynthesize)
   eImageInfo_ImageIsSimulated    = (1 << 5),
   eImageInfo_ClassProperties     = (1 << 6)
 };
@@ -5036,6 +5035,17 @@ void CGObjCCommonMac::EmitImageInfo() {
   // Indicate whether we are generating class properties.
   Mod.addModuleFlag(llvm::Module::Error, "Objective-C Class Properties",
                     eImageInfo_ClassProperties);
+
+  // Indicate whether we want enforcement of pointer signing for class_ro_t
+  // pointers.
+  if (CGM.getLangOpts().PointerAuthObjcClassROPointers)
+    Mod.addModuleFlag(llvm::Module::Error,
+                      "Objective-C Enforce ClassRO Pointer Signing",
+                      eImageInfo_SignedClassRO);
+  else
+    Mod.addModuleFlag(llvm::Module::Error,
+                      "Objective-C Enforce ClassRO Pointer Signing",
+                      llvm::ConstantInt::get(Int8Ty, 0));
 }
 
 // struct objc_module {
@@ -6223,11 +6233,19 @@ llvm::GlobalVariable 
*CGObjCNonFragileABIMac::BuildClassRoTInitializer(
         methods.push_back(MD);
   }
 
-  values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
-                            (flags & NonFragileABI_Class_Meta)
-                                ? MethodListType::ClassMethods
-                                : MethodListType::InstanceMethods,
-                            methods));
+  llvm::Constant *MethListPtr = emitMethodList(
+      ID->getObjCRuntimeNameAsString(),
+      (flags & NonFragileABI_Class_Meta) ? MethodListType::ClassMethods
+                                         : MethodListType::InstanceMethods,
+      methods);
+
+  const PointerAuthSchema &MethListSchema =
+      CGM.getCodeGenOpts().PointerAuth.ObjCMethodListPointer;
+  if (!MethListPtr->isNullValue())
+    values.addSignedPointer(MethListPtr, MethListSchema, GlobalDecl(),
+                            QualType());
+  else
+    values.add(MethListPtr);
 
   const ObjCInterfaceDecl *OID = ID->getClassInterface();
   assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
@@ -6275,15 +6293,20 @@ llvm::GlobalVariable 
*CGObjCNonFragileABIMac::BuildClassObject(
     bool HiddenVisibility) {
   ConstantInitBuilder builder(CGM);
   auto values = builder.beginStruct(ObjCTypes.ClassnfABITy);
-  values.add(IsAGV);
-  if (SuperClassGV) {
-    values.add(SuperClassGV);
-  } else {
+  const PointerAuthOptions &PointerAuthOpts = CGM.getCodeGenOpts().PointerAuth;
+  values.addSignedPointer(IsAGV, PointerAuthOpts.ObjCIsaPointers, GlobalDecl(),
+                          QualType());
+  if (SuperClassGV)
+    values.addSignedPointer(SuperClassGV, PointerAuthOpts.ObjCSuperPointers,
+                            GlobalDecl(), QualType());
+  else
     values.addNullPointer(ObjCTypes.ClassnfABIPtrTy);
-  }
+
   values.add(ObjCEmptyCacheVar);
   values.add(ObjCEmptyVtableVar);
-  values.add(ClassRoGV);
+
+  values.addSignedPointer(ClassRoGV, PointerAuthOpts.ObjCClassROPointers,
+                          GlobalDecl(), QualType());
 
   llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(
       GetClassGlobal(CI, isMetaclass, ForDefinition));
@@ -6543,15 +6566,27 @@ void CGObjCNonFragileABIMac::GenerateCategory(const 
ObjCCategoryImplDecl *OCD) {
     }
   }
 
-  auto instanceMethodList = emitMethodList(
+  llvm::Constant *InstanceMethodList = emitMethodList(
       listName, MethodListType::CategoryInstanceMethods, instanceMethods);
-  auto classMethodList = emitMethodList(
+  const PointerAuthSchema &MethListSchema =
+      CGM.getCodeGenOpts().PointerAuth.ObjCMethodListPointer;
+  if (!InstanceMethodList->isNullValue())
+    values.addSignedPointer(InstanceMethodList, MethListSchema, GlobalDecl(),
+                            QualType());
+  else
+    values.add(InstanceMethodList);
+
+  llvm::Constant *ClassMethodList = emitMethodList(
       listName, MethodListType::CategoryClassMethods, classMethods);
-  values.add(instanceMethodList);
-  values.add(classMethodList);
+  if (!ClassMethodList->isNullValue())
+    values.addSignedPointer(ClassMethodList, MethListSchema, GlobalDecl(),
+                            QualType());
+  else
+    values.add(ClassMethodList);
+
   // Keep track of whether we have actual metadata to emit.
   bool isEmptyCategory =
-      instanceMethodList->isNullValue() && classMethodList->isNullValue();
+      InstanceMethodList->isNullValue() && ClassMethodList->isNullValue();
 
   const ObjCCategoryDecl *Category =
       Interface->FindCategoryDeclaration(OCD->getIdentifier());
@@ -6629,7 +6664,13 @@ void 
CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
   } else {
     llvm::Function *fn = GetMethodDefinition(MD);
     assert(fn && "no definition for method?");
-    method.add(fn);
+    if (const PointerAuthSchema &Schema =
+            CGM.getCodeGenOpts().PointerAuth.ObjCMethodListFunctionPointers) {
+      llvm::Constant *Bitcast =
+          llvm::ConstantExpr::getBitCast(fn, ObjCTypes.Int8PtrProgramASTy);
+      method.addSignedPointer(Bitcast, Schema, GlobalDecl(), QualType());
+    } else
+      method.add(fn);
   }
 
   method.finishAndAddTo(builder);
@@ -7672,10 +7713,15 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const 
ObjCInterfaceDecl *ID,
   }
 
   llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
+  llvm::Constant *VTablePtr = llvm::ConstantExpr::getInBoundsGetElementPtr(
+      VTableGV->getValueType(), VTableGV, VTableIdx);
+
   ConstantInitBuilder builder(CGM);
   auto values = builder.beginStruct(ObjCTypes.EHTypeTy);
-  values.add(llvm::ConstantExpr::getInBoundsGetElementPtr(
-      VTableGV->getValueType(), VTableGV, VTableIdx));
+  const PointerAuthSchema &TypeInfoSchema =
+      CGM.getCodeGenOpts().PointerAuth.CXXTypeInfoVTablePointer;
+  values.addSignedPointer(VTablePtr, TypeInfoSchema, GlobalDecl(), QualType());
+
   values.add(GetClassName(ClassName));
   values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition));
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index c8866f15745c2..678be0718be28 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6616,7 +6616,9 @@ CodeGenModule::GetAddrOfConstantCFString(const 
StringLiteral *Literal) {
   auto Fields = Builder.beginStruct(STy);
 
   // Class pointer.
-  Fields.add(cast<llvm::Constant>(CFConstantStringClassRef));
+  Fields.addSignedPointer(cast<llvm::Constant>(CFConstantStringClassRef),
+                          getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                          GlobalDecl(), QualType());
 
   // Flags.
   if (IsSwiftABI) {
diff --git a/clang/lib/CodeGen/ConstantInitBuilder.cpp 
b/clang/lib/CodeGen/ConstantInitBuilder.cpp
index 7b3e7aea0f647..0f93d81c53fc7 100644
--- a/clang/lib/CodeGen/ConstantInitBuilder.cpp
+++ b/clang/lib/CodeGen/ConstantInitBuilder.cpp
@@ -309,7 +309,7 @@ void ConstantAggregateBuilderBase::addSignedPointer(
   if (Schema.isAddressDiscriminated()) {
     StorageAddress = getAddrOfCurrentPosition(Pointer->getType());
   }
-
+  assert(!Pointer->isNullValue());
   llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer(
       Pointer, Schema, StorageAddress, CalleeDecl, CalleeType);
   add(SignedPointer);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index b76163afc8aa4..48e327c425c24 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1746,6 +1746,13 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
   Args.addOptInFlag(CmdArgs, options::OPT_faarch64_jump_table_hardening,
                     options::OPT_fno_aarch64_jump_table_hardening);
 
+  Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_isa,
+                    options::OPT_fno_ptrauth_objc_isa);
+  Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_interface_sel,
+                    options::OPT_fno_ptrauth_objc_interface_sel);
+  Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_class_ro,
+                    options::OPT_fno_ptrauth_objc_class_ro);
+
   if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
     handlePAuthABI(Args, CmdArgs);
 
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp 
b/clang/lib/Frontend/CompilerInvocation.cpp
index b9f75796ecc16..08cf0ae6b2c24 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1541,6 +1541,25 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
           Key::ASIA, LangOpts.PointerAuthInitFiniAddressDiscrimination,
           Discrimination::Constant, InitFiniPointerConstantDiscriminator);
     }
+
+    Opts.ObjCMethodListFunctionPointers =
+        PointerAuthSchema(Key::ASIA, true, Discrimination::None);
+    Opts.ObjCMethodListPointer =
+        PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
+                          MethodListPointerConstantDiscriminator);
+    if (LangOpts.PointerAuthObjcIsa) {
+      Opts.ObjCIsaPointers =
+          PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
+                            IsaPointerConstantDiscriminator);
+      Opts.ObjCSuperPointers =
+          PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
+                            SuperPointerConstantDiscriminator);
+    }
+
+    if (LangOpts.PointerAuthObjcClassROPointers)
+      Opts.ObjCClassROPointers =
+          PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
+                            ClassROConstantDiscriminator);
   }
   Opts.ReturnAddresses = LangOpts.PointerAuthReturns;
   Opts.AuthTraps = LangOpts.PointerAuthAuthTraps;
@@ -3573,6 +3592,12 @@ static void GeneratePointerAuthArgs(const LangOptions 
&Opts,
     GenerateArg(Consumer, OPT_fptrauth_elf_got);
   if (Opts.AArch64JumpTableHardening)
     GenerateArg(Consumer, OPT_faarch64_jump_table_hardening);
+  if (Opts.PointerAuthObjcIsa)
+    GenerateArg(Consumer, OPT_fptrauth_objc_isa);
+  if (Opts.PointerAuthObjcInterfaceSel)
+    GenerateArg(Consumer, OPT_fptrauth_objc_interface_sel);
+  if (Opts.PointerAuthObjcClassROPointers)
+    GenerateArg(Consumer, OPT_fptrauth_objc_class_ro);
 }
 
 static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
@@ -3596,6 +3621,15 @@ static void ParsePointerAuthArgs(LangOptions &Opts, 
ArgList &Args,
   Opts.PointerAuthELFGOT = Args.hasArg(OPT_fptrauth_elf_got);
   Opts.AArch64JumpTableHardening =
       Args.hasArg(OPT_faarch64_jump_table_hardening);
+
+  Opts.PointerAuthObjcIsa = Args.hasArg(OPT_fptrauth_objc_isa);
+  Opts.PointerAuthObjcClassROPointers = 
Args.hasArg(OPT_fptrauth_objc_class_ro);
+  Opts.PointerAuthObjcInterfaceSel =
+      Args.hasArg(OPT_fptrauth_objc_interface_sel);
+
+  if (Opts.PointerAuthObjcInterfaceSel)
+    Opts.PointerAuthObjcInterfaceSelKey =
+        static_cast<unsigned>(PointerAuthSchema::ARM8_3Key::ASDB);
 }
 
 /// Check if input file kind and language standard are compatible.
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index d489a67c533d4..7f7d387cbdfda 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -42,6 +42,19 @@ typedef enum {
      The extra data is always 0. */
   ptrauth_key_cxx_vtable_pointer = ptrauth_key_process_independent_data,
 
+  /* The key used to sign metadata pointers to Objective-C method-lists. */
+  ptrauth_key_method_list_pointer = ptrauth_key_asda,
+
+  /* The key used to sign Objective-C isa and super pointers. */
+  ptrauth_key_objc_isa_pointer = ptrauth_key_process_independent_data,
+  ptrauth_key_objc_super_pointer = ptrauth_key_process_independent_data,
+
+  /* The key used to sign selector pointers */
+  ptrauth_key_objc_sel_pointer = ptrauth_key_process_dependent_data,
+
+  /* The key used to sign Objective-C class_ro_t pointers. */
+  ptrauth_key_objc_class_ro_pointer = ptrauth_key_process_independent_data,
+
   /* The key used to sign pointers in ELF .init_array/.fini_array. */
   ptrauth_key_init_fini_pointer = ptrauth_key_process_independent_code,
 
@@ -259,6 +272,46 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
 /* The value is ptrauth_string_discriminator("init_fini") */
 #define __ptrauth_init_fini_discriminator 0xd9d4
 
+/* Objective-C pointer auth ABI qualifiers */
+#define __ptrauth_objc_method_list_imp                                         
\
+  __ptrauth(ptrauth_key_function_pointer, 1, 0)
+
+#if __has_feature(ptrauth_objc_method_list_pointer)
+#define __ptrauth_objc_method_list_pointer                                     
\
+  __ptrauth(ptrauth_key_method_list_pointer, 1, 0xC310)
+#else
+#define __ptrauth_objc_method_list_pointer
+#endif
+
+#define __ptrauth_isa_discriminator 0x6AE1
+#define __ptrauth_super_discriminator 0xB5AB
+#define __ptrauth_objc_isa_pointer                                             
\
+  __ptrauth(ptrauth_key_objc_isa_pointer, 1, __ptrauth_isa_discriminator)
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define __ptrauth_objc_isa_uintptr                                             
\
+  __ptrauth_restricted_intptr(ptrauth_key_objc_isa_pointer, 1,                 
\
+                              __ptrauth_isa_discriminator)
+#else
+#define __ptrauth_objc_isa_uintptr                                             
\
+  __ptrauth(ptrauth_key_objc_isa_pointer, 1, __ptrauth_isa_discriminator)
+#endif
+
+#define __ptrauth_objc_super_pointer                                           
\
+  __ptrauth(ptrauth_key_objc_super_pointer, 1, __ptrauth_super_discriminator)
+
+#define __ptrauth_objc_sel_discriminator 0x57c2
+#if __has_feature(ptrauth_objc_interface_sel)
+#define __ptrauth_objc_sel                                                     
\
+  __ptrauth(ptrauth_key_objc_sel_pointer, 1, __ptrauth_objc_sel_discriminator)
+#else
+#define __ptrauth_objc_sel
+#endif
+
+#define __ptrauth_objc_class_ro_discriminator 0x61f8
+#define __ptrauth_objc_class_ro                                                
\
+  __ptrauth(ptrauth_key_objc_class_ro_pointer, 1,                              
\
+            __ptrauth_objc_class_ro_discriminator)
+
 #else
 
 #define ptrauth_strip(__value, __key)                                          
\
@@ -331,6 +384,10 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
 #define ptrauth_cxx_vtable_pointer(key, address_discrimination,                
\
                                    extra_discrimination...)
 
+#define __ptrauth_objc_isa_pointer
+#define __ptrauth_objc_isa_uintptr
+#define __ptrauth_objc_super_pointer
+
 #endif /* __has_feature(ptrauth_intrinsics) */
 
 #endif /* __PTRAUTH_H */
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 9dbc3efbca405..bbd104909956f 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -5585,6 +5585,14 @@ Decl *SemaObjC::ActOnIvar(Scope *S, SourceLocation 
DeclStart, Declarator &D,
 
   TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
   QualType T = TInfo->getType();
+  ASTContext &Context = getASTContext();
+  if (Context.getLangOpts().PointerAuthObjcInterfaceSel &&
+      !T.getPointerAuth()) {
+    if (Context.isObjCSelType(T.getUnqualifiedType())) {
+      if (auto PAQ = Context.getObjCMemberSelTypePtrAuth())
+        T = Context.getPointerAuthType(T, PAQ);
+    }
+  }
 
   if (BitWidth) {
     // 6.7.2.1p3, 6.7.2.1p4
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp 
b/clang/lib/Sema/SemaObjCProperty.cpp
index 9d5106805892a..9dbb1d28aa722 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -1298,6 +1298,15 @@ Decl *SemaObjC::ActOnPropertyImplDecl(
         }
       }
 
+      if (Context.getLangOpts().PointerAuthObjcInterfaceSel &&
+          !PropertyIvarType.getPointerAuth()) {
+        if (Context.isObjCSelType(QualType(PropertyIvarType.getTypePtr(), 0))) 
{
+          if (auto PAQ = Context.getObjCMemberSelTypePtrAuth())
+            PropertyIvarType =
+                Context.getPointerAuthType(PropertyIvarType, PAQ);
+        }
+      }
+
       Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
                                   PropertyIvarLoc,PropertyIvarLoc, 
PropertyIvar,
                                   PropertyIvarType, /*TInfo=*/nullptr,
diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m
index 6dbd5057314e4..57afe9c245e77 100644
--- a/clang/test/CodeGenObjC/arc.m
+++ b/clang/test/CodeGenObjC/arc.m
@@ -1371,13 +1371,13 @@ void test71(void) {
 // CHECK: %[[T:.*]] = alloca [2 x ptr], align 16
 // CHECK: %[[V0:.*]] = call ptr @llvm.objc.retain(ptr %[[A]])
 // CHECK: %[[V1:.*]] = call ptr @llvm.objc.retain(ptr %[[B]]) #2
-// CHECK: %[[V3:.*]] = load ptr, ptr %[[A_ADDR]], align 8, !tbaa !7
+// CHECK: %[[V3:.*]] = load ptr, ptr %[[A_ADDR]], align 8, !tbaa !{{[0-9]+}}
 // CHECK: %[[V4:.*]] = call ptr @llvm.objc.retain(ptr %[[V3]]) #2
-// CHECK: store ptr %[[V4]], ptr %[[T]], align 8, !tbaa !7
+// CHECK: store ptr %[[V4]], ptr %[[T]], align 8, !tbaa !{{[0-9]+}}
 // CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds ptr, ptr %[[T]], 
i64 1
-// CHECK: %[[V5:.*]] = load ptr, ptr %[[B_ADDR]], align 8, !tbaa !7
+// CHECK: %[[V5:.*]] = load ptr, ptr %[[B_ADDR]], align 8, !tbaa !{{[0-9]+}}
 // CHECK: %[[V6:.*]] = call ptr @llvm.objc.retain(ptr %[[V5]]) #2
-// CHECK: store ptr %[[V6]], ptr %[[ARRAYINIT_ELEMENT]], align 8, !tbaa !7
+// CHECK: store ptr %[[V6]], ptr %[[ARRAYINIT_ELEMENT]], align 8, !tbaa 
!{{[0-9]+}}
 // CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x ptr], ptr %[[T]], 
i32 0, i32 0
 // CHECK: %[[V7:.*]] = getelementptr inbounds ptr, ptr %[[ARRAY_BEGIN]], i64 2
 
diff --git a/clang/test/CodeGenObjC/matrix-type-operators.m 
b/clang/test/CodeGenObjC/matrix-type-operators.m
index 179bb180daf90..ddd6c5f003f0a 100644
--- a/clang/test/CodeGenObjC/matrix-type-operators.m
+++ b/clang/test/CodeGenObjC/matrix-type-operators.m
@@ -13,11 +13,11 @@ @interface IntValue
 // CHECK-LABEL: @test_index_placeholders(
 // CHECK-NEXT:  entry:
 // CHECK:         [[IV:%.*]] = load ptr, ptr [[IV_ADDR:%.*]], align 8
-// CHECK-NEXT:    [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !7
+// CHECK-NEXT:    [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !{{[0-9]+}}
 // CHECK-NEXT:    [[CALL:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV]], 
ptr noundef [[SEL]])
 // CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[CALL]] to i64
 // CHECK-NEXT:    [[IV2:%.*]] = load ptr, ptr [[IV_ADDR]], align 8
-// CHECK-NEXT:    [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !7
+// CHECK-NEXT:    [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !{{[0-9]+}}
 // CHECK-NEXT:    [[CALL1:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV2]], 
ptr noundef [[SEL2]])
 // CHECK-NEXT:    [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
 // CHECK-NEXT:    [[IDX1:%.*]] = mul i64 [[CONV2]], 4
@@ -38,17 +38,17 @@ @interface MatrixValue
 
 // CHECK-LABEL: @test_base_and_index_placeholders(
 // CHECK:         [[IV:%.*]] = load ptr, ptr [[IV_ADDR:%.*]], align 8
-// CHECK-NEXT:    [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !7
+// CHECK-NEXT:    [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !{{[0-9]+}}
 // CHECK-NEXT:    [[CALL:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV]], 
ptr noundef [[SEL]])
 // CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[CALL]] to i64
 // CHECK-NEXT:    [[IV2:%.*]] = load ptr, ptr [[IV_ADDR]], align 8
-// CHECK-NEXT:    [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !7
+// CHECK-NEXT:    [[SEL2:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !{{[0-9]+}}
 // CHECK-NEXT:    [[CALL1:%.*]] = call i32 @objc_msgSend(ptr noundef [[IV2]], 
ptr noundef [[SEL2]])
 // CHECK-NEXT:    [[CONV2:%.*]] = sext i32 [[CALL1]] to i64
 // CHECK-NEXT:    [[IDX1:%.*]] = mul i64 [[CONV2]], 4
 // CHECK-NEXT:    [[IDX2:%.*]] = add i64 [[IDX1]], [[CONV]]
 // CHECK-NEXT:    [[M:%.*]] = load ptr, ptr %m.addr, align 8
-// CHECK-NEXT:    [[SEL3:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !7
+// CHECK-NEXT:    [[SEL3:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, 
align 8, !invariant.load !{{[0-9]+}}
 // CHECK-NEXT:    [[MAT:%.*]] = call <16 x double> @objc_msgSend(ptr noundef 
[[M]], ptr noundef [[SEL3]])
 // CHECK-NEXT:    [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 
[[IDX2]]
 // CHECK-NEXT:    ret double [[MATEXT]]
diff --git a/clang/test/CodeGenObjC/ptrauth-attr-exception.m 
b/clang/test/CodeGenObjC/ptrauth-attr-exception.m
new file mode 100644
index 0000000000000..8c07a698ecc70
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-attr-exception.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple arm64e -fptrauth-calls 
-fptrauth-vtable-pointer-address-discrimination 
-fptrauth-vtable-pointer-type-discrimination -emit-llvm -fexceptions 
-fobjc-exceptions -o - %s | FileCheck %s
+
+__attribute__((objc_root_class))
+@interface Root {
+  Class isa;
+}
+@end
+
+__attribute__((objc_exception))
+@interface A : Root
+@end
+
+@implementation A
+@end
+
+// CHECK: @"OBJC_EHTYPE_$_A" = global %struct._objc_typeinfo { ptr ptrauth 
(ptr getelementptr inbounds (ptr, ptr @objc_ehtype_vtable, i32 2), i32 2), ptr 
@OBJC_CLASS_NAME_, ptr @"OBJC_CLASS_$_A" }
+ //.      @"OBJC_EHTYPE_$_A" = global %struct._objc_typeinfo { ptr 
getelementptr inbounds (ptr, ptr @objc_ehtype_vtable, i32 2), ptr 
@OBJC_CLASS_NAME_, ptr @"OBJC_CLASS_$_A" }
diff --git a/clang/test/CodeGenObjC/ptrauth-block-isa.m 
b/clang/test/CodeGenObjC/ptrauth-block-isa.m
new file mode 100644
index 0000000000000..c1e98c6fd9d3e
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-block-isa.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fptrauth-calls -fptrauth-objc-isa -fobjc-arc -fblocks 
-triple arm64e -emit-llvm %s  -o - | FileCheck %s
+
+void (^globalblock)(void) = ^{};
+// CHECK: [[GLOBAL_BLOCK:@.*]] = internal constant { ptr, i32, i32, ptr, ptr } 
{ ptr ptrauth (ptr @_NSConcreteGlobalBlock, i32 2, i64 27361, ptr 
[[GLOBAL_BLOCK]]), i32 1342177280, i32 0, ptr @globalblock_block_invoke, ptr 
@"__block_descriptor_32_e5_v8\01?0l" }, align 8 #0
+
+@interface A
+- (int) count;
+@end
+
+void use_block(int (^)(void));
+
+// CHECK-LABEL: define dso_local void @test_block_literal(
+void test_block_literal(int i) {
+  // CHECK:      [[I:%.*]] = alloca i32,
+  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align
+  // CHECK:      [[ISAPTRADDR:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], 
ptr [[BLOCK]], i32 0, i32 0
+  // CHECK-NEXT: [[ISAPTRADDR_I:%.*]] = ptrtoint ptr [[ISAPTRADDR]] to i64
+  // CHECK-NEXT: [[ISADISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[ISAPTRADDR_I]], i64 27361)
+  // CHECK-NEXT: [[SIGNEDISA:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint 
(ptr @_NSConcreteStackBlock to i64), i32 2, i64 [[ISADISCRIMINATOR]])
+  // CHECK-NEXT: [[SIGNEDISAPTR:%.*]] = inttoptr i64 [[SIGNEDISA]] to ptr
+  // CHECK-NEXT: store ptr [[SIGNEDISAPTR]], ptr [[ISAPTRADDR]]
+  use_block(^{return i;});
+}
+
+void test_conversion_helper(id);
+
+// CHECK-LABEL: define dso_local void @test_conversion(
+void test_conversion(id a) {
+  // CHECK:      [[A:%.*addr]] = alloca ptr
+  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align
+  // CHECK:      [[ISAPTRADDR:%.*]] = getelementptr inbounds nuw [[BLOCK_T]], 
ptr [[BLOCK]], i32 0, i32 0
+  // CHECK-NEXT: [[ISAPTRADDR_I:%.*]] = ptrtoint ptr [[ISAPTRADDR]] to i64
+  // CHECK-NEXT: [[ISADISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[ISAPTRADDR_I]], i64 27361)
+  // CHECK-NEXT: [[SIGNEDISA:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint 
(ptr @_NSConcreteStackBlock to i64), i32 2, i64 [[ISADISCRIMINATOR]])
+  // CHECK-NEXT: [[SIGNEDISAPTR:%.*]] = inttoptr i64 [[SIGNEDISA]] to ptr
+  // CHECK-NEXT: store ptr [[SIGNEDISAPTR]], ptr [[ISAPTRADDR]]
+  test_conversion_helper(^{
+    (void)a;
+  });
+}
diff --git a/clang/test/CodeGenObjC/ptrauth-class-ro.m 
b/clang/test/CodeGenObjC/ptrauth-class-ro.m
new file mode 100644
index 0000000000000..d4364a9b8e332
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-class-ro.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fptrauth-calls -Wno-objc-root-class 
-fptrauth-objc-class-ro -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @"OBJC_CLASS_$_C" = global %struct._class_t { ptr 
@"OBJC_METACLASS_$_C", ptr null, ptr @_objc_empty_cache, ptr null, ptr ptrauth 
(ptr @"_OBJC_CLASS_RO_$_C", i32 2, i64 25080, ptr getelementptr inbounds 
(%struct._class_t, ptr @"OBJC_CLASS_$_C", i32 0, i32 4)) }, section "__DATA, 
__objc_data", align 8
+// CHECK: @"OBJC_METACLASS_$_C" = global %struct._class_t { ptr 
@"OBJC_METACLASS_$_C", ptr @"OBJC_CLASS_$_C", ptr @_objc_empty_cache, ptr null, 
ptr ptrauth (ptr @"_OBJC_METACLASS_RO_$_C", i32 2, i64 25080, ptr getelementptr 
inbounds (%struct._class_t, ptr @"OBJC_METACLASS_$_C", i32 0, i32 4)) }, 
section "__DATA, __objc_data", align 8
+// CHECK: @OBJC_CLASS_NAME_ = private unnamed_addr constant [2 x i8] c"C\00", 
section "__TEXT,__objc_classname,cstring_literals", align 1
+// CHECK: @"_OBJC_METACLASS_RO_$_C" = internal global %struct._class_ro_t { 
i32 131, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, 
ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+// CHECK: @OBJC_METH_VAR_NAME_ = private unnamed_addr constant [3 x i8] 
c"m0\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+// CHECK: @OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] 
c"v16@0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+// CHECK: @"_OBJC_$_INSTANCE_METHODS_C" = internal global { i32, i32, [1 x 
%struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] 
[%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr 
ptrauth (ptr @"\01-[C m0]", i32 0, i64 0, ptr getelementptr inbounds ({ i32, 
i32, [1 x %struct._objc_method] }, ptr @"_OBJC_$_INSTANCE_METHODS_C", i32 0, 
i32 2, i32 0, i32 2)) }] }, section "__DATA, __objc_const", align 8
+// CHECK: @"_OBJC_CLASS_RO_$_C" = internal global %struct._class_ro_t { i32 
130, i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr 
@"_OBJC_$_INSTANCE_METHODS_C", i32 2, i64 49936, ptr getelementptr inbounds 
(%struct._class_ro_t, ptr @"_OBJC_CLASS_RO_$_C", i32 0, i32 5)), ptr null, ptr 
null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+// CHECK: @OBJC_SELECTOR_REFERENCES_ = internal externally_initialized global 
ptr @OBJC_METH_VAR_NAME_, section 
"__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8
+// CHECK: @"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr 
@"OBJC_CLASS_$_C"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+
+@interface C
+- (void) m0;
+@end
+
+@implementation C
+- (void)m0 {}
+@end
+
+void test_sign_class_ro(C *c) {
+  [c m0];
+}
diff --git a/clang/test/CodeGenObjC/ptrauth-class.m 
b/clang/test/CodeGenObjC/ptrauth-class.m
new file mode 100644
index 0000000000000..c5ad03665f2a7
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-class.m
@@ -0,0 +1,103 @@
+// RUN: %clang_cc1 -Wno-everything -fblocks -fptrauth-intrinsics -triple 
arm64-apple-ios -fobjc-runtime=ios-12.2 -emit-llvm -no-enable-noundef-analysis 
-fobjc-arc -O2 -disable-llvm-passes -o - %s | FileCheck %s
+
+#if __has_feature(ptrauth_objc_signable_class)
+struct TestStruct {
+  __ptrauth(2, 1, 1234) Class isa;
+};
+
+@interface TestClass {
+@public
+  __ptrauth(2, 1, 1234) Class isa;
+}
+@end
+
+struct TestConstStruct {
+  __ptrauth(2, 1, 1234) const Class isa;
+  __ptrauth(2, 1, 1234) volatile Class visa;
+};
+
+@interface TestConstClass {
+@public
+  __ptrauth(2, 1, 1234) const Class isa;
+  __ptrauth(2, 1, 1234) volatile Class visa;
+}
+@end
+
+// CHECK-LABEL: define void @setTestStructIsa(ptr %t, ptr %c) #0 {
+void setTestStructIsa(struct TestStruct *t, Class c) {
+  t->isa = c;
+  // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: [[C_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: store ptr %c, ptr [[C_ADDR]], align 8
+  // CHECK: [[ISA_SLOT:%.*]] = getelementptr inbounds nuw %struct.TestStruct, 
ptr %0, i32 0, i32 0
+  // CHECK: [[C:%.*]] = load ptr, ptr %c.addr, align 8
+  // CHECK: [[CAST_ISA_SLOT:%.*]] = ptrtoint ptr [[ISA_SLOT]] to i64
+  // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[CAST_ISA_SLOT]], i64 1234)
+  // CHECK: [[CAST_C:%.*]] = ptrtoint ptr [[C]] to i64
+  // CHECK: [[AUTHENTICATED:%.*]] = call i64 @llvm.ptrauth.sign(i64 
[[CAST_C]], i32 2, i64 [[BLENDED_VALUE]])
+}
+
+// CHECK-LABEL: define void @setTestClassIsa(ptr %t, ptr %c) #0 {
+void setTestClassIsa(TestClass *t, Class c) {
+  t->isa = c;
+  // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: [[C_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: store ptr %c, ptr [[C_ADDR]], align 8
+  // CHECK: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
+  // CHECK: [[IVAR_OFFSET32:%.*]] = load i32, ptr 
@"OBJC_IVAR_$_TestClass.isa", align 8
+  // CHECK: [[IVAR_OFFSET64:%.*]] = sext i32 [[IVAR_OFFSET32]] to i64
+  // CHECK: [[ADDED_PTR:%.*]] = getelementptr inbounds i8, ptr %1, i64 
[[IVAR_OFFSET64]]
+  // CHECK: [[C_VALUE:%.*]] = load ptr, ptr [[C_ADDR]], align 8
+  // CHECK: [[CAST_ISA_SLOT:%.*]] = ptrtoint ptr [[ADDED_PTR]] to i64
+  // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[CAST_ISA_SLOT]], i64 1234)
+  // CHECK: [[CAST_C_VALUE:%.*]] = ptrtoint ptr [[C_VALUE]] to i64
+  // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CAST_C_VALUE]], 
i32 2, i64 [[BLENDED_VALUE]])
+}
+
+// CHECK-LABEL: define ptr @getTestStructIsa(ptr %t) #0 {
+Class getTestStructIsa(struct TestStruct *t) {
+  return t->isa;
+  // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: [[T_VALUE:%.*]] = load ptr, ptr [[T_ADDR]], align 8
+  // CHECK: [[ISA_SLOT:%.*]] = getelementptr inbounds nuw %struct.TestStruct, 
ptr [[T_VALUE]], i32 0, i32 0
+  // CHECK: [[ISA_VALUE:%.*]] = load ptr, ptr [[ISA_SLOT]], align 8
+  // CHECK: [[CAST_ISA_SLOT:%.*]] = ptrtoint ptr %isa to i64
+  // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[CAST_ISA_SLOT]], i64 1234)
+  // CHECK: [[CAST_ISA_VALUE:%.*]] = ptrtoint ptr [[ISA_VALUE]] to i64
+  // CHECK: [[SIGNED_VALUE:%.*]] = call i64 @llvm.ptrauth.auth(i64 
[[CAST_ISA_VALUE]], i32 2, i64 [[BLENDED_VALUE]])
+}
+
+// CHECK-LABEL: define ptr @getTestClassIsa(ptr %t) #0 {
+Class getTestClassIsa(TestClass *t) {
+  return t->isa;
+  // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
+  // CHECK: [[IVAR:%.*]] = load i32, ptr @"OBJC_IVAR_$_TestClass.isa", align 8
+  // CHECK: [[IVAR_CONV:%.*]] = sext i32 [[IVAR]] to i64
+  // CHECK: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[T]], i64 
[[IVAR_CONV]]
+  // CHECK: [[LOADED_VALUE:%.*]] = load ptr, ptr [[ADD_PTR]], align 8
+  // CHECK: [[INT_VALUE:%.*]] = ptrtoint ptr [[ADD_PTR]] to i64
+  // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[INT_VALUE]], i64 1234)
+  // CHECK: [[NULL_CHECK:%.*]] = icmp ne ptr [[LOADED_VALUE]], null
+  // CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[LOADED_VALUE]] to i64
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VALUE]], 
i32 2, i64 [[BLENDED_VALUE]])
+}
+
+// Just enough to verify we do actually authenticate qualified Class
+// CHECK: define ptr @getTestConstClassIsa(ptr %t) #0 {
+Class getTestConstClassIsa(TestConstClass *t) {
+  return t->isa;
+  // CHECK: [[T_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
+  // CHECK: [[IVAR:%.*]] = load i32, ptr @"OBJC_IVAR_$_TestConstClass.isa", 
align 8
+  // CHECK: [[IVAR_CONV:%.*]] = sext i32 [[IVAR]] to i64
+  // CHECK: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[T]], i64 
[[IVAR_CONV]]
+  // CHECK: [[LOADED_VALUE:%.*]] = load ptr, ptr [[ADD_PTR]], align 8
+  // CHECK: [[INT_VALUE:%.*]] = ptrtoint ptr [[ADD_PTR]] to i64
+  // CHECK: [[BLENDED_VALUE:%.*]] = call i64 @llvm.ptrauth.blend(i64 
[[INT_VALUE]], i64 1234)
+  // CHECK: [[NULL_CHECK:%.*]] = icmp ne ptr [[LOADED_VALUE]], null
+  // CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[LOADED_VALUE]] to i64
+  // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VALUE]], 
i32 2, i64 [[BLENDED_VALUE]])
+}
+
+#endif
diff --git a/clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m 
b/clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m
new file mode 100644
index 0000000000000..53734bb1121fa
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-objc-interface-selector.m
@@ -0,0 +1,130 @@
+// RUN: %clang_cc1 -O0 -Wno-objc-root-class -fptrauth-intrinsics 
-fptrauth-calls -nostdsysteminc -triple arm64e-apple-ios -emit-llvm 
-fptrauth-objc-interface-sel -o - %s | FileCheck 
--check-prefix=CHECK-AUTHENTICATED-SEL %s
+// RUN: %clang_cc1 -O0 -Wno-objc-root-class -fptrauth-intrinsics 
-fptrauth-calls -nostdsysteminc -triple arm64e-apple-ios -emit-llvm -o - %s | 
FileCheck --check-prefix=CHECK-UNAUTHENTICATED-SEL %s
+
+#include <ptrauth.h>
+#define __ptrauth_objc_sel_override                 \
+  __ptrauth(ptrauth_key_objc_sel_pointer, 1, 22467)
+
+@interface Test {
+@public
+  SEL auto_sel;
+@public
+  const SEL const_auto_sel;
+@public
+  volatile SEL volatile_auto_sel;
+@public
+  SEL __ptrauth_objc_sel_override manual;
+@public
+  const SEL __ptrauth_objc_sel_override const_manual;
+@public
+  volatile SEL __ptrauth_objc_sel_override volatile_manual;
+@public
+
+  SEL __ptrauth_objc_sel_override _manual_sel_property;
+}
+
+@property SEL auto_sel_property;
+@property const SEL const_auto_sel_property;
+@property volatile SEL volatile_auto_sel_property;
+@property SEL manual_sel_property;
+
+@end
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test test:]"
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
{{%.*}}, i32 3, i64 {{%.*}}, i32 3, i64 {{%.*}})
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = load volatile ptr, ptr {{%.*}}, align 8
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
{{%.*}}, i32 3, i64 {{%.*}}, i32 3, i64 {{%.*}})
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22467)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22467)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
{{%.*}}, i32 3, i64 {{%.*}}, i32 3, i64 {{%.*}})
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, 
i32 3, i64 {{%.*}})
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test 
auto_sel_property]"
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, 
i32 3, i64 {{%.*}})
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define internal void @"\01-[Test 
setAuto_sel_property:]"
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.sign(i64 {{%.*}}, 
i32 3, i64 {{%.*}})
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test 
const_auto_sel_property]"
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, 
i32 3, i64 {{%.*}})
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define internal void @"\01-[Test 
setConst_auto_sel_property:]"
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.sign(i64 {{%.*}}, 
i32 3, i64 {{%.*}})
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define internal ptr @"\01-[Test 
volatile_auto_sel_property]"
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.auth(i64 {{%.*}}, 
i32 3, i64 {{%.*}})
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define internal void @"\01-[Test 
setVolatile_auto_sel_property:]"
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.sign(i64 {{%.*}}, 
i32 3, i64 {{%.*}})
+
+@implementation Test
+- (SEL)test:(Test *)in {
+  _auto_sel_property = in->_auto_sel_property;
+  _volatile_auto_sel_property = in->_volatile_auto_sel_property;
+  _manual_sel_property = in->_manual_sel_property;
+  return _const_auto_sel_property;
+}
+@end
+
+void auto_sel(Test *out, Test *in) {
+  out->auto_sel = in->auto_sel;
+}
+// CHECK-AUTHENTICATED-SEL-LABEL: define void @auto_sel
+// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
+
+// CHECK-UNAUTHENTICATED-SEL-LABEL: define void @auto_sel
+SEL const_auto_sel(Test *in) {
+  return in->const_auto_sel;
+}
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define ptr @const_auto_sel
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64
+// CHECK-AUTHENTICATED-SEL: [[AUTHENTICATED:%.*]] = call i64 
@llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}})
+// CHECK-AUTHENTICATED-SEL: [[RESULT:%.*]] = inttoptr i64 [[AUTHENTICATED]] to 
ptr
+
+void volatile_auto_sel(Test *out, Test *in) {
+  out->volatile_auto_sel = in->volatile_auto_sel;
+}
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define void @volatile_auto_sel
+// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
+
+void manual(Test *out, Test *in) {
+  out->manual = in->manual;
+}
+
+// CHECK-AUTHENTICATED-SEL-LABEL: define void @manual
+// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467)
+// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467)
+// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
+
+// CHECK-UNAUTHENTICATED-SEL-LABEL: define void @manual
+// CHECK-UNAUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467)
+// CHECK-UNAUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-UNAUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467)
+// CHECK-UNAUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-UNAUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
diff --git a/clang/test/CodeGenObjC/ptrauth-objc-isa-super.m 
b/clang/test/CodeGenObjC/ptrauth-objc-isa-super.m
new file mode 100644
index 0000000000000..69fd01f28067d
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-objc-isa-super.m
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -I %S/Inputs -fptrauth-calls -fptrauth-objc-isa -triple 
arm64-apple-ios -emit-llvm -no-enable-noundef-analysis -fblocks -fobjc-arc 
-fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s
+
+#include "literal-support.h"
+
+#if __has_feature(objc_bool)
+#define YES __objc_yes
+#define NO __objc_no
+#else
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+#endif
+
+@class NSString;
+
+// CHECK: @"OBJC_METACLASS_$_C" = global %struct._class_t { ptr ptrauth (ptr 
@"OBJC_METACLASS_$_Base", i32 2, i64 27361, ptr @"OBJC_METACLASS_$_C"), ptr 
ptrauth (ptr @"OBJC_METACLASS_$_Base", i32 2, i64 46507, ptr getelementptr 
inbounds (%struct._class_t, ptr @"OBJC_METACLASS_$_C", i32 0, i32 1)), ptr 
@_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_C" }
+// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_" = private global ptr 
@"OBJC_METACLASS_$_C"
+// CHECK: @OBJC_METH_VAR_NAME_ = private unnamed_addr constant [5 x i8] 
c"test\00"
+// CHECK: @OBJC_SELECTOR_REFERENCES_ = internal externally_initialized global 
ptr @OBJC_METH_VAR_NAME_
+// CHECK: @"OBJC_METACLASS_$_Base" = external global %struct._class_t
+// CHECK: @OBJC_CLASS_NAME_ = private unnamed_addr constant [2 x i8] c"C\00"
+// CHECK: @OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [11 x i8] 
c"super_test\00"
+// CHECK: @OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] 
c"v16@0:8\00"
+// CHECK: @"_OBJC_$_CLASS_METHODS_C" = internal global { i32, i32, [1 x 
%struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] 
[%struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, 
ptr ptrauth (ptr @"\01+[C super_test]", i32 0, i64 0, ptr getelementptr 
inbounds ({ i32, i32, [1 x %struct._objc_method] }, ptr 
@"_OBJC_$_CLASS_METHODS_C", i32 0, i32 2, i32 0, i32 2)) }] }
+// CHECK: @"_OBJC_METACLASS_RO_$_C" = internal global %struct._class_ro_t { 
i32 129, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr 
@"_OBJC_$_CLASS_METHODS_C", i32 2, i64 49936, ptr getelementptr inbounds 
(%struct._class_ro_t, ptr @"_OBJC_METACLASS_RO_$_C", i32 0, i32 5)), ptr null, 
ptr null, ptr null, ptr null }
+// CHECK: @"OBJC_CLASS_$_Base" = external global %struct._class_t
+// CHECK: @"_OBJC_CLASS_RO_$_C" = internal global %struct._class_ro_t { i32 
128, i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr 
null, ptr null, ptr null }
+//        @"_OBJC_CLASS_RO_$_C" = internal global %struct._class_ro_t { i32 
128, i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr null, i32 
2, i64 49936, ptr getelementptr inbounds (%struct._class_ro_t, ptr 
@"_OBJC_CLASS_RO_$_C", i32 0, i32 5)), ptr null, ptr null, ptr null, ptr null }
+// CHECK: @"OBJC_CLASS_$_C" = global %struct._class_t { ptr ptrauth (ptr 
@"OBJC_METACLASS_$_C", i32 2, i64 27361, ptr @"OBJC_CLASS_$_C"), ptr ptrauth 
(ptr @"OBJC_CLASS_$_Base", i32 2, i64 46507, ptr getelementptr inbounds 
(%struct._class_t, ptr @"OBJC_CLASS_$_C", i32 0, i32 1)), ptr 
@_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_C" }
+// CHECK: @"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr 
@"OBJC_CLASS_$_C"]
+
+@interface Base
++ (void)test;
+@end
+
+@interface C : Base
+@end
+
+@implementation C
+// CHECK-LABEL: define internal void @"\01+[C super_test]"(ptr %self, ptr 
%_cmd) #1 {
++ (void)super_test {
+  return [super test];
+  // CHECK: [[SELF_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: [[CMD_ADDR:%.*]] = alloca ptr, align 8
+  // CHECK: [[SUPER_STRUCT:%.*]] = alloca %struct._objc_super, align 8
+  // CHECK: store ptr %self, ptr [[SELF_ADDR]], align 8, !tbaa !{{[0-9]+}}
+  // CHECK: store ptr %_cmd, ptr [[CMD_ADDR]], align 8, !tbaa !{{[0-9]+}}
+  // CHECK: [[TARGET:%.*]] = load ptr, ptr [[SELF_ADDR]], align 8, !tbaa 
!{{[0-9]+}}
+  // CHECK: [[OBJC_SUPER_TARGET:%.*]] = getelementptr inbounds nuw 
%struct._objc_super, ptr [[SUPER_STRUCT]], i32 0, i32 0
+  // CHECK: store ptr [[TARGET]], ptr [[OBJC_SUPER_TARGET]], align 8
+  // CHECK: [[SUPER_REFERENCES:%.*]] = load ptr, ptr 
@"OBJC_CLASSLIST_SUP_REFS_$_"
+  // CHECK: [[OBJC_SUPER_SUPER:%.*]] = getelementptr inbounds nuw 
%struct._objc_super, ptr [[SUPER_STRUCT]], i32 0, i32 1
+  // CHECK: store ptr [[SUPER_REFERENCES]], ptr [[OBJC_SUPER_SUPER:%.*]], 
align 8
+  // CHECK: call void @objc_msgSendSuper2(ptr %objc_super, ptr %4)
+}
+@end
+
+id str = @"";
diff --git a/clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m 
b/clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m
new file mode 100644
index 0000000000000..e7cb5642ee490
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-objc-method-list-pointer.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -Wno-objc-root-class -fptrauth-calls -triple arm64e 
-fptrauth-objc-class-ro %s -emit-llvm -o - | FileCheck %s
+@interface X
+@end
+
+@implementation X
+-(void)meth {}
+@end
+
+// CHECK: @"OBJC_CLASS_$_X" = global %struct._class_t { ptr 
@"OBJC_METACLASS_$_X", ptr null, ptr @_objc_empty_cache, ptr null, ptr ptrauth 
(ptr @"_OBJC_CLASS_RO_$_X", i32 2, i64 25080, ptr getelementptr inbounds 
(%struct._class_t, ptr @"OBJC_CLASS_$_X", i32 0, i32 4)) }
+// CHECK: @"OBJC_METACLASS_$_X" = global %struct._class_t { ptr 
@"OBJC_METACLASS_$_X", ptr @"OBJC_CLASS_$_X", ptr @_objc_empty_cache, ptr null, 
ptr ptrauth (ptr @"_OBJC_METACLASS_RO_$_X", i32 2, i64 25080, ptr getelementptr 
inbounds (%struct._class_t, ptr @"OBJC_METACLASS_$_X", i32 0, i32 4)) }
+// CHECK: @OBJC_CLASS_NAME_ = private unnamed_addr constant [2 x i8] c"X\00"
+// CHECK: @"_OBJC_METACLASS_RO_$_X" = private global %struct._class_ro_t { i32 
3, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr 
null, ptr null, ptr null }
+// CHECK: @OBJC_METH_VAR_NAME_ = private unnamed_addr constant [5 x i8] 
c"meth\00"
+// CHECK: @OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] 
c"v16@0:8\00"
+// CHECK: @"_OBJC_$_INSTANCE_METHODS_X" = private global { i32, i32, [1 x 
%struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] 
[%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr 
ptrauth (ptr @"\01-[X meth]", i32 0, i64 0, ptr getelementptr inbounds ({ i32, 
i32, [1 x %struct._objc_method] }, ptr @"_OBJC_$_INSTANCE_METHODS_X", i32 0, 
i32 2, i32 0, i32 2)) }] }
+// CHECK: @"_OBJC_CLASS_RO_$_X" = private global %struct._class_ro_t { i32 2, 
i32 0, i32 0, ptr null, ptr @OBJC_CLASS_NAME_, ptr ptrauth (ptr 
@"_OBJC_$_INSTANCE_METHODS_X", i32 2, i64 49936, ptr getelementptr inbounds 
(%struct._class_ro_t, ptr @"_OBJC_CLASS_RO_$_X", i32 0, i32 5)), ptr null, ptr 
null, ptr null, ptr null }
+// CHECK: @"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr 
@"OBJC_CLASS_$_X"]
diff --git a/clang/test/CodeGenObjC/ptrauth-property-backing.m 
b/clang/test/CodeGenObjC/ptrauth-property-backing.m
new file mode 100644
index 0000000000000..8c6bcb45e7446
--- /dev/null
+++ b/clang/test/CodeGenObjC/ptrauth-property-backing.m
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm 
-fexceptions -fptrauth-intrinsics -o - %s | FileCheck %s
+
+typedef void (*func)();
+
+__attribute__((objc_root_class))
+@interface Root {
+  Class isa;
+  void *__ptrauth(1, 1, 1) _field1;
+  void *__ptrauth(1, 1, 1) _field2;
+  func __ptrauth(1, 1, 1) _field3;
+  func __ptrauth(1, 1, 123) _field4;
+}
+
+@property void *field1;
+@property(nonatomic) void *field2;
+@property func field3;
+@property(nonatomic) func field4;
+@end
+
+@implementation Root
+@end
+
+// CHECK-LABEL: define internal ptr @"\01-[Root field1]"
+// CHECK: [[LOAD:%.*]] = load atomic i64, ptr [[ADDR:%.*]] unordered
+// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 
1)
+// CHECK: [[RESULT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[LOAD]], i32 1, 
i64 [[BLEND]])
+
+// CHECK-LABEL: define internal void @"\01-[Root setField1:]"
+// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR:%.*]] to i64
+// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 
1)
+// CHECK: [[RESULT:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[VALUE:%.*]], i32 
1, i64 [[BLEND]])
+// CHECK: [[PHI:%.*]] = phi i64 [ 0, {{%.*}} ], [ [[RESULT]], {{%.*}} ]
+// CHECK: store atomic i64 [[PHI]], ptr [[ADDR]] unordered
+
+// CHECK-LABEL: define internal ptr @"\01-[Root field2]"
+// CHECK: load ptr, ptr
+// CHECK: [[LOAD:%.*]] = load ptr, ptr [[ADDR:%.*]],
+// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR:%.*]], 
i64 1)
+// CHECK: [[VALUE:%.*]] = ptrtoint ptr [[LOAD]] to i64
+// CHECK: [[RESULT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, 
i64 [[BLEND]])
+
+// CHECK-LABEL: define internal void @"\01-[Root setField2:]"
+// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR:%.*]] to i64
+// CHECK: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 
1)
+// CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[VALUE:%.*]] to i64
+// CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CAST_VALUE]], i32 
1, i64 [[BLEND]])
+// CHECK: [[RESULT:%.*]] = inttoptr i64 [[SIGNED]] to ptr
+// CHECK: [[PHI:%.*]] = phi ptr [ null, {{%.*}} ], [ [[RESULT]], {{%.*}} ]
+// CHECK: store ptr [[PHI]], ptr [[ADDR]]
+
+// CHECK-LABEL: define internal ptr @"\01-[Root field3]"
+// CHECK: [[VALUE:%.*]] = load atomic i64, ptr [[ADDR:%.*]] unordered, align 8
+// CHECK: [[CASTED_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTED_ADDR]], 
i64 1)
+// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[VALUE]], i32 1, i64 
[[BLENDED]], i32 0, i64 0
+
+// CHECK-LABEL: define internal void @"\01-[Root setField3:]"
+// CHECK: [[VALUE:%.*]] = load i64, ptr {{%.*}}, align 8
+// CHECK: [[CASTED_ADDR:%.*]] = ptrtoint ptr {{%.*}} to i64
+// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTED_ADDR]], 
i64 1)
+// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[VALUE]], i32 0, i64 0, 
i32 1, i64 [[BLENDED]])
+// CHECK: store atomic i64
+
+// CHECK-LABEL: define internal ptr @"\01-[Root field4]"
+// CHECK: load ptr, ptr
+// CHECK: [[VALUE:%.*]] = load ptr, ptr [[ADDR:%.*]],
+// CHECK: [[CASTED_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTED_ADDR]], 
i64 123)
+// CHECK: [[CAST_VALUE:%.*]] = ptrtoint ptr [[VALUE]] to i64
+// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[CAST_VALUE]], i32 1, 
i64 [[BLENDED]], i32 0, i64 0)
+
+// CHECK-LABEL: define internal void @"\01-[Root setField4:]"
+// CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr {{%.*}} to i64
+// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], 
i64 123)
+// CHECK: resign.nonnull:
+// CHECK: [[VALUE:%.*]] = ptrtoint ptr %1 to i64
+// CHECK: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 [[VALUE]], i32 0, i64 0, 
i32 1, i64 [[BLENDED]])
+
diff --git a/clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm 
b/clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm
new file mode 100644
index 0000000000000..fc90f5ffcbcf6
--- /dev/null
+++ b/clang/test/CodeGenObjCXX/ptrauth-objc-interface-selector.mm
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -O0 -Wobjc-root-class -fptrauth-intrinsics -fptrauth-calls 
-nostdsysteminc -triple arm64e-apple-ios -emit-llvm 
-fptrauth-objc-interface-sel -o - %s | FileCheck 
--check-prefix=CHECK-AUTHENTICATED-SEL %s
+// RUN: %clang_cc1 -O0 -Wobjc-root-class -fptrauth-intrinsics -fptrauth-calls 
-nostdsysteminc -triple arm64e-apple-ios -emit-llvm -o - %s | FileCheck 
--check-prefix=CHECK-UNAUTHENTICATED-SEL %s
+
+#include <ptrauth.h>
+#define __ptrauth_objc_sel_override                 \
+  __ptrauth(ptrauth_key_objc_sel_pointer, 1, 22467)
+
+extern "C" {
+
+@interface Test {
+@public
+  SEL auto_sel;
+@public
+  const SEL const_auto_sel;
+@public
+  volatile SEL volatile_auto_sel;
+@public
+  SEL __ptrauth_objc_sel_override manual;
+@public
+  const SEL __ptrauth_objc_sel_override const_manual;
+@public
+  volatile SEL __ptrauth_objc_sel_override volatile_manual;
+}
+
+@end
+#if __has_feature(ptrauth_objc_interface_sel)
+typedef const SEL __ptrauth_objc_sel const_auto_sel_ptr_type;
+const_auto_sel_ptr_type *const_auto_sel_ptr_type_test;
+typedef volatile SEL __ptrauth_objc_sel volatile_auto_sel_ptr_type;
+volatile_auto_sel_ptr_type *volatile_auto_sel_ptr_type_test;
+#else
+typedef const SEL const_auto_sel_ptr_type;
+const_auto_sel_ptr_type *const_auto_sel_ptr_type_test;
+typedef volatile SEL volatile_auto_sel_ptr_type;
+volatile_auto_sel_ptr_type *volatile_auto_sel_ptr_type_test;
+#endif
+
+void auto_sel(Test *out, Test *in) {
+  out->auto_sel = in->auto_sel;
+}
+// CHECK-AUTHENTICATED-SEL: define void @auto_sel
+// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
+
+// CHECK-UNAUTHENTICATED-SEL: define void @auto_sel
+SEL const_auto_sel(Test *in) {
+  const_auto_sel_ptr_type_test = &in->const_auto_sel;
+  return in->const_auto_sel;
+}
+
+// CHECK-AUTHENTICATED-SEL: define ptr @const_auto_sel
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.blend(i64 
{{%.*}}, i64 22466)
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = ptrtoint ptr {{%.*}} to i64
+// CHECK-AUTHENTICATED-SEL: [[AUTHENTICATED:%.*]] = call i64 
@llvm.ptrauth.auth(i64 {{%.*}}, i32 3, i64 {{%.*}})
+// CHECK-AUTHENTICATED-SEL: [[RESULT:%.*]] = inttoptr i64 [[AUTHENTICATED]] to 
ptr
+
+void volatile_auto_sel(Test *out, Test *in) {
+  volatile_auto_sel_ptr_type_test = &in->volatile_auto_sel;
+  out->volatile_auto_sel = in->volatile_auto_sel;
+}
+
+// CHECK-AUTHENTICATED-SEL: define void @volatile_auto_sel
+// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22466)
+// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
+
+void manual(Test *out, Test *in) {
+  out->manual = in->manual;
+}
+
+// CHECK-AUTHENTICATED-SEL: define void @manual
+// CHECK-AUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467)
+// CHECK-AUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467)
+// CHECK-AUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-AUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
+
+// CHECK-UNAUTHENTICATED-SEL: define void @manual
+// CHECK-UNAUTHENTICATED-SEL: [[DST_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_DST_ADDR:%.*]], i64 22467)
+// CHECK-UNAUTHENTICATED-SEL: [[CAST_SRC_ADDR:%.*]] = ptrtoint ptr 
[[SRC_ADDR:%.*]] to i64
+// CHECK-UNAUTHENTICATED-SEL: [[SRC_DESCRIMINATOR:%.*]] = call i64 
@llvm.ptrauth.blend(i64 [[CAST_SRC_ADDR]], i64 22467)
+// CHECK-UNAUTHENTICATED-SEL: [[SRC_SEL:%.*]] = ptrtoint ptr 
[[SRC_SEL_ADDR:%.*]] to i64
+// CHECK-UNAUTHENTICATED-SEL: {{%.*}} = call i64 @llvm.ptrauth.resign(i64 
[[SRC_SEL]], i32 3, i64 [[DST_DESCRIMINATOR]], i32 3, i64 [[SRC_DESCRIMINATOR]])
+
+}
diff --git a/clang/test/SemaObjC/ptrauth-pointers.m 
b/clang/test/SemaObjC/ptrauth-pointers.m
new file mode 100644
index 0000000000000..5a3bd49d74f0d
--- /dev/null
+++ b/clang/test/SemaObjC/ptrauth-pointers.m
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -fblocks -triple arm64-apple-ios -fptrauth-calls 
-fptrauth-intrinsics -verify %s
+
+#if __has_feature(ptrauth_objc_signable_class)
+@class TestClass;
+typedef TestClass *ClassPtr;
+typedef void(^BlockPtr)();
+@interface TestClass {
+@public
+  __ptrauth(2, 1, 1) Class a;
+  __ptrauth(2, 1, 3) volatile Class vi;
+  __ptrauth(2, 1, 3) const Class ci;
+  __ptrauth(2, 1, 1) id b;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'id' is invalid}}
+  __ptrauth(2, 1, 2) ClassPtr c;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'ClassPtr' (aka 'TestClass *') is invalid}}
+  __ptrauth(2, 1, 2) BlockPtr d;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'BlockPtr' (aka 'void (^)()') is invalid}}
+}
+
+struct TestStruct {
+  __ptrauth(2, 1, 3) Class e;
+  __ptrauth(2, 1, 3) volatile Class vi;
+  __ptrauth(2, 1, 3) const Class ci;
+  __ptrauth(2, 1, 4) id f;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'id' is invalid}}
+  __ptrauth(2, 1, 5) ClassPtr g;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'ClassPtr' (aka 'TestClass *') is invalid}}
+  __ptrauth(2, 1, 2) BlockPtr h;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'BlockPtr' (aka 'void (^)()') is invalid}}
+};
+
+@end
+
+void foo() {
+  __ptrauth(2, 1, 3) Class i;
+  __ptrauth(2, 1, 3) volatile Class vi;
+  __ptrauth(2, 1, 3) const Class ci = 0;
+  __ptrauth(2, 1, 4) id j;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'id' is invalid}}
+  __ptrauth(2, 1, 5) ClassPtr k;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'ClassPtr' (aka 'TestClass *') is invalid}}
+  __ptrauth(2, 1, 2) BlockPtr l;
+  // expected-error@-1 {{'__ptrauth' qualifier only applies to pointer or 
pointer sized integer types; 'BlockPtr' (aka 'void (^)()') is invalid}}
+}
+
+#endif
diff --git a/clang/test/SemaObjC/ptrauth-qualifier.m 
b/clang/test/SemaObjC/ptrauth-qualifier.m
index 98d0248f169be..74bbe6f09899b 100644
--- a/clang/test/SemaObjC/ptrauth-qualifier.m
+++ b/clang/test/SemaObjC/ptrauth-qualifier.m
@@ -18,12 +18,24 @@ @interface Foo
 @property void *__ptrauth(1, 0, 1) invalid2;
 // expected-error@-1 {{property may not be qualified with '__ptrauth'; type is 
'void *__ptrauth(1,0,1)'}}
 
+@property unsigned long long __ptrauth(1, 1, 1) invalid3;
+// expected-error@-1 {{property may not be qualified with '__ptrauth'; type is 
'__ptrauth(1,1,1) unsigned long long'}}
+
+@property unsigned long long __ptrauth(1, 0, 1) invalid4;
+// expected-error@-1 {{property may not be qualified with '__ptrauth'; type is 
'__ptrauth(1,0,1) unsigned long long'}}
+
 - (void *__ptrauth(1, 1, 1))invalid5;
 // expected-error@-1 {{return type may not be qualified with '__ptrauth'; type 
is 'void *__ptrauth(1,1,1)'}}
 
 - (void *__ptrauth(1, 0, 1))invalid6;
 // expected-error@-1 {{return type may not be qualified with '__ptrauth'; type 
is 'void *__ptrauth(1,0,1)'}}
 
+- (unsigned long long __ptrauth(1, 1, 1))invalid7;
+// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type 
is '__ptrauth(1,1,1) unsigned long long'}}
+
+- (unsigned long long __ptrauth(1, 0, 1))invalid8;
+// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type 
is '__ptrauth(1,0,1) unsigned long long'}}
+
 - (void)invalid9:(void *__ptrauth(1, 1, 1))a;
 // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is 'void *__ptrauth(1,1,1)'}}
 // expected-note@-2 {{method 'invalid9:' declared here}}
@@ -32,10 +44,17 @@ - (void)invalid10:(void *__ptrauth(1, 0, 1))a;
 // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is 'void *__ptrauth(1,0,1)'}}
 // expected-note@-2 {{method 'invalid10:' declared here}}
 
+- (void)invalid11:(unsigned long long __ptrauth(1, 1, 1))a;
+// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is '__ptrauth(1,1,1) unsigned long long'}}
+// expected-note@-2 {{method 'invalid11:' declared here}}
+
+- (void)invalid12:(unsigned long long __ptrauth(1, 0, 1))a;
+// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is '__ptrauth(1,0,1) unsigned long long'}}
+// expected-note@-2 {{method 'invalid12:' declared here}}
 @end
 
 @implementation Foo
-// expected-warning@-1 2{{method definition for}}
+// expected-warning@-1 4{{method definition for}}
 
 - (void *__ptrauth(1, 1, 1))invalid13 {
 // expected-error@-1 {{return type may not be qualified with '__ptrauth'; type 
is 'void *__ptrauth(1,1,1)'}}
@@ -47,6 +66,16 @@ @implementation Foo
   return 0;
 }
 
+- (unsigned long long __ptrauth(1, 1, 1))invalid15 {
+// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type 
is '__ptrauth(1,1,1) unsigned long long'}}
+  return 0;
+}
+
+- (unsigned long long __ptrauth(1, 0, 1))invalid16 {
+// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type 
is '__ptrauth(1,0,1) unsigned long long'}}
+  return 0;
+}
+
 - (void)invalid17:(void *__ptrauth(1, 1, 1))a {
 // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is 'void *__ptrauth(1,1,1)'}}
 }
@@ -55,4 +84,12 @@ - (void)invalid18:(void *__ptrauth(1, 0, 1))a {
 // expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is 'void *__ptrauth(1,0,1)'}}
 }
 
+- (void)invalid19:(unsigned long long __ptrauth(1, 1, 1))a {
+// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is '__ptrauth(1,1,1) unsigned long long'}}
+}
+
+- (void)invalid20:(unsigned long long __ptrauth(1, 0, 1))a {
+// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; 
type is '__ptrauth(1,0,1) unsigned long long'}}
+}
+
 @end

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

Reply via email to