https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/135649
>From 6795a5143129520d2db343d768507174a70da453 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Tue, 15 Apr 2025 01:24:10 +0800 Subject: [PATCH 1/2] [Clang] Add support for GCC bound member functions extension --- clang/include/clang/AST/ExprCXX.h | 37 +++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 4 ++ .../clang/Basic/DiagnosticSemaKinds.td | 3 + .../include/clang/Serialization/ASTBitCodes.h | 3 + clang/lib/AST/ExprConstant.cpp | 6 ++ clang/lib/AST/StmtPrinter.cpp | 12 ++++ clang/lib/AST/StmtProfile.cpp | 8 +++ clang/lib/Sema/SemaCast.cpp | 64 +++++++++++++++++++ clang/lib/Sema/TreeTransform.h | 35 ++++++++++ clang/lib/Serialization/ASTReaderStmt.cpp | 16 +++++ clang/lib/Serialization/ASTWriterStmt.cpp | 7 ++ 11 files changed, 195 insertions(+) diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 844f6dd90ae1d..7918ea0b20d41 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5448,6 +5448,43 @@ class BuiltinBitCastExpr final } }; +/// Represents a GCC extension bound pointer-to-member-function -> function +/// pointer conversion. +class BoundPointerToMemberFunctionToFunctionPointerCastExpr final + : public ExplicitCastExpr, + private llvm::TrailingObjects<CXXDynamicCastExpr, CXXBaseSpecifier *> { + friend class ASTStmtReader; + friend class CastExpr; + + Expr *BaseExpr; + +public: + BoundPointerToMemberFunctionToFunctionPointerCastExpr( + QualType T, ExprValueKind VK, CastKind CK, Expr *SrcExpr, + TypeSourceInfo *DstType, Expr *BaseExpr) + : ExplicitCastExpr( + BoundPointerToMemberFunctionToFunctionPointerCastExprClass, T, VK, + CK, SrcExpr, 0, false, DstType), + BaseExpr(BaseExpr) {} + + BoundPointerToMemberFunctionToFunctionPointerCastExpr(EmptyShell Empty) + : ExplicitCastExpr(BuiltinBitCastExprClass, Empty, 0, false) {} + + Expr *getBaseExpr() const LLVM_READONLY { return BaseExpr; } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return BaseExpr ? BaseExpr->getBeginLoc() : getSubExpr()->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { + return getSubExpr()->getEndLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == + BoundPointerToMemberFunctionToFunctionPointerCastExprClass; + } +}; + } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 3edc8684d0a19..e917f468b322f 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2567,6 +2567,10 @@ DEF_TRAVERSE_STMT(BuiltinBitCastExpr, { TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) +DEF_TRAVERSE_STMT(BoundPointerToMemberFunctionToFunctionPointerCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) + template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr( InitListExpr *S, DataRecursionQueue *Queue) { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 180ca39bc07e9..5f5d53c968bbc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5120,6 +5120,9 @@ 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 warn_bound_member_function_conversion + : Warning< + "converting the bound member function %0 to a function pointer %1">; 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/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 5cb9998126a85..98ec32d0e5b98 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1869,6 +1869,9 @@ enum StmtCode { /// A BuiltinBitCastExpr record. EXPR_BUILTIN_BIT_CAST, + /// A BoundPointerToMemberFunctionToFunctionPointerCastExpr record. + EXPR_PMF_CAST, + /// A UserDefinedLiteral record. EXPR_USER_DEFINED_LITERAL, diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d1cc722fb7945..4382bb05e7b97 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8121,6 +8121,10 @@ class ExprEvaluatorBase bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) { return static_cast<Derived*>(this)->VisitCastExpr(E); } + bool VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr( + const BoundPointerToMemberFunctionToFunctionPointerCastExpr *E) { + return static_cast<Derived *>(this)->VisitCastExpr(E); + } bool VisitBinaryOperator(const BinaryOperator *E) { switch (E->getOpcode()) { @@ -17662,6 +17666,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { return ICEDiag(IK_NotICE, E->getBeginLoc()); return CheckICE(cast<CastExpr>(E)->getSubExpr(), Ctx); } + case Expr::BoundPointerToMemberFunctionToFunctionPointerCastExprClass: + return ICEDiag(IK_NotICE, E->getBeginLoc()); } llvm_unreachable("Invalid StmtClass!"); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index dbe2432d5c799..d515314be4efa 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2135,6 +2135,18 @@ void StmtPrinter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *Node) { OS << ")"; } +void StmtPrinter::VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr( + BoundPointerToMemberFunctionToFunctionPointerCastExpr *Node) { + OS << "("; + Node->getTypeAsWritten().print(OS, Policy); + OS << ")"; + if (auto *Base = Node->getBaseExpr()) { + PrintExpr(Base); + OS << ".*"; + } + PrintExpr(Node->getSubExpr()); +} + void StmtPrinter::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *Node) { VisitCXXNamedCastExpr(Node); } diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 83d54da9be7e5..efb68c7bf78e6 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2014,6 +2014,14 @@ void StmtProfiler::VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *S) { VisitType(S->getTypeInfoAsWritten()->getType()); } +void StmtProfiler::VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr( + const BoundPointerToMemberFunctionToFunctionPointerCastExpr *S) { + VisitExpr(S); + VisitType(S->getTypeInfoAsWritten()->getType()); + if (auto *Base = S->getBaseExpr()) + VisitExpr(Base); +} + void StmtProfiler::VisitCXXAddrspaceCastExpr(const CXXAddrspaceCastExpr *S) { VisitCXXNamedCastExpr(S); } diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 2824dfce1572c..308d541c1dd9e 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,59 @@ 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_NotApplicable) + return TC_NotApplicable; + } + + DestPMFTy->dump(); + + // SrcExpr = Result; + return TC_NotApplicable; +} + /// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2 /// is valid: /// diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index bb58ec49612c8..41d3c9aad3d54 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3329,6 +3329,16 @@ class TreeTransform { return getSema().BuildBuiltinBitCastExpr(KWLoc, TSI, Sub, RParenLoc); } + /// Build a new C++ bound pointer-to-member-function to function pointer + /// conversion expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildBoundPointerToMemberFunctionToFunctionPointerCastExpr( + TypeSourceInfo *TSI, Expr *Sub, Expr *Base) { + return ExprError(); + } + /// Build a new C++ typeid(type) expression. /// /// By default, performs semantic analysis to build the new expression. @@ -14175,6 +14185,31 @@ TreeTransform<Derived>::TransformBuiltinBitCastExpr(BuiltinBitCastExpr *BCE) { Sub.get(), BCE->getEndLoc()); } +template <typename Derived> +ExprResult TreeTransform<Derived>:: + TransformBoundPointerToMemberFunctionToFunctionPointerCastExpr( + BoundPointerToMemberFunctionToFunctionPointerCastExpr *E) { + TypeSourceInfo *TSI = getDerived().TransformType(E->getTypeInfoAsWritten()); + if (!TSI) + return ExprError(); + + ExprResult Sub = getDerived().TransformExpr(E->getSubExpr()); + if (Sub.isInvalid()) + return ExprError(); + + auto *Base = E->getBaseExpr(); + if (Base) { + ExprResult NewBase = getDerived().TransformExpr(Base); + if (NewBase.isInvalid()) + return ExprError(); + Base = NewBase.get(); + } + + return getDerived() + .RebuildBoundPointerToMemberFunctionToFunctionPointerCastExpr( + TSI, Sub.get(), Base); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index f41cfcc53a35d..a9445e6623970 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1846,6 +1846,12 @@ void ASTStmtReader::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *E) { E->RParenLoc = readSourceLocation(); } +void ASTStmtReader::VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr( + BoundPointerToMemberFunctionToFunctionPointerCastExpr *E) { + VisitExplicitCastExpr(E); + E->BaseExpr = Record.readSubExpr(); +} + void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) { VisitCallExpr(E); E->UDSuffixLoc = readSourceLocation(); @@ -4150,6 +4156,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; } + case EXPR_PMF_CAST: { +#ifndef NDEBUG + unsigned PathSize = Record[ASTStmtReader::NumExprFields]; + assert(PathSize == 0 && "Wrong PathSize!"); +#endif + S = new (Context) + BoundPointerToMemberFunctionToFunctionPointerCastExpr(Empty); + break; + } + case EXPR_USER_DEFINED_LITERAL: { auto NumArgs = Record[ASTStmtReader::NumExprFields]; BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index b9eabd5ddb64c..46413f917cf07 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1839,6 +1839,13 @@ void ASTStmtWriter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *E) { Code = serialization::EXPR_BUILTIN_BIT_CAST; } +void ASTStmtWriter::VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr( + BoundPointerToMemberFunctionToFunctionPointerCastExpr *E) { + VisitExplicitCastExpr(E); + Record.AddStmt(E->getBaseExpr()); + Code = serialization::EXPR_PMF_CAST; +} + void ASTStmtWriter::VisitUserDefinedLiteral(UserDefinedLiteral *E) { VisitCallExpr(E); Record.AddSourceLocation(E->UDSuffixLoc); >From ad35c72575b8b3cfd2dde1060be7500309f2bea8 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Tue, 15 Apr 2025 09:36:30 +0800 Subject: [PATCH 2/2] Update --- clang/include/clang-c/Index.h | 5 +++++ clang/include/clang/Basic/StmtNodes.td | 1 + clang/tools/libclang/CIndex.cpp | 3 +++ clang/tools/libclang/CXCursor.cpp | 3 +++ 4 files changed, 12 insertions(+) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 38e2417dcd181..dce77eef6ec6c 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2218,6 +2218,11 @@ enum CXCursorKind { */ CXCursor_OpenACCCacheConstruct = 333, + /** GNU C++ bound pointer to member function to function pointer cast + * expression. + */ + CXCursor_BoundPointerToMemberFunctionToFunctionPointerCastExpr = 334, + CXCursor_LastStmt = CXCursor_OpenACCCacheConstruct, /** diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 9526fa5808aa5..1e3681785905b 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -113,6 +113,7 @@ def AddrLabelExpr : StmtNode<Expr>; def StmtExpr : StmtNode<Expr>; def ChooseExpr : StmtNode<Expr>; def GNUNullExpr : StmtNode<Expr>; +def BoundPointerToMemberFunctionToFunctionPointerCastExpr : StmtNode<ExplicitCastExpr>; // C++ Expressions. def CXXOperatorCallExpr : StmtNode<CallExpr>; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index c8db6c92bb4d4..bdc14232dd52e 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -22,6 +22,7 @@ #include "CXType.h" #include "CursorVisitor.h" #include "clang-c/FatalErrorHandler.h" +#include "clang-c/Index.h" #include "clang/AST/Attr.h" #include "clang/AST/AttrVisitor.h" #include "clang/AST/DeclObjCCommon.h" @@ -6501,6 +6502,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("OpenACCUpdateConstruct"); case CXCursor_OpenACCAtomicConstruct: return cxstring::createRef("OpenACCAtomicConstruct"); + case CXCursor_BoundPointerToMemberFunctionToFunctionPointerCastExpr: + return cxstring::createRef("BoundPointerToMemberFunctionToFunctionPointerCastExpr"); } llvm_unreachable("Unhandled CXCursorKind"); diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 1d15120106017..162af05bd7600 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -937,6 +937,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::OMPAssumeDirectiveClass: K = CXCursor_OMPAssumeDirective; break; + case Stmt::BoundPointerToMemberFunctionToFunctionPointerCastExprClass: + K = CXCursor_BoundPointerToMemberFunctionToFunctionPointerCastExpr; + break; } CXCursor C = {K, 0, {Parent, S, TU}}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits