https://github.com/dtcxzyw updated 
https://github.com/llvm/llvm-project/pull/135649

>From 6f0a3ba5852134d8bd04679438866e6f373f494a Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2...@gmail.com>
Date: Tue, 15 Apr 2025 12:12:19 +0800
Subject: [PATCH 1/6] [Clang] Add support for GCC bound member functions
 extension

---
 clang/include/clang/AST/OperationKinds.def    |  4 ++
 clang/include/clang/Basic/DiagnosticGroups.td | 32 +++++-----
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 ++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  1 +
 clang/lib/AST/Expr.cpp                        |  5 ++
 clang/lib/AST/ExprConstant.cpp                |  2 +
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  1 +
 clang/lib/CodeGen/CGExpr.cpp                  |  1 +
 clang/lib/CodeGen/CGExprAgg.cpp               |  2 +
 clang/lib/CodeGen/CGExprComplex.cpp           |  1 +
 clang/lib/CodeGen/CGExprConstant.cpp          |  1 +
 clang/lib/CodeGen/CGExprScalar.cpp            |  1 +
 clang/lib/CodeGen/ItaniumCXXABI.cpp           | 24 ++++++-
 clang/lib/Edit/RewriteObjCFoundationAPI.cpp   |  1 +
 clang/lib/Sema/SemaCast.cpp                   | 63 +++++++++++++++++++
 .../StaticAnalyzer/Core/BasicValueFactory.cpp |  3 +-
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp |  3 +-
 17 files changed, 129 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/AST/OperationKinds.def 
b/clang/include/clang/AST/OperationKinds.def
index 790dd572a7c99..489d89a697dc3 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -152,6 +152,10 @@ CAST_OPERATION(MemberPointerToBoolean)
 /// many ABIs do not guarantee this on all possible intermediate types).
 CAST_OPERATION(ReinterpretMemberPointer)
 
+/// CK_BoundPointerToMemberFunctionToFunctionPointer - Convert a bound
+/// member function pointer to a function pointer.  This is a GNU extension.
+CAST_OPERATION(BoundMemberFunctionToFunctionPointer)
+
 /// CK_UserDefinedConversion - Conversion using a user defined type
 /// conversion function.
 ///    struct A { operator int(); }; int i = int(A());
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index d97bbfee2e4d5..8e5a4cba87c95 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -795,6 +795,7 @@ def DuplicateDeclSpecifier : 
DiagGroup<"duplicate-decl-specifier">;
 def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;
 def GNUUnionCast : DiagGroup<"gnu-union-cast">;
 def GNUVariableSizedTypeNotAtEnd : 
DiagGroup<"gnu-variable-sized-type-not-at-end">;
+def GNUPMFCast : DiagGroup<"pmf-conversions">;
 def Varargs : DiagGroup<"varargs">;
 def XorUsedAsPow : DiagGroup<"xor-used-as-pow">;
 
@@ -1294,22 +1295,21 @@ def C2y : DiagGroup<"c2y-extensions">;
 def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;
 
 // A warning group for warnings about GCC extensions.
-def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
-                            GNUAutoType, GNUBinaryLiteral, GNUCaseRange,
-                            GNUComplexInteger, GNUCompoundLiteralInitializer,
-                            GNUConditionalOmittedOperand, GNUDesignator,
-                            GNUEmptyStruct,
-                            VLAExtension, GNUFlexibleArrayInitializer,
-                            GNUFlexibleArrayUnionMember, GNUFoldingConstant,
-                            GNUImaginaryConstant, GNUIncludeNext,
-                            GNULabelsAsValue, GNULineMarker, 
GNUNullPointerArithmetic,
-                            GNUOffsetofExtensions, GNUPointerArith,
-                            RedeclaredClassMember, GNURedeclaredEnum,
-                            GNUStatementExpression, GNUStaticFloatInit,
-                            GNUStringLiteralOperatorTemplate, GNUUnionCast,
-                            GNUVariableSizedTypeNotAtEnd, ZeroLengthArray,
-                            GNUZeroLineDirective,
-                            GNUZeroVariadicMacroArguments]>;
+def GNU
+    : DiagGroup<
+          "gnu", [GNUAlignofExpression, GNUAnonymousStruct, GNUAutoType,
+                  GNUBinaryLiteral, GNUCaseRange, GNUComplexInteger,
+                  GNUCompoundLiteralInitializer, GNUConditionalOmittedOperand,
+                  GNUDesignator, GNUEmptyStruct, VLAExtension,
+                  GNUFlexibleArrayInitializer, GNUFlexibleArrayUnionMember,
+                  GNUFoldingConstant, GNUImaginaryConstant, GNUIncludeNext,
+                  GNULabelsAsValue, GNULineMarker, GNUNullPointerArithmetic,
+                  GNUOffsetofExtensions, GNUPointerArith, 
RedeclaredClassMember,
+                  GNURedeclaredEnum, GNUStatementExpression, 
GNUStaticFloatInit,
+                  GNUStringLiteralOperatorTemplate, GNUUnionCast,
+                  GNUVariableSizedTypeNotAtEnd, ZeroLengthArray,
+                  GNUZeroLineDirective, GNUZeroVariadicMacroArguments,
+                  GNUPMFCast]>;
 // A warning group for warnings about code that clang accepts but gcc doesn't.
 def GccCompat : DiagGroup<"gcc-compat">;
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 180ca39bc07e9..7b5fb514e94fb 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5120,6 +5120,10 @@ def err_ovl_unresolvable : Error<
 def err_bound_member_function : Error<
   "reference to non-static member function must be called"
   "%select{|; did you mean to call it with no arguments?}0">;
+def ext_bound_member_function_conversion
+    : ExtWarn<"converting the bound member function %0 to a function pointer "
+              "%1 is a GNU extension">,
+      InGroup<GNUPMFCast>;
 def note_possible_target_of_call : Note<"possible target for call">;
 def err_no_viable_destructor : Error<
   "no viable destructor found for class %0">;
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 0d3c2065cd58c..7dc299827916b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -109,6 +109,7 @@ def CK_ArrayToPointerDecay : 
I32EnumAttrCase<"array_to_ptrdecay", 11>;
 // CK_DerivedToBaseMemberPointer
 def CK_MemberPointerToBoolean : I32EnumAttrCase<"member_ptr_to_bool", 17>;
 // CK_ReinterpretMemberPointer
+// CK_BoundMemberFunctionToFunctionPointer
 // CK_UserDefinedConversion
 // CK_ConstructorConversion
 def CK_IntegralToPointer : I32EnumAttrCase<"int_to_ptr", 21>;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 4deed08d693ac..bae06543207b9 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1864,6 +1864,11 @@ bool CastExpr::CastConsistency() const {
     assert(getSubExpr()->getType()->isMemberPointerType());
     goto CheckNoBasePath;
 
+  case CK_BoundMemberFunctionToFunctionPointer:
+    assert(getType()->isFunctionPointerType());
+    assert(getSubExpr()->getType()->isMemberPointerType());
+    goto CheckNoBasePath;
+
   case CK_BitCast:
     // Arbitrary casts to C pointer types count as bitcasts.
     // Otherwise, we should only have block and ObjC pointer casts
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d1cc722fb7945..b104a4e9416c0 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15103,6 +15103,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) 
{
   case CK_BaseToDerivedMemberPointer:
   case CK_DerivedToBaseMemberPointer:
   case CK_ReinterpretMemberPointer:
+  case CK_BoundMemberFunctionToFunctionPointer:
   case CK_ConstructorConversion:
   case CK_IntegralToPointer:
   case CK_ToVoid:
@@ -15960,6 +15961,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr 
*E) {
   case CK_DerivedToBaseMemberPointer:
   case CK_MemberPointerToBoolean:
   case CK_ReinterpretMemberPointer:
+  case CK_BoundMemberFunctionToFunctionPointer:
   case CK_ConstructorConversion:
   case CK_IntegralToPointer:
   case CK_PointerToIntegral:
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index f0732a8ea60af..a6f4541cc7e80 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -83,6 +83,7 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr 
*expr,
     case CK_NullToMemberPointer:
     case CK_NullToPointer:
     case CK_ReinterpretMemberPointer:
+    case CK_BoundMemberFunctionToFunctionPointer:
       // Common pointer conversions, nothing to do here.
       // TODO: Is there any reason to treat base-to-derived conversions
       // specially?
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 5f028f6d8c6ac..eeeb5c8f7a21f 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5387,6 +5387,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) 
{
   case CK_BaseToDerivedMemberPointer:
   case CK_MemberPointerToBoolean:
   case CK_ReinterpretMemberPointer:
+  case CK_BoundMemberFunctionToFunctionPointer:
   case CK_AnyPointerToBlockPointerCast:
   case CK_ARCProduceObject:
   case CK_ARCConsumeObject:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 87b2a73fb0c03..91fdf8a072111 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1043,6 +1043,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_DerivedToBaseMemberPointer:
   case CK_MemberPointerToBoolean:
   case CK_ReinterpretMemberPointer:
+  case CK_BoundMemberFunctionToFunctionPointer:
   case CK_IntegralToPointer:
   case CK_PointerToIntegral:
   case CK_PointerToBoolean:
@@ -1600,6 +1601,7 @@ static bool castPreservesZero(const CastExpr *CE) {
   case CK_MemberPointerToBoolean:
   case CK_NullToMemberPointer:
   case CK_ReinterpretMemberPointer:
+  case CK_BoundMemberFunctionToFunctionPointer:
     // FIXME: ABI-dependent.
     return false;
 
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp 
b/clang/lib/CodeGen/CGExprComplex.cpp
index f556594f4a9ec..008082a493a2a 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -575,6 +575,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, 
Expr *Op,
   case CK_DerivedToBaseMemberPointer:
   case CK_MemberPointerToBoolean:
   case CK_ReinterpretMemberPointer:
+  case CK_BoundMemberFunctionToFunctionPointer:
   case CK_ConstructorConversion:
   case CK_IntegralToPointer:
   case CK_PointerToIntegral:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp 
b/clang/lib/CodeGen/CGExprConstant.cpp
index b016c6e36d1a8..bb665e6634e5a 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1272,6 +1272,7 @@ class ConstExprEmitter
       llvm_unreachable("builtin functions are handled elsewhere");
 
     case CK_ReinterpretMemberPointer:
+    case CK_BoundMemberFunctionToFunctionPointer:
     case CK_DerivedToBaseMemberPointer:
     case CK_BaseToDerivedMemberPointer: {
       auto C = Emitter.tryEmitPrivate(subExpr, subExpr->getType());
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index e9a7ba509350c..9cf2dcf376133 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2582,6 +2582,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
   }
 
   case CK_ReinterpretMemberPointer:
+  case CK_BoundMemberFunctionToFunctionPointer:
   case CK_BaseToDerivedMemberPointer:
   case CK_DerivedToBaseMemberPointer: {
     Value *Src = Visit(E);
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 35485dc6d867f..63cb2d8128454 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -930,7 +930,8 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction 
&CGF,
 
   assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
          E->getCastKind() == CK_BaseToDerivedMemberPointer ||
-         E->getCastKind() == CK_ReinterpretMemberPointer);
+         E->getCastKind() == CK_ReinterpretMemberPointer ||
+         E->getCastKind() == CK_BoundMemberFunctionToFunctionPointer);
 
   CGBuilderTy &Builder = CGF.Builder;
   QualType DstType = E->getType();
@@ -977,6 +978,10 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction 
&CGF,
 
   // Under Itanium, reinterprets don't require any additional processing.
   if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
+  if (E->getCastKind() == CK_BoundMemberFunctionToFunctionPointer) {
+    llvm::errs() << *src << '\n';
+    llvm_unreachable("TODO");
+  }
 
   llvm::Constant *adj = getMemberPointerAdjustment(E);
   if (!adj) return src;
@@ -1051,7 +1056,8 @@ ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr 
*E,
                                            llvm::Constant *src) {
   assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
          E->getCastKind() == CK_BaseToDerivedMemberPointer ||
-         E->getCastKind() == CK_ReinterpretMemberPointer);
+         E->getCastKind() == CK_ReinterpretMemberPointer ||
+         E->getCastKind() == CK_BoundMemberFunctionToFunctionPointer);
 
   QualType DstType = E->getType();
 
@@ -1061,6 +1067,20 @@ ItaniumCXXABI::EmitMemberPointerConversion(const 
CastExpr *E,
 
   // Under Itanium, reinterprets don't require any additional processing.
   if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
+  if (E->getCastKind() == CK_BoundMemberFunctionToFunctionPointer) {
+    llvm::Type *PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());
+    llvm::Constant *FuncPtr = llvm::ConstantExpr::getIntToPtr(
+        ConstantFoldExtractValueInstruction(src, 0), PtrTy);
+
+    const auto &NewAuthInfo = CGM.getFunctionPointerAuthInfo(DstType);
+    const auto &CurAuthInfo =
+        CGM.getMemberFunctionPointerAuthInfo(E->getSubExpr()->getType());
+
+    if (!NewAuthInfo && !CurAuthInfo)
+      return FuncPtr;
+
+    return pointerAuthResignConstant(FuncPtr, CurAuthInfo, NewAuthInfo, CGM);
+  }
 
   // If the adjustment is trivial, we don't need to do anything.
   llvm::Constant *adj = getMemberPointerAdjustment(E);
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp 
b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 627a1d6fb3dd5..51f1de0edae4b 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1054,6 +1054,7 @@ static bool rewriteToNumericBoxedExpression(const 
ObjCMessageExpr *Msg,
     case CK_DerivedToBaseMemberPointer:
     case CK_MemberPointerToBoolean:
     case CK_ReinterpretMemberPointer:
+    case CK_BoundMemberFunctionToFunctionPointer:
     case CK_ConstructorConversion:
     case CK_IntegralToPointer:
     case CK_PointerToIntegral:
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 2824dfce1572c..6d048e8888242 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -250,6 +250,10 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema 
&Self, ExprResult &SrcExp
                                                unsigned &msg,
                                                CastKind &Kind,
                                                CXXCastPath &BasePath);
+static TryCastResult TryStaticMemberFunctionPointerToFunctionPointerCast(
+    Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType,
+    bool CStyle, SourceRange OpRange, unsigned &msg, CastKind &Kind,
+    CXXCastPath &BasePath);
 
 static TryCastResult
 TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
@@ -1430,6 +1434,13 @@ static TryCastResult TryStaticCast(Sema &Self, 
ExprResult &SrcExpr,
     }
   }
 
+  // GCC extension: convert a PMF constant into a function pointer.
+  tcr = TryStaticMemberFunctionPointerToFunctionPointerCast(
+      Self, SrcExpr, SrcType, DestType, CStyle, OpRange, msg, Kind, BasePath);
+
+  if (tcr != TC_NotApplicable)
+    return tcr;
+
   // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
   // C++ 5.2.9p8 additionally disallows a cast path through virtual 
inheritance.
   tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
@@ -1834,6 +1845,58 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult 
&SrcExpr, QualType SrcType,
   return TC_Success;
 }
 
+/// TryStaticMemberFunctionPointerToFunctionPointerCast - Tests whether a
+/// conversion from PMF constant to function pointer is valid.
+TryCastResult TryStaticMemberFunctionPointerToFunctionPointerCast(
+    Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType,
+    bool CStyle, SourceRange OpRange, unsigned &msg, CastKind &Kind,
+    CXXCastPath &BasePath) {
+  const TargetCXXABI &CXXABI = Self.Context.getTargetInfo().getCXXABI();
+  if (!CXXABI.isItaniumFamily())
+    return TC_NotApplicable;
+
+  const PointerType *DestPtr = DestType->getAs<PointerType>();
+  if (!DestPtr)
+    return TC_NotApplicable;
+
+  const FunctionProtoType *DestFnType =
+      DestPtr->getPointeeType()->getAs<FunctionProtoType>();
+  if (!DestFnType || DestFnType->getNumParams() == 0)
+    return TC_NotApplicable;
+
+  auto *ClsPtr = DestFnType->getParamType(0)->getAs<PointerType>();
+  if (!ClsPtr)
+    return TC_NotApplicable;
+
+  auto *ClsRec = ClsPtr->getPointeeType()->getAs<RecordType>();
+  if (!ClsRec)
+    return TC_NotApplicable;
+
+  auto *ClsTy = ClsRec->getAsCXXRecordDecl();
+  if (!ClsTy)
+    return TC_NotApplicable;
+
+  auto EPI = DestFnType->getExtProtoInfo();
+  EPI.TypeQuals = ClsPtr->getPointeeType().getQualifiers();
+  auto FuncTy =
+      Self.Context.getFunctionType(DestFnType->getCallResultType(Self.Context),
+                                   DestFnType->param_types().drop_front(), 
EPI);
+  auto DestPMFTy = Self.Context.getMemberPointerType(FuncTy, nullptr, ClsTy);
+
+  ExprResult Result = SrcExpr;
+
+  if (SrcType.getCanonicalType() != DestPMFTy) {
+    TryCastResult Res = TryStaticMemberPointerUpcast(
+        Self, Result, SrcType, DestType, CStyle, OpRange, msg, Kind, BasePath);
+    if (Res != TC_Success)
+      return TC_NotApplicable;
+  }
+
+  Kind = CK_BoundMemberFunctionToFunctionPointer;
+  msg = diag::ext_bound_member_function_conversion;
+  return TC_Extension;
+}
+
 /// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2
 /// is valid:
 ///
diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp 
b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 02f34bc30f554..0ef1a14450cc2 100644
--- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -190,7 +190,8 @@ const PointerToMemberData *BasicValueFactory::accumCXXBase(
     const nonloc::PointerToMember &PTM, const CastKind &kind) {
   assert((kind == CK_DerivedToBaseMemberPointer ||
           kind == CK_BaseToDerivedMemberPointer ||
-          kind == CK_ReinterpretMemberPointer) &&
+          kind == CK_ReinterpretMemberPointer ||
+          kind == CK_BoundMemberFunctionToFunctionPointer) &&
          "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 3d0a69a515ab8..e470f7df3cef0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -505,7 +505,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
       }
       case CK_DerivedToBaseMemberPointer:
       case CK_BaseToDerivedMemberPointer:
-      case CK_ReinterpretMemberPointer: {
+      case CK_ReinterpretMemberPointer:
+      case CK_BoundMemberFunctionToFunctionPointer: {
         SVal V = state->getSVal(Ex, LCtx);
         if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) {
           SVal CastedPTMSV =

>From 01eca7bde7521d368416cc4d57eec010b3a89e5d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2...@gmail.com>
Date: Tue, 15 Apr 2025 13:16:21 +0800
Subject: [PATCH 2/6] Move to `TryReinterpretCast`

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +-
 clang/lib/CodeGen/ItaniumCXXABI.cpp           |  6 +-
 clang/lib/Sema/SemaCast.cpp                   | 89 ++++---------------
 3 files changed, 22 insertions(+), 77 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7b5fb514e94fb..57ff6435daee8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5121,8 +5121,8 @@ def err_bound_member_function : Error<
   "reference to non-static member function must be called"
   "%select{|; did you mean to call it with no arguments?}0">;
 def ext_bound_member_function_conversion
-    : ExtWarn<"converting the bound member function %0 to a function pointer "
-              "%1 is a GNU extension">,
+    : ExtWarn<"converting the bound member function %1 to a function pointer "
+              "%2 is a GNU extension">,
       InGroup<GNUPMFCast>;
 def note_possible_target_of_call : Note<"possible target for call">;
 def err_no_viable_destructor : Error<
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 63cb2d8128454..e846ed52f8d90 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -978,10 +978,8 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction 
&CGF,
 
   // Under Itanium, reinterprets don't require any additional processing.
   if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
-  if (E->getCastKind() == CK_BoundMemberFunctionToFunctionPointer) {
-    llvm::errs() << *src << '\n';
-    llvm_unreachable("TODO");
-  }
+  if (E->getCastKind() == CK_BoundMemberFunctionToFunctionPointer)
+    return Builder.CreateExtractValue(src, 0, "src.ptr");
 
   llvm::Constant *adj = getMemberPointerAdjustment(E);
   if (!adj) return src;
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 6d048e8888242..964988e6344f1 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -243,17 +243,11 @@ static TryCastResult TryStaticDowncast(Sema &Self, 
CanQualType SrcType,
                                        QualType OrigDestType, unsigned &msg,
                                        CastKind &Kind,
                                        CXXCastPath &BasePath);
-static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult 
&SrcExpr,
-                                               QualType SrcType,
-                                               QualType DestType,bool CStyle,
-                                               SourceRange OpRange,
-                                               unsigned &msg,
-                                               CastKind &Kind,
-                                               CXXCastPath &BasePath);
-static TryCastResult TryStaticMemberFunctionPointerToFunctionPointerCast(
-    Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType,
-    bool CStyle, SourceRange OpRange, unsigned &msg, CastKind &Kind,
-    CXXCastPath &BasePath);
+static TryCastResult
+TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
+                             QualType DestType, bool CStyle,
+                             SourceRange OpRange, unsigned &msg, CastKind 
&Kind,
+                             CXXCastPath &BasePath);
 
 static TryCastResult
 TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
@@ -1434,13 +1428,6 @@ static TryCastResult TryStaticCast(Sema &Self, 
ExprResult &SrcExpr,
     }
   }
 
-  // GCC extension: convert a PMF constant into a function pointer.
-  tcr = TryStaticMemberFunctionPointerToFunctionPointerCast(
-      Self, SrcExpr, SrcType, DestType, CStyle, OpRange, msg, Kind, BasePath);
-
-  if (tcr != TC_NotApplicable)
-    return tcr;
-
   // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
   // C++ 5.2.9p8 additionally disallows a cast path through virtual 
inheritance.
   tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
@@ -1845,58 +1832,6 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult 
&SrcExpr, QualType SrcType,
   return TC_Success;
 }
 
