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/2] [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/2] 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits