[clang] [Clang] Add support for GCC bound member functions extension (PR #135649)
Yingwei Zheng via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 14 18:36:47 PDT 2025
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 <dtcxzyw2333 at 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 <dtcxzyw2333 at 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}};
More information about the cfe-commits
mailing list