-/// TryStaticMemberFunctionPointerToFunctionPointerCast - Tests whether a
-/// conversion from PMF constant to function pointer is valid.
-TryCastResult TryStaticMemberFunctionPointerToFunctionPointerCast(
-    Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType,
-    bool CStyle, SourceRange OpRange, unsigned &msg, CastKind &Kind,
-    CXXCastPath &BasePath) {
-  const TargetCXXABI &CXXABI = Self.Context.getTargetInfo().getCXXABI();
-  if (!CXXABI.isItaniumFamily())
-    return TC_NotApplicable;
-
-  const PointerType *DestPtr = DestType->getAs<PointerType>();
-  if (!DestPtr)
-    return TC_NotApplicable;
-
-  const FunctionProtoType *DestFnType =
-      DestPtr->getPointeeType()->getAs<FunctionProtoType>();
-  if (!DestFnType || DestFnType->getNumParams() == 0)
-    return TC_NotApplicable;
-
-  auto *ClsPtr = DestFnType->getParamType(0)->getAs<PointerType>();
-  if (!ClsPtr)
-    return TC_NotApplicable;
-
-  auto *ClsRec = ClsPtr->getPointeeType()->getAs<RecordType>();
-  if (!ClsRec)
-    return TC_NotApplicable;
-
-  auto *ClsTy = ClsRec->getAsCXXRecordDecl();
-  if (!ClsTy)
-    return TC_NotApplicable;
-
-  auto EPI = DestFnType->getExtProtoInfo();
-  EPI.TypeQuals = ClsPtr->getPointeeType().getQualifiers();
-  auto FuncTy =
-      Self.Context.getFunctionType(DestFnType->getCallResultType(Self.Context),
-                                   DestFnType->param_types().drop_front(), 
EPI);
-  auto DestPMFTy = Self.Context.getMemberPointerType(FuncTy, nullptr, ClsTy);
-
-  ExprResult Result = SrcExpr;
-
-  if (SrcType.getCanonicalType() != DestPMFTy) {
-    TryCastResult Res = TryStaticMemberPointerUpcast(
-        Self, Result, SrcType, DestType, CStyle, OpRange, msg, Kind, BasePath);
-    if (Res != TC_Success)
-      return TC_NotApplicable;
-  }
-
-  Kind = CK_BoundMemberFunctionToFunctionPointer;
-  msg = diag::ext_bound_member_function_conversion;
-  return TC_Extension;
-}
-
 /// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2
 /// is valid:
 ///
@@ -2352,7 +2287,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, 
ExprResult &SrcExpr,
 
   const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(),
                           *SrcMemPtr = SrcType->getAs<MemberPointerType>();
