https://github.com/ahatanak updated 
https://github.com/llvm/llvm-project/pull/109056

>From eede4b2c2916a3016643fb56f87f7601dfaff69b Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahata...@gmail.com>
Date: Mon, 16 Sep 2024 17:12:13 -0700
Subject: [PATCH 1/4] [PAC] Re-sign a pointer to a noexcept member function
 when it is converted to a pointer to a member function without noexcept

Fixes https://github.com/llvm/llvm-project/issues/106487.
---
 clang/lib/CodeGen/CGExprScalar.cpp            |   9 +-
 clang/lib/CodeGen/ItaniumCXXABI.cpp           |  28 ++++-
 .../ptrauth-member-function-pointer.cpp       | 109 +++++++++++++++++-
 3 files changed, 136 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 82caf65ac68d6b..76e2f047e84ae4 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2419,8 +2419,13 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
     return Visit(const_cast<Expr*>(E));
 
   case CK_NoOp: {
-    return CE->changesVolatileQualification() ? EmitLoadOfLValue(CE)
-                                              : Visit(const_cast<Expr *>(E));
+    if (CE->changesVolatileQualification())
+      return EmitLoadOfLValue(CE);
+    auto V = Visit(const_cast<Expr *>(E));
+    if (CGF.CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers &&
+        CE->getType()->isMemberFunctionPointerType())
+      V = CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, V);
+    return V;
   }
 
   case CK_BaseToDerived: {
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index dcc35d5689831e..085ed84b5108b4 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -924,17 +924,20 @@ 
ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
   if (isa<llvm::Constant>(src))
     return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));
 
+  QualType DstType = E->getType(), SrcType = E->getSubExpr()->getType();
+
   assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
          E->getCastKind() == CK_BaseToDerivedMemberPointer ||
-         E->getCastKind() == CK_ReinterpretMemberPointer);
+         E->getCastKind() == CK_ReinterpretMemberPointer ||
+         (E->getCastKind() == CK_NoOp &&
+          getContext().hasSameFunctionTypeIgnoringExceptionSpec(
+              DstType->getPointeeType(), SrcType->getPointeeType())));
 
   CGBuilderTy &Builder = CGF.Builder;
-  QualType DstType = E->getType();
 
   if (DstType->isMemberFunctionPointerType()) {
     if (const auto &NewAuthInfo =
             CGM.getMemberFunctionPointerAuthInfo(DstType)) {
-      QualType SrcType = E->getSubExpr()->getType();
       assert(SrcType->isMemberFunctionPointerType());
       const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);
       llvm::Value *MemFnPtr = Builder.CreateExtractValue(src, 0, "memptr.ptr");
@@ -971,6 +974,11 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction 
&CGF,
     }
   }
 
+  // Conversion from a pointer to a noexcept member function to a pointer to a
+  // member function without noexcept doesn't require any additional 
processing.
+  if (E->getCastKind() == CK_NoOp)
+    return src;
+
   // Under Itanium, reinterprets don't require any additional processing.
   if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
 
@@ -1045,16 +1053,24 @@ pointerAuthResignMemberFunctionPointer(llvm::Constant 
*Src, QualType DestType,
 llvm::Constant *
 ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
                                            llvm::Constant *src) {
+  QualType DstType = E->getType(), SrcType = E->getSubExpr()->getType();
+
   assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
          E->getCastKind() == CK_BaseToDerivedMemberPointer ||
-         E->getCastKind() == CK_ReinterpretMemberPointer);
-
-  QualType DstType = E->getType();
+         E->getCastKind() == CK_ReinterpretMemberPointer ||
+         (E->getCastKind() == CK_NoOp &&
+          getContext().hasSameFunctionTypeIgnoringExceptionSpec(
+              DstType->getPointeeType(), SrcType->getPointeeType())));
 
   if (DstType->isMemberFunctionPointerType())
     src = pointerAuthResignMemberFunctionPointer(
         src, DstType, E->getSubExpr()->getType(), CGM);
 
+  // Conversion from a pointer to a noexcept member function to a pointer to a
+  // member function without noexcept doesn't require any additional 
processing.
+  if (E->getCastKind() == CK_NoOp)
+    return src;
+
   // Under Itanium, reinterprets don't require any additional processing.
   if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
 
diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp 
b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
index 0a9ac3fa510f56..3408e7e18c3adc 100644
--- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
+++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
@@ -1,10 +1,12 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN %s
+// RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN,CXX11 %s
+// RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN,CXX17 %s
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,DARWIN %s
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 2 -o - %s | FileCheck %s -check-prefix=STACK-PROT
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 3 -o - %s | FileCheck %s -check-prefix=STACK-PROT
 
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,ELF %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,ELF,CXX11 %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,ELF,CXX17 %s
 // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,ELF %s
 // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT
 // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 2 -o - %s | FileCheck %s -check-prefix=STACK-PROT
@@ -20,6 +22,11 @@
 // CHECK: @__const._Z13testArrayInitv.c0 = private unnamed_addr constant 
%struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base011nonvirtual0Ev, i32 0, i64 35591) to i64), i64 0 } }, align 8
 // CHECK: @__const._Z13testArrayInitv.c1 = private unnamed_addr constant 
%struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 35591) to i64), i64 0 } }, align 8
 
+// CHECK: @_ZN22testNoexceptConversion6mfptr1E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NO_NOEXCEPT:.*]]) to i64), i64 0 },
+// CHECK: @_ZN22testNoexceptConversion6mfptr2E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 },
+// CXX11: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } 
{ i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 },
+// CXX17: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } 
{ i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NOEXCEPT:.*]]) to i64), i64 0 },
+
 // CHECK: @_ZTV5Base0 = unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr 
null, ptr @_ZTI5Base0,
 // CHECK-SAME: ptr ptrauth (ptr @_ZN5Base08virtual1Ev, i32 0, i64 55600, ptr 
getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5Base0, i32 0, i32 0, i32 2)),
 // CHECK-SAME: ptr ptrauth (ptr @_ZN5Base08virtual3Ev, i32 0, i64 53007, ptr 
getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5Base0, i32 0, i32 0, i32 3)),
@@ -438,3 +445,101 @@ void testArrayInit() {
 void testConvertNull() {
   VariadicMethodTy0 t = (VariadicMethodTy0)(MethodTy0{});
 }
+
+namespace testNoexceptConversion {
+
+// CHECK-LABEL: define internal void @__cxx_global_var_init()
+// CXX17: [[ENTRY:.*]]:
+// CHECK: %[[V0:.*]] = load { i64, i64 }, ptr 
@_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8
+// CXX17: %[[MEMPTR_PTR:.*]] = extractvalue { i64, i64 } %[[V0]], 0
+// CXX17: %[[MEMPTR_ADJ:.*]] = extractvalue { i64, i64 } %[[V0]], 1
+// CXX17: %[[V1:.*]] = and i64 %[[MEMPTR_ADJ]], 1
+// CXX17: %[[IS_VIRTUAL_OFFSET:.*]] = icmp ne i64 %[[V1]], 0
+// CXX17: br i1 %[[IS_VIRTUAL_OFFSET]], label %[[MERGE:.*]], label 
%[[RESIGN:.*]]
+
+// CXX17: [[RESIGN]]:
+// CXX17: %[[V2:.*]] = inttoptr i64 %[[MEMPTR_PTR]] to ptr
+// CXX17: %[[V3:.*]] = icmp ne ptr %[[V2]], null
+// CXX17: br i1 %[[V3]], label %[[RESIGN_NONNULL:.*]], label 
%[[RESIGN_CONT:.*]]
+
+// CXX17: [[RESIGN_NONNULL]]:
+// CXX17: %[[V4:.*]] = ptrtoint ptr %[[V2]] to i64
+// CXX17: %[[V5:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V4]], i32 0, i64 
[[DISC_NOEXCEPT]], i32 0, i64 [[DISC_NO_NOEXCEPT]])
+// CXX17: %[[V6:.*]] = inttoptr i64 %[[V5]] to ptr
+// CXX17: br label %[[RESIGN_CONT]]
+
+// CXX17: [[RESIGN_CONT]]:
+// CXX17: %[[V7:.*]] = phi ptr [ null, %[[RESIGN]] ], [ %[[V6]], 
%[[RESIGN_NONNULL]] ]
+// CXX17: %[[V8:.*]] = ptrtoint ptr %[[V7]] to i64
+// CXX17: %[[V9:.*]] = insertvalue { i64, i64 } %[[V0]], i64 %[[V8]], 0
+// CXX17: br label %[[MERGE]]
+
+// CXX17: [[MERGE]]:
+// CXX17: %[[V10:.*]] = phi { i64, i64 } [ %[[V0]], %[[ENTRY]] ], [ %[[V9]], 
%[[RESIGN_CONT]] ]
+// CXX17: store { i64, i64 } %[[V10]], ptr 
@_ZN22testNoexceptConversion6mfptr4E, align 8
+// CXX11: store { i64, i64 } %[[V0]], ptr 
@_ZN22testNoexceptConversion6mfptr4E, align 8
+
+// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test0Ev()
+// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
+// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 }, ptr %[[P0]], align 8,
+
+// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test1Ev()
+// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
+// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 }, ptr %[[P0]], align 8,
+
+// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test2Ev()
+// CXX17: [[ENTRY:.*]]:
+// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
+// CHECK: %[[V0:.*]] = load { i64, i64 }, ptr 
@_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8
+// CXX17: %[[MEMPTR_PTR:.*]] = extractvalue { i64, i64 } %[[V0]], 0
+// CXX17: %[[MEMPTR_ADJ:.*]] = extractvalue { i64, i64 } %[[V0]], 1
+// CXX17: %[[V1:.*]] = and i64 %[[MEMPTR_ADJ]], 1
+// CXX17: %[[IS_VIRTUAL_OFFSET:.*]] = icmp ne i64 %[[V1]], 0
+// CXX17: br i1 %[[IS_VIRTUAL_OFFSET]], label %[[MERGE:.*]], label 
%[[RESIGN:.*]]
+
+// CXX17: [[RESIGN]]:
+// CXX17: %[[V2:.*]] = inttoptr i64 %[[MEMPTR_PTR]] to ptr
+// CXX17: %[[V3:.*]] = icmp ne ptr %[[V2]], null
+// CXX17: br i1 %[[V3]], label %[[RESIGN_NONNULL:.*]], label 
%[[RESIGN_CONT:.*]]
+
+// CXX17: [[RESIGN_NONNULL]]:
+// CXX17: %[[V4:.*]] = ptrtoint ptr %[[V2]] to i64
+// CXX17: %[[V5:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V4]], i32 0, i64 
[[DISC_NOEXCEPT]], i32 0, i64 [[DISC_NO_NOEXCEPT]])
+// CXX17: %[[V6:.*]] = inttoptr i64 %[[V5]] to ptr
+// CXX17: br label %[[RESIGN_CONT]]
+
+// CXX17: [[RESIGN_CONT]]:
+// CXX17: %[[V7:.*]] = phi ptr [ null, %[[RESIGN]] ], [ %[[V6]], 
%[[RESIGN_NONNULL]] ]
+// CXX17: %[[V8:.*]] = ptrtoint ptr %[[V7]] to i64
+// CXX17: %[[V9:.*]] = insertvalue { i64, i64 } %[[V0]], i64 %[[V8]], 0
+// CXX17: br label %[[MERGE]]
+
+// CXX17: [[MERGE]]:
+// CXX17: %[[V10:.*]] = phi { i64, i64 } [ %[[V0]], %[[ENTRY]] ], [ %[[V9]], 
%[[RESIGN_CONT]] ]
+// CXX11: store { i64, i64 } %[[V0]], ptr %[[P0]], align 8
+// CXX17: store { i64, i64 } %[[V10]], ptr %[[P0]], align 8
+
+struct S {
+  void nonvirtual_noexcept() noexcept;
+  virtual void virtual_noexcept() noexcept;
+};
+
+void (S::*mfptr0_noexcept)() noexcept;
+void (S::*mfptr1)() = &S::nonvirtual_noexcept;
+void (S::*mfptr2)() = &S::virtual_noexcept;
+void (S::*mfptr3_noexcept)() noexcept = &S::nonvirtual_noexcept;
+void (S::*mfptr4)() = mfptr0_noexcept;
+
+void test0() {
+  void (S::*p0)() = &S::nonvirtual_noexcept;
+}
+
+void test1() {
+  void (S::*p0)() = &S::virtual_noexcept;
+}
+
+void test2() {
+  void (S::*p0)() = mfptr0_noexcept;
+}
+
+}