-  if (DestMemPtr && SrcMemPtr) {
+  if (SrcMemPtr) {
+    // GNU extension: check if we can convert a pmf to a function pointer
+    if (!DestMemPtr) {
+      if (DestType->isFunctionPointerType() &&
+          SrcMemPtr->isMemberFunctionPointer() &&
+          Self.Context.getTargetInfo().getCXXABI().isItaniumFamily()) {
+        Kind = CK_BoundMemberFunctionToFunctionPointer;
+        msg = diag::ext_bound_member_function_conversion;
+        return TC_Extension;
+      }
+      return TC_NotApplicable;
+    }
+
     // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
     //   can be explicitly converted to an rvalue of type "pointer to member
     //   of Y of type T2" if T1 and T2 are both function types or both object

>From a8d60983b49e36eb66c395fead0fb65a922233c9 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2...@gmail.com>
Date: Tue, 15 Apr 2025 13:23:43 +0800
Subject: [PATCH 3/6] Remove incorrect static analyzer support

---
 clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp | 3 +--
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp       | 6 +++---
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp 
b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 0ef1a14450cc2..02f34bc30f554 100644
--- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -190,8 +190,7 @@ const PointerToMemberData *BasicValueFactory::accumCXXBase(
     const nonloc::PointerToMember &PTM, const CastKind &kind) {
   assert((kind == CK_DerivedToBaseMemberPointer ||
           kind == CK_BaseToDerivedMemberPointer ||
-          kind == CK_ReinterpretMemberPointer ||
-          kind == CK_BoundMemberFunctionToFunctionPointer) &&
+          kind == CK_ReinterpretMemberPointer) &&
          "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index e470f7df3cef0..d28752febce43 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -505,8 +505,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
       }
       case CK_DerivedToBaseMemberPointer:
       case CK_BaseToDerivedMemberPointer:
-      case CK_ReinterpretMemberPointer:
-      case CK_BoundMemberFunctionToFunctionPointer: {
+      case CK_ReinterpretMemberPointer: {
         SVal V = state->getSVal(Ex, LCtx);
         if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) {
           SVal CastedPTMSV =
@@ -525,7 +524,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
       case CK_VectorSplat:
       case CK_HLSLElementwiseCast:
       case CK_HLSLAggregateSplatCast:
-      case CK_HLSLVectorTruncation: {
+      case CK_HLSLVectorTruncation:
+      case CK_BoundMemberFunctionToFunctionPointer: {
         QualType resultType = CastE->getType();
         if (CastE->isGLValue())
           resultType = getContext().getPointerType(resultType);

>From bfdeefdbe2959e1cedbd0f2d9142b8c9c0b20de1 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2...@gmail.com>
Date: Tue, 15 Apr 2025 16:29:11 +0800
Subject: [PATCH 4/6] [Clang] Add codegen support

---
 clang/lib/AST/Expr.cpp             |  4 +++-
 clang/lib/CodeGen/CGExprScalar.cpp | 33 +++++++++++++++++++++++++++++-
 clang/lib/Sema/SemaCast.cpp        | 32 ++++++++++++++---------------
 3 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index bae06543207b9..967fb42668902 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1866,7 +1866,9 @@ bool CastExpr::CastConsistency() const {
 
   case CK_BoundMemberFunctionToFunctionPointer:
     assert(getType()->isFunctionPointerType());
-    assert(getSubExpr()->getType()->isMemberPointerType());
+    assert(getSubExpr()->getType()->isMemberPointerType() ||
+           getSubExpr()->getType()->isSpecificPlaceholderType(
+               BuiltinType::BoundMember));
     goto CheckNoBasePath;
 
   case CK_BitCast:
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 9cf2dcf376133..b2cca91f1b733 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2581,8 +2581,39 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
     return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
   }
 
+  case CK_BoundMemberFunctionToFunctionPointer: {
+    // Special handling bound member functions
+    if (E->isBoundMemberFunction(CGF.getContext())) {
+      auto *BO = cast<BinaryOperator>(E->IgnoreParens());
+      const Expr *BaseExpr = BO->getLHS();
+      const Expr *MemFnExpr = BO->getRHS();
+
+      const auto *MPT = MemFnExpr->getType()->castAs<MemberPointerType>();
+      const auto *FPT = MPT->getPointeeType()->castAs<FunctionProtoType>();
+      const auto *RD = MPT->getMostRecentCXXRecordDecl();
+
+      // Emit the 'this' pointer.
+      Address This = Address::invalid();
+      if (BO->getOpcode() == BO_PtrMemI)
+        This = CGF.EmitPointerWithAlignment(BaseExpr, nullptr, nullptr,
+                                            KnownNonNull);
+      else
+        This = CGF.EmitLValue(BaseExpr, KnownNonNull).getAddress();
+
+      // Get the member function pointer.
+      llvm::Value *MemFnPtr = CGF.EmitScalarExpr(MemFnExpr);
+
+      // Ask the ABI to load the callee.  Note that This is modified.
+      llvm::Value *ThisPtrForCall = nullptr;
+      CGCallee Callee = CGF.CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(
+          CGF, BO, This, ThisPtrForCall, MemFnPtr, MPT);
+      return Callee.getFunctionPointer();
+    }
+
+    // fallback to the case without the base object address
+  }
+    [[fallthrough]];
   case CK_ReinterpretMemberPointer:
-  case CK_BoundMemberFunctionToFunctionPointer:
   case CK_BaseToDerivedMemberPointer:
   case CK_DerivedToBaseMemberPointer: {
     Value *Src = Visit(E);
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 964988e6344f1..ec4d4e5f3f370 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1196,9 +1196,11 @@ static unsigned int checkCastFunctionType(Sema &Self, 
const ExprResult &SrcExpr,
 /// like this:
 /// char *bytes = reinterpret_cast\<char*\>(int_ptr);
 void CastOperation::CheckReinterpretCast() {
-  if (ValueKind == VK_PRValue && !isPlaceholder(BuiltinType::Overload))
-    SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
-  else
+  if (ValueKind == VK_PRValue) {
+    if (!isPlaceholder(BuiltinType::Overload) &&
+        !isPlaceholder(BuiltinType::BoundMember))
+      SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
+  } else
     checkNonOverloadPlaceholders();
   if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
     return;
@@ -2287,19 +2289,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, 
ExprResult &SrcExpr,
 
   const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(),
                           *SrcMemPtr = SrcType->getAs<MemberPointerType>();
-  if (SrcMemPtr) {
-    // GNU extension: check if we can convert a pmf to a function pointer
-    if (!DestMemPtr) {
-      if (DestType->isFunctionPointerType() &&
-          SrcMemPtr->isMemberFunctionPointer() &&
-          Self.Context.getTargetInfo().getCXXABI().isItaniumFamily()) {
-        Kind = CK_BoundMemberFunctionToFunctionPointer;
-        msg = diag::ext_bound_member_function_conversion;
-        return TC_Extension;
-      }
-      return TC_NotApplicable;
-    }
-
+  if (SrcMemPtr && DestMemPtr) {
     // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
     //   can be explicitly converted to an rvalue of type "pointer to member
     //   of Y of type T2" if T1 and T2 are both function types or both object
@@ -2337,6 +2327,16 @@ static TryCastResult TryReinterpretCast(Sema &Self, 
ExprResult &SrcExpr,
     return TC_Success;
   }
 
+  // GNU extension: check if we can convert a pmf to a function pointer
+  if (DestType->isFunctionPointerType() &&
+      (SrcType->isMemberFunctionPointerType() ||
+       SrcExpr.get()->isBoundMemberFunction(Self.Context)) &&
+      Self.Context.getTargetInfo().getCXXABI().isItaniumFamily()) {
+    Kind = CK_BoundMemberFunctionToFunctionPointer;
+    msg = diag::ext_bound_member_function_conversion;
+    return TC_Extension;
+  }
+
   // See below for the enumeral issue.
   if (SrcType->isNullPtrType() && DestType->isIntegralType(Self.Context)) {
     // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral

>From db282232bdb94fbc1237377cf978f9178950a941 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2...@gmail.com>
Date: Tue, 15 Apr 2025 17:56:29 +0800
Subject: [PATCH 5/6] Fix test

---
 clang/lib/Sema/SemaCast.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index ec4d4e5f3f370..1934b9830852b 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1198,7 +1198,8 @@ static unsigned int checkCastFunctionType(Sema &Self, 
const ExprResult &SrcExpr,
 void CastOperation::CheckReinterpretCast() {
   if (ValueKind == VK_PRValue) {
     if (!isPlaceholder(BuiltinType::Overload) &&
-        !isPlaceholder(BuiltinType::BoundMember))
+        !(isPlaceholder(BuiltinType::BoundMember) &&
+          DestType->isFunctionPointerType()))
       SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
   } else
     checkNonOverloadPlaceholders();

>From 9f04b0751d04c18292f9d1c25e239b3ead87c48d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2...@gmail.com>
Date: Tue, 15 Apr 2025 21:48:22 +0800
Subject: [PATCH 6/6] Add tests. NFC.

---
 clang/test/CodeGenCXX/pmf-conversions.cpp | 105 ++++++++++++++++++++++
 clang/test/SemaCXX/pmf-conversions.cpp    |  50 +++++++++++
 2 files changed, 155 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/pmf-conversions.cpp
 create mode 100644 clang/test/SemaCXX/pmf-conversions.cpp

diff --git a/clang/test/CodeGenCXX/pmf-conversions.cpp 
b/clang/test/CodeGenCXX/pmf-conversions.cpp
new file mode 100644
index 0000000000000..cbe2cd4d09bd6
--- /dev/null
+++ b/clang/test/CodeGenCXX/pmf-conversions.cpp
@@ -0,0 +1,105 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --check-globals all --version 5
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -Wno-pmf-conversions %s -O3 
-emit-llvm -o - | FileCheck %s --check-globals
+
+struct A {
+  int data;
+//.
+// CHECK: @method = local_unnamed_addr global ptr @_ZN1A6methodEv, align 8
+//.
+// CHECK-LABEL: define linkonce_odr noundef i32 @_ZN1A6methodEv(
+// CHECK-SAME: ptr noundef nonnull align 8 dereferenceable(12) [[THIS:%.*]]) 
#[[ATTR0:[0-9]+]] comdat align 2 {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret i32 0
+//
+  int method() { return 0; }
+  virtual int virtual_method() { return 1; }
+  virtual ~A() = default;
+};
+
+struct C {
+  int data;
+};
+
+struct B : C, A {
+  virtual int virtual_method() override { return 2; }
+};
+
+using pmf_type = int (A::*)();
+using pf_type = int (*)(A*);
+
+pf_type method = reinterpret_cast<pf_type>(&A::method);
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z11convert_pmfP1AMS_FivE(
+// CHECK-SAME: ptr noundef readonly captures(none) [[P:%.*]], i64 
[[METHOD_COERCE0:%.*]], i64 [[METHOD_COERCE1:%.*]]) local_unnamed_addr 
#[[ATTR1:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = and i64 [[METHOD_COERCE0]], 1
+// CHECK-NEXT:    [[MEMPTR_ISVIRTUAL_NOT:%.*]] = icmp eq i64 [[TMP0]], 0
+// CHECK-NEXT:    br i1 [[MEMPTR_ISVIRTUAL_NOT]], label 
%[[MEMPTR_NONVIRTUAL:.*]], label %[[MEMPTR_VIRTUAL:.*]]
+// CHECK:       [[MEMPTR_VIRTUAL]]:
+// CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 
[[METHOD_COERCE1]]
+// CHECK-NEXT:    [[VTABLE:%.*]] = load ptr, ptr [[TMP1]], align 8, !tbaa 
[[TBAA2:![0-9]+]]
+// CHECK-NEXT:    [[TMP2:%.*]] = getelementptr i8, ptr [[VTABLE]], i64 
[[METHOD_COERCE0]]
+// CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i8, ptr [[TMP2]], i64 -1
+// CHECK-NEXT:    [[MEMPTR_VIRTUALFN:%.*]] = load ptr, ptr [[TMP3]], align 8, 
!nosanitize [[META5:![0-9]+]]
+// CHECK-NEXT:    br label %[[MEMPTR_END:.*]]
+// CHECK:       [[MEMPTR_NONVIRTUAL]]:
+// CHECK-NEXT:    [[MEMPTR_NONVIRTUALFN:%.*]] = inttoptr i64 
[[METHOD_COERCE0]] to ptr
+// CHECK-NEXT:    br label %[[MEMPTR_END]]
+// CHECK:       [[MEMPTR_END]]:
+// CHECK-NEXT:    [[TMP4:%.*]] = phi ptr [ [[MEMPTR_VIRTUALFN]], 
%[[MEMPTR_VIRTUAL]] ], [ [[MEMPTR_NONVIRTUALFN]], %[[MEMPTR_NONVIRTUAL]] ]
+// CHECK-NEXT:    ret ptr [[TMP4]]
+//
+pf_type convert_pmf(A* p, pmf_type method) {
+  return reinterpret_cast<pf_type>(p->*method);
+}
+
+// CHECK-LABEL: define dso_local noundef nonnull ptr @_Z17convert_pmf_constP1A(
+// CHECK-SAME: ptr noundef readnone captures(none) [[P:%.*]]) 
local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret ptr @_ZN1A6methodEv
+//
+pf_type convert_pmf_const(A* p) {
+  return reinterpret_cast<pf_type>(p->*(&A::method));
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z18convert_vpmf_constP1A(
+// CHECK-SAME: ptr noundef readonly captures(none) [[P:%.*]]) 
local_unnamed_addr #[[ATTR1]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[VTABLE:%.*]] = load ptr, ptr [[P]], align 8, !tbaa 
[[TBAA2]]
+// CHECK-NEXT:    [[MEMPTR_VIRTUALFN:%.*]] = load ptr, ptr [[VTABLE]], align 
8, !nosanitize [[META5]]
+// CHECK-NEXT:    ret ptr [[MEMPTR_VIRTUALFN]]
+//
+pf_type convert_vpmf_const(A* p) {
+  return reinterpret_cast<pf_type>(p->*(&A::virtual_method));
+}
+
+// CHECK-LABEL: define dso_local noundef range(i32 0, 2) i32 
@_Z21call_b_virtual_methodP1B(
+// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[VTABLE_I:%.*]] = load ptr, ptr [[P]], align 8, !tbaa 
[[TBAA2]]
+// CHECK-NEXT:    [[MEMPTR_VIRTUALFN_I:%.*]] = load ptr, ptr [[VTABLE_I]], 
align 8, !nosanitize [[META5]]
+// CHECK-NEXT:    [[CALL1:%.*]] = tail call noundef i32 
[[MEMPTR_VIRTUALFN_I]](ptr noundef nonnull [[P]]) #[[ATTR3:[0-9]+]]
+// CHECK-NEXT:    [[VTABLE:%.*]] = load ptr, ptr [[P]], align 8, !tbaa 
[[TBAA2]]
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[VTABLE]], align 8
+// CHECK-NEXT:    [[CALL2:%.*]] = tail call noundef i32 [[TMP0]](ptr noundef 
nonnull align 8 dereferenceable(16) [[P]]) #[[ATTR3]]
+// CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CALL1]], [[CALL2]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i32
+// CHECK-NEXT:    ret i32 [[CONV]]
+//
+int call_b_virtual_method(B* p) {
+  return convert_pmf(p, &A::virtual_method)(p) == p->virtual_method();
+}
+
+//.
+// CHECK: attributes #[[ATTR0]] = { mustprogress nounwind 
"min-legal-vector-width"="0" "no-trapping-math"="true" 
"stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" 
}
+// CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync 
nounwind willreturn memory(read, inaccessiblemem: none) 
"min-legal-vector-width"="0" "no-trapping-math"="true" 
"stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" 
}
+// CHECK: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync 
nounwind willreturn memory(none) "min-legal-vector-width"="0" 
"no-trapping-math"="true" "stack-protector-buffer-size"="8" 
"target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+// CHECK: attributes #[[ATTR3]] = { nounwind }
+//.
+// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
+// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
+// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// CHECK: [[META3]] = !{!"vtable pointer", [[META4:![0-9]+]], i64 0}
+// CHECK: [[META4]] = !{!"Simple C++ TBAA"}
+// CHECK: [[META5]] = !{}
+//.
diff --git a/clang/test/SemaCXX/pmf-conversions.cpp 
b/clang/test/SemaCXX/pmf-conversions.cpp
new file mode 100644
index 0000000000000..e683d5d314072
--- /dev/null
+++ b/clang/test/SemaCXX/pmf-conversions.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only %s -verify
+
+struct S {
+  int a;
+  void method();
+  void method_overload();
+  void method_overload(int);
+};
+
+using pmf_type = void (S::*)();
+using pm_type = int S::*;
+using pf_type = void (*)(S*);
+using pf_type_mismatched = void (*)(S*, int);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpmf-conversions"
+
+void pmf_convert_no_object(pmf_type method, pm_type field) {
+  (void)reinterpret_cast<pf_type>(&S::method);
+  (void)reinterpret_cast<pf_type>(method);
+  (void)reinterpret_cast<pf_type>(((method)));
+  (void)(pf_type)(&S::method);
+  (void)(pf_type)(method);
+  (void)reinterpret_cast<pf_type_mismatched>(&S::method);
+  (void)reinterpret_cast<pf_type_mismatched>(method);
+  (void)reinterpret_cast<pf_type>(&S::a); // expected-error {{reinterpret_cast 
from 'int S::*' to 'pf_type' (aka 'void (*)(S *)') is not allowed}}
+  (void)reinterpret_cast<pf_type>(field); // expected-error {{reinterpret_cast 
from 'pm_type' (aka 'int S::*') to 'pf_type' (aka 'void (*)(S *)') is not 
allowed}}
+}
+
+void pmf_convert_with_base(S* p, S& r, pmf_type method, pm_type field) {
+  (void)reinterpret_cast<pf_type>(p->*(&S::method));
+  (void)reinterpret_cast<pf_type>(((p)->*((&S::method))));
+  (void)reinterpret_cast<pf_type>(p->*method);
+  (void)reinterpret_cast<pf_type>(((p)->*(method)));
+  
(void)reinterpret_cast<pf_type>(p->*(static_cast<pmf_type>(&S::method_overload)));
+  (void)(pf_type)(p->*(&S::method)); // expected-error {{reference to 
non-static member function must be called; did you mean to call it with no 
arguments?}} expected-error {{cannot cast from type 'void' to pointer type 
'pf_type' (aka 'void (*)(S *)')}}
+  (void)(pf_type)(p->*method); // expected-error {{reference to non-static 
member function must be called; did you mean to call it with no arguments?}} 
expected-error {{cannot cast from type 'void' to pointer type 'pf_type' (aka 
'void (*)(S *)')}}
+  (void)reinterpret_cast<pf_type_mismatched>(p->*method);
+  (void)reinterpret_cast<pf_type>(r.*method);
+  (void)reinterpret_cast<pf_type_mismatched>(r.*method);
+  (void)reinterpret_cast<pf_type>(p->*(&S::a));
+  (void)reinterpret_cast<pf_type>(p->*field);
+}
+
+#pragma clang diagnostic pop
+
+void pmf_convert_warning(S *p, pmf_type method) {
+  (void)reinterpret_cast<pf_type>(method); // expected-warning {{converting 
the bound member function 'pmf_type' (aka 'void (S::*)()') to a function 
pointer 'pf_type' (aka 'void (*)(S *)') is a GNU extension}}
+  (void)reinterpret_cast<pf_type>(p->*method); // expected-warning 
{{converting the bound member function '<bound member function type>' to a 
function pointer 'pf_type' (aka 'void (*)(S *)') is a GNU extension}}
+}

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

Reply via email to