>From bb2051660628be74ae42bf86fc8d63581177dcee Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahata...@gmail.com>
Date: Tue, 14 Jan 2025 09:27:32 -0800
Subject: [PATCH 2/4] Ignore exception specification when computing
 discriminator of member function pointers

---
 clang/lib/AST/ASTContext.cpp                  |  7 ++
 clang/lib/CodeGen/CGExprScalar.cpp            |  9 +-
 clang/lib/CodeGen/ItaniumCXXABI.cpp           | 28 ++----
 .../ptrauth-member-function-pointer.cpp       | 85 +++++--------------
 4 files changed, 36 insertions(+), 93 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 67841a30a571f3..311cf80eb6bff7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3442,6 +3442,13 @@ uint16_t 
ASTContext::getPointerAuthTypeDiscriminator(QualType T) {
     encodeTypeForFunctionPointerAuth(*this, Out, T);
   } else {
     T = T.getUnqualifiedType();
+    // Drop exception specification from member function pointer type.
+    if (auto *MPT = T->getAs<MemberPointerType>())
+      if (MPT->isMemberFunctionPointer()) {
+        QualType FT =
+            getFunctionTypeWithExceptionSpec(MPT->getPointeeType(), EST_None);
+        T = getMemberPointerType(FT, MPT->getClass());
+      }
     std::unique_ptr<MangleContext> MC(createMangleContext());
     MC->mangleCanonicalTypeName(T, Out);
   }
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 76e2f047e84ae4..82caf65ac68d6b 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2419,13 +2419,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
     return Visit(const_cast<Expr*>(E));
 
   case CK_NoOp: {
-    if (CE->changesVolatileQualification())
-      return EmitLoadOfLValue(CE);
-    auto V = Visit(const_cast<Expr *>(E));
-    if (CGF.CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers &&
-        CE->getType()->isMemberFunctionPointerType())
-      V = CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, V);
-    return V;
+    return CE->changesVolatileQualification() ? EmitLoadOfLValue(CE)
+                                              : Visit(const_cast<Expr *>(E));
   }
 
   case CK_BaseToDerived: {
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 085ed84b5108b4..dcc35d5689831e 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -924,20 +924,17 @@ 
ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
   if (isa<llvm::Constant>(src))
     return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));
 
-  QualType DstType = E->getType(), SrcType = E->getSubExpr()->getType();
-
   assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
          E->getCastKind() == CK_BaseToDerivedMemberPointer ||
-         E->getCastKind() == CK_ReinterpretMemberPointer ||
-         (E->getCastKind() == CK_NoOp &&
-          getContext().hasSameFunctionTypeIgnoringExceptionSpec(
-              DstType->getPointeeType(), SrcType->getPointeeType())));
+         E->getCastKind() == CK_ReinterpretMemberPointer);
 
   CGBuilderTy &Builder = CGF.Builder;
+  QualType DstType = E->getType();
 
   if (DstType->isMemberFunctionPointerType()) {
     if (const auto &NewAuthInfo =
             CGM.getMemberFunctionPointerAuthInfo(DstType)) {
+      QualType SrcType = E->getSubExpr()->getType();
       assert(SrcType->isMemberFunctionPointerType());
       const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);
       llvm::Value *MemFnPtr = Builder.CreateExtractValue(src, 0, "memptr.ptr");
@@ -974,11 +971,6 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction 
&CGF,
     }
   }
 
-  // Conversion from a pointer to a noexcept member function to a pointer to a
-  // member function without noexcept doesn't require any additional 
processing.
-  if (E->getCastKind() == CK_NoOp)
-    return src;
-
   // Under Itanium, reinterprets don't require any additional processing.
   if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
 
@@ -1053,24 +1045,16 @@ pointerAuthResignMemberFunctionPointer(llvm::Constant 
*Src, QualType DestType,
 llvm::Constant *
 ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
                                            llvm::Constant *src) {
-  QualType DstType = E->getType(), SrcType = E->getSubExpr()->getType();
-
   assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
          E->getCastKind() == CK_BaseToDerivedMemberPointer ||
-         E->getCastKind() == CK_ReinterpretMemberPointer ||
-         (E->getCastKind() == CK_NoOp &&
-          getContext().hasSameFunctionTypeIgnoringExceptionSpec(
-              DstType->getPointeeType(), SrcType->getPointeeType())));
+         E->getCastKind() == CK_ReinterpretMemberPointer);
+
+  QualType DstType = E->getType();
 
   if (DstType->isMemberFunctionPointerType())
     src = pointerAuthResignMemberFunctionPointer(
         src, DstType, E->getSubExpr()->getType(), CGM);
 
-  // Conversion from a pointer to a noexcept member function to a pointer to a
-  // member function without noexcept doesn't require any additional 
processing.
-  if (E->getCastKind() == CK_NoOp)
-    return src;
-
   // Under Itanium, reinterprets don't require any additional processing.
   if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
 
diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp 
b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
index 3408e7e18c3adc..05223cfd4c99a6 100644
--- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
+++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN,CXX11 %s
+// RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN %s
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN,CXX17 %s
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,DARWIN %s
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 2 -o - %s | FileCheck %s -check-prefix=STACK-PROT
 // RUN: %clang_cc1 -triple arm64-apple-ios   -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 3 -o - %s | FileCheck %s -check-prefix=STACK-PROT
 
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,ELF,CXX11 %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,ELF %s
 // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | 
FileCheck -check-prefixes=CHECK,NODEBUG,ELF,CXX17 %s
 // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,ELF %s
 // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls 
-fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes 
-stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT
@@ -22,10 +22,9 @@
 // CHECK: @__const._Z13testArrayInitv.c0 = private unnamed_addr constant 
%struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base011nonvirtual0Ev, i32 0, i64 35591) to i64), i64 0 } }, align 8
 // CHECK: @__const._Z13testArrayInitv.c1 = private unnamed_addr constant 
%struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 35591) to i64), i64 0 } }, align 8
 
-// CHECK: @_ZN22testNoexceptConversion6mfptr1E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NO_NOEXCEPT:.*]]) to i64), i64 0 },
-// CHECK: @_ZN22testNoexceptConversion6mfptr2E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 },
-// CXX11: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } 
{ i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 },
-// CXX17: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } 
{ i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NOEXCEPT:.*]]) to i64), i64 0 },
+// CHECK: @_ZN22testNoexceptConversion6mfptr1E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[TYPEDISC3:.*]]) to i64), i64 0 },
+// CHECK: @_ZN22testNoexceptConversion6mfptr2E = global { i64, i64 } { i64 
ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 
[[TYPEDISC3]]) to i64), i64 0 },
+// CHECK: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } 
{ i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[TYPEDISC3]]) to i64), i64 0 },
 
 // CHECK: @_ZTV5Base0 = unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr 
null, ptr @_ZTI5Base0,
 // CHECK-SAME: ptr ptrauth (ptr @_ZN5Base08virtual1Ev, i32 0, i64 55600, ptr 
getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5Base0, i32 0, i32 0, i32 2)),
@@ -84,6 +83,9 @@ struct Derived1 : Base0, Base1 {
 };
 
 typedef void (Base0::*MethodTy0)();
+#if __cplusplus >= 201703L
+typedef void (Base0::*NoExceptMethodTy0)() noexcept;
+#endif
 typedef void (Base0::*VariadicMethodTy0)(int, ...);
 typedef void (Derived0::*MethodTy1)();
 
@@ -300,6 +302,15 @@ void test1(Base0 *a0, MethodTy0 a1) {
   (a0->*a1)();
 }
 
+// CXX17: %[[V14:.*]] = phi ptr [ %{{.*}}, {{.*}} ], [ %{{.*}}, {{.*}} ]
+// CXX17: %[[V15:.*]] = phi i64 [ 0, {{.*}} ], [ [[TYPEDISC0]], {{.*}} ]
+// CXX17: call void %[[V14]](ptr noundef nonnull align {{[0-9]+}} 
dereferenceable(8) %[[V4]]) {{.*}}[ "ptrauth"(i32 0, i64 %[[V15]]) ]
+#if __cplusplus >= 201703L
+void test1_noexcept(Base0 *a0, NoExceptMethodTy0 a1) {
+  (a0->*a1)();
+}
+#endif
+
 // CHECK: define{{.*}} void @_Z15testConversion0M5Base0FvvEM8Derived0FvvE([2 x 
i64] %[[METHOD0_COERCE:.*]], [2 x i64] %[[METHOD1_COERCE:.*]])
 // CHECK: %[[METHOD0:.*]] = alloca { i64, i64 }, align 8
 // CHECK: %[[METHOD1:.*]] = alloca { i64, i64 }, align 8
@@ -449,75 +460,21 @@ void testConvertNull() {
 namespace testNoexceptConversion {
 
 // CHECK-LABEL: define internal void @__cxx_global_var_init()
-// CXX17: [[ENTRY:.*]]:
 // CHECK: %[[V0:.*]] = load { i64, i64 }, ptr 
@_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8
-// CXX17: %[[MEMPTR_PTR:.*]] = extractvalue { i64, i64 } %[[V0]], 0
-// CXX17: %[[MEMPTR_ADJ:.*]] = extractvalue { i64, i64 } %[[V0]], 1
-// CXX17: %[[V1:.*]] = and i64 %[[MEMPTR_ADJ]], 1
-// CXX17: %[[IS_VIRTUAL_OFFSET:.*]] = icmp ne i64 %[[V1]], 0
-// CXX17: br i1 %[[IS_VIRTUAL_OFFSET]], label %[[MERGE:.*]], label 
%[[RESIGN:.*]]
-
-// CXX17: [[RESIGN]]:
-// CXX17: %[[V2:.*]] = inttoptr i64 %[[MEMPTR_PTR]] to ptr
-// CXX17: %[[V3:.*]] = icmp ne ptr %[[V2]], null
-// CXX17: br i1 %[[V3]], label %[[RESIGN_NONNULL:.*]], label 
%[[RESIGN_CONT:.*]]
-
-// CXX17: [[RESIGN_NONNULL]]:
-// CXX17: %[[V4:.*]] = ptrtoint ptr %[[V2]] to i64
-// CXX17: %[[V5:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V4]], i32 0, i64 
[[DISC_NOEXCEPT]], i32 0, i64 [[DISC_NO_NOEXCEPT]])
-// CXX17: %[[V6:.*]] = inttoptr i64 %[[V5]] to ptr
-// CXX17: br label %[[RESIGN_CONT]]
-
-// CXX17: [[RESIGN_CONT]]:
-// CXX17: %[[V7:.*]] = phi ptr [ null, %[[RESIGN]] ], [ %[[V6]], 
%[[RESIGN_NONNULL]] ]
-// CXX17: %[[V8:.*]] = ptrtoint ptr %[[V7]] to i64
-// CXX17: %[[V9:.*]] = insertvalue { i64, i64 } %[[V0]], i64 %[[V8]], 0
-// CXX17: br label %[[MERGE]]
-
-// CXX17: [[MERGE]]:
-// CXX17: %[[V10:.*]] = phi { i64, i64 } [ %[[V0]], %[[ENTRY]] ], [ %[[V9]], 
%[[RESIGN_CONT]] ]
-// CXX17: store { i64, i64 } %[[V10]], ptr 
@_ZN22testNoexceptConversion6mfptr4E, align 8
-// CXX11: store { i64, i64 } %[[V0]], ptr 
@_ZN22testNoexceptConversion6mfptr4E, align 8
+// CHECK: store { i64, i64 } %[[V0]], ptr 
@_ZN22testNoexceptConversion6mfptr4E, align 8
 
 // CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test0Ev()
 // CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
-// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 }, ptr %[[P0]], align 8,
+// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 
[[TYPEDISC3]]) to i64), i64 0 }, ptr %[[P0]], align 8,
 
 // CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test1Ev()
 // CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
-// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 
[[DISC_NO_NOEXCEPT]]) to i64), i64 0 }, ptr %[[P0]], align 8,
+// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr 
@_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 
[[TYPEDISC3]]) to i64), i64 0 }, ptr %[[P0]], align 8,
 
 // CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test2Ev()
-// CXX17: [[ENTRY:.*]]:
 // CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
 // CHECK: %[[V0:.*]] = load { i64, i64 }, ptr 
@_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8
-// CXX17: %[[MEMPTR_PTR:.*]] = extractvalue { i64, i64 } %[[V0]], 0
-// CXX17: %[[MEMPTR_ADJ:.*]] = extractvalue { i64, i64 } %[[V0]], 1
-// CXX17: %[[V1:.*]] = and i64 %[[MEMPTR_ADJ]], 1
-// CXX17: %[[IS_VIRTUAL_OFFSET:.*]] = icmp ne i64 %[[V1]], 0
-// CXX17: br i1 %[[IS_VIRTUAL_OFFSET]], label %[[MERGE:.*]], label 
%[[RESIGN:.*]]
-
-// CXX17: [[RESIGN]]:
-// CXX17: %[[V2:.*]] = inttoptr i64 %[[MEMPTR_PTR]] to ptr
-// CXX17: %[[V3:.*]] = icmp ne ptr %[[V2]], null
-// CXX17: br i1 %[[V3]], label %[[RESIGN_NONNULL:.*]], label 
%[[RESIGN_CONT:.*]]
-
-// CXX17: [[RESIGN_NONNULL]]:
-// CXX17: %[[V4:.*]] = ptrtoint ptr %[[V2]] to i64
-// CXX17: %[[V5:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V4]], i32 0, i64 
[[DISC_NOEXCEPT]], i32 0, i64 [[DISC_NO_NOEXCEPT]])
-// CXX17: %[[V6:.*]] = inttoptr i64 %[[V5]] to ptr
-// CXX17: br label %[[RESIGN_CONT]]
-
-// CXX17: [[RESIGN_CONT]]:
-// CXX17: %[[V7:.*]] = phi ptr [ null, %[[RESIGN]] ], [ %[[V6]], 
%[[RESIGN_NONNULL]] ]
-// CXX17: %[[V8:.*]] = ptrtoint ptr %[[V7]] to i64
-// CXX17: %[[V9:.*]] = insertvalue { i64, i64 } %[[V0]], i64 %[[V8]], 0
-// CXX17: br label %[[MERGE]]
-
-// CXX17: [[MERGE]]:
-// CXX17: %[[V10:.*]] = phi { i64, i64 } [ %[[V0]], %[[ENTRY]] ], [ %[[V9]], 
%[[RESIGN_CONT]] ]
-// CXX11: store { i64, i64 } %[[V0]], ptr %[[P0]], align 8
-// CXX17: store { i64, i64 } %[[V10]], ptr %[[P0]], align 8
+// CHECK: store { i64, i64 } %[[V0]], ptr %[[P0]], align 8,
 
 struct S {
   void nonvirtual_noexcept() noexcept;

>From 6a5d101e630fca43c02a918971800e7b17888e0e Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahata...@gmail.com>
Date: Thu, 16 Jan 2025 12:19:42 -0800
Subject: [PATCH 3/4] Improve comment and Avoid rebuilding the member pointer
 type if it already doesn't have an exception spec

---
 clang/lib/AST/ASTContext.cpp | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 311cf80eb6bff7..c1409ce65b5355 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3443,11 +3443,33 @@ uint16_t 
ASTContext::getPointerAuthTypeDiscriminator(QualType T) {
   } else {
     T = T.getUnqualifiedType();
     // Drop exception specification from member function pointer type.
+    // Calls to member function pointers don't need to worry about
+    // language interop or the laxness of the C type compatibility rules.
+    // We just mangle the member pointer type directly, which is
+    // implicitly much stricter about type matching. However, we do
+    // strip any top-level exception specification before this mangling.
+    // C++23 requires calls to work when the function type is convertible
+    // to the pointer type by a function pointer conversion, which can
+    // change the exception specification. This does not technically
+    // require the exception specification to not affect representation,
+    // because the function pointer conversion is still always a direct
+    // value conversion and therefore an opportunity to resign the
+    // pointer. (This is in contrast to e.g. qualification conversions,
+    // which can be applied in nested pointer positions, effectively
+    // requiring qualified and unqualified representations to match.)
+    // However, it is pragmatic to ignore exception specifications
+    // because it allows a certain amount of `noexcept` mismatching
+    // to not become a visible ODR problem. This also leaves some
+    // room for the committee to add laxness to function pointer
+    // conversions in future standards.
     if (auto *MPT = T->getAs<MemberPointerType>())
       if (MPT->isMemberFunctionPointer()) {
-        QualType FT =
-            getFunctionTypeWithExceptionSpec(MPT->getPointeeType(), EST_None);
-        T = getMemberPointerType(FT, MPT->getClass());
+        QualType PointeeType = MPT->getPointeeType();
+        if (PointeeType->castAs<FunctionProtoType>()->getExceptionSpecType() !=
+            EST_None) {
+          QualType FT = getFunctionTypeWithExceptionSpec(PointeeType, 
EST_None);
+          T = getMemberPointerType(FT, MPT->getClass());
+        }
       }
     std::unique_ptr<MangleContext> MC(createMangleContext());
     MC->mangleCanonicalTypeName(T, Out);

>From eb62db58fbe01c4ce1fb70a61080e043ef64b7e4 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahata...@gmail.com>
Date: Thu, 16 Jan 2025 12:45:04 -0800
Subject: [PATCH 4/4] Fix test

---
 clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp 
b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
index 05223cfd4c99a6..e9436f11b5106e 100644
--- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
+++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
@@ -302,9 +302,10 @@ void test1(Base0 *a0, MethodTy0 a1) {
   (a0->*a1)();
 }
 
+// CXX17: define{{.*}} void @_Z14test1_noexceptP5Base0MS_DoFvvE(
 // CXX17: %[[V14:.*]] = phi ptr [ %{{.*}}, {{.*}} ], [ %{{.*}}, {{.*}} ]
 // CXX17: %[[V15:.*]] = phi i64 [ 0, {{.*}} ], [ [[TYPEDISC0]], {{.*}} ]
-// CXX17: call void %[[V14]](ptr noundef nonnull align {{[0-9]+}} 
dereferenceable(8) %[[V4]]) {{.*}}[ "ptrauth"(i32 0, i64 %[[V15]]) ]
+// CXX17: call void %[[V14]](ptr noundef nonnull align {{[0-9]+}} 
dereferenceable(8) %{{.*}}) {{.*}}[ "ptrauth"(i32 0, i64 %[[V15]]) ]
 #if __cplusplus >= 201703L
 void test1_noexcept(Base0 *a0, NoExceptMethodTy0 a1) {
   (a0->*a1)();

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

Reply via email to