Skip to content

Commit 6795a51

Browse files
committed
[Clang] Add support for GCC bound member functions extension
1 parent e710a5a commit 6795a51

File tree

11 files changed

+195
-0
lines changed

11 files changed

+195
-0
lines changed

clang/include/clang/AST/ExprCXX.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5448,6 +5448,43 @@ class BuiltinBitCastExpr final
54485448
}
54495449
};
54505450

5451+
/// Represents a GCC extension bound pointer-to-member-function -> function
5452+
/// pointer conversion.
5453+
class BoundPointerToMemberFunctionToFunctionPointerCastExpr final
5454+
: public ExplicitCastExpr,
5455+
private llvm::TrailingObjects<CXXDynamicCastExpr, CXXBaseSpecifier *> {
5456+
friend class ASTStmtReader;
5457+
friend class CastExpr;
5458+
5459+
Expr *BaseExpr;
5460+
5461+
public:
5462+
BoundPointerToMemberFunctionToFunctionPointerCastExpr(
5463+
QualType T, ExprValueKind VK, CastKind CK, Expr *SrcExpr,
5464+
TypeSourceInfo *DstType, Expr *BaseExpr)
5465+
: ExplicitCastExpr(
5466+
BoundPointerToMemberFunctionToFunctionPointerCastExprClass, T, VK,
5467+
CK, SrcExpr, 0, false, DstType),
5468+
BaseExpr(BaseExpr) {}
5469+
5470+
BoundPointerToMemberFunctionToFunctionPointerCastExpr(EmptyShell Empty)
5471+
: ExplicitCastExpr(BuiltinBitCastExprClass, Empty, 0, false) {}
5472+
5473+
Expr *getBaseExpr() const LLVM_READONLY { return BaseExpr; }
5474+
5475+
SourceLocation getBeginLoc() const LLVM_READONLY {
5476+
return BaseExpr ? BaseExpr->getBeginLoc() : getSubExpr()->getBeginLoc();
5477+
}
5478+
SourceLocation getEndLoc() const LLVM_READONLY {
5479+
return getSubExpr()->getEndLoc();
5480+
}
5481+
5482+
static bool classof(const Stmt *T) {
5483+
return T->getStmtClass() ==
5484+
BoundPointerToMemberFunctionToFunctionPointerCastExprClass;
5485+
}
5486+
};
5487+
54515488
} // namespace clang
54525489

54535490
#endif // LLVM_CLANG_AST_EXPRCXX_H

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,6 +2567,10 @@ DEF_TRAVERSE_STMT(BuiltinBitCastExpr, {
25672567
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
25682568
})
25692569

2570+
DEF_TRAVERSE_STMT(BoundPointerToMemberFunctionToFunctionPointerCastExpr, {
2571+
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
2572+
})
2573+
25702574
template <typename Derived>
25712575
bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
25722576
InitListExpr *S, DataRecursionQueue *Queue) {

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5120,6 +5120,9 @@ def err_ovl_unresolvable : Error<
51205120
def err_bound_member_function : Error<
51215121
"reference to non-static member function must be called"
51225122
"%select{|; did you mean to call it with no arguments?}0">;
5123+
def warn_bound_member_function_conversion
5124+
: Warning<
5125+
"converting the bound member function %0 to a function pointer %1">;
51235126
def note_possible_target_of_call : Note<"possible target for call">;
51245127
def err_no_viable_destructor : Error<
51255128
"no viable destructor found for class %0">;

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,9 @@ enum StmtCode {
18691869
/// A BuiltinBitCastExpr record.
18701870
EXPR_BUILTIN_BIT_CAST,
18711871

1872+
/// A BoundPointerToMemberFunctionToFunctionPointerCastExpr record.
1873+
EXPR_PMF_CAST,
1874+
18721875
/// A UserDefinedLiteral record.
18731876
EXPR_USER_DEFINED_LITERAL,
18741877

clang/lib/AST/ExprConstant.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8121,6 +8121,10 @@ class ExprEvaluatorBase
81218121
bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) {
81228122
return static_cast<Derived*>(this)->VisitCastExpr(E);
81238123
}
8124+
bool VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr(
8125+
const BoundPointerToMemberFunctionToFunctionPointerCastExpr *E) {
8126+
return static_cast<Derived *>(this)->VisitCastExpr(E);
8127+
}
81248128

81258129
bool VisitBinaryOperator(const BinaryOperator *E) {
81268130
switch (E->getOpcode()) {
@@ -17662,6 +17666,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
1766217666
return ICEDiag(IK_NotICE, E->getBeginLoc());
1766317667
return CheckICE(cast<CastExpr>(E)->getSubExpr(), Ctx);
1766417668
}
17669+
case Expr::BoundPointerToMemberFunctionToFunctionPointerCastExprClass:
17670+
return ICEDiag(IK_NotICE, E->getBeginLoc());
1766517671
}
1766617672

1766717673
llvm_unreachable("Invalid StmtClass!");

clang/lib/AST/StmtPrinter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,6 +2135,18 @@ void StmtPrinter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *Node) {
21352135
OS << ")";
21362136
}
21372137

2138+
void StmtPrinter::VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr(
2139+
BoundPointerToMemberFunctionToFunctionPointerCastExpr *Node) {
2140+
OS << "(";
2141+
Node->getTypeAsWritten().print(OS, Policy);
2142+
OS << ")";
2143+
if (auto *Base = Node->getBaseExpr()) {
2144+
PrintExpr(Base);
2145+
OS << ".*";
2146+
}
2147+
PrintExpr(Node->getSubExpr());
2148+
}
2149+
21382150
void StmtPrinter::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *Node) {
21392151
VisitCXXNamedCastExpr(Node);
21402152
}

clang/lib/AST/StmtProfile.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,6 +2014,14 @@ void StmtProfiler::VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *S) {
20142014
VisitType(S->getTypeInfoAsWritten()->getType());
20152015
}
20162016

2017+
void StmtProfiler::VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr(
2018+
const BoundPointerToMemberFunctionToFunctionPointerCastExpr *S) {
2019+
VisitExpr(S);
2020+
VisitType(S->getTypeInfoAsWritten()->getType());
2021+
if (auto *Base = S->getBaseExpr())
2022+
VisitExpr(Base);
2023+
}
2024+
20172025
void StmtProfiler::VisitCXXAddrspaceCastExpr(const CXXAddrspaceCastExpr *S) {
20182026
VisitCXXNamedCastExpr(S);
20192027
}

clang/lib/Sema/SemaCast.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExp
250250
unsigned &msg,
251251
CastKind &Kind,
252252
CXXCastPath &BasePath);
253+
static TryCastResult TryStaticMemberFunctionPointerToFunctionPointerCast(
254+
Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType,
255+
bool CStyle, SourceRange OpRange, unsigned &msg, CastKind &Kind,
256+
CXXCastPath &BasePath);
253257

254258
static TryCastResult
255259
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
@@ -1430,6 +1434,13 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
14301434
}
14311435
}
14321436

1437+
// GCC extension: convert a PMF constant into a function pointer.
1438+
tcr = TryStaticMemberFunctionPointerToFunctionPointerCast(
1439+
Self, SrcExpr, SrcType, DestType, CStyle, OpRange, msg, Kind, BasePath);
1440+
1441+
if (tcr != TC_NotApplicable)
1442+
return tcr;
1443+
14331444
// Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
14341445
// C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
14351446
tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
@@ -1834,6 +1845,59 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
18341845
return TC_Success;
18351846
}
18361847

1848+
/// TryStaticMemberFunctionPointerToFunctionPointerCast - Tests whether a
1849+
/// conversion from PMF constant to function pointer is valid.
1850+
TryCastResult TryStaticMemberFunctionPointerToFunctionPointerCast(
1851+
Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType,
1852+
bool CStyle, SourceRange OpRange, unsigned &msg, CastKind &Kind,
1853+
CXXCastPath &BasePath) {
1854+
const TargetCXXABI &CXXABI = Self.Context.getTargetInfo().getCXXABI();
1855+
if (!CXXABI.isItaniumFamily())
1856+
return TC_NotApplicable;
1857+
1858+
const PointerType *DestPtr = DestType->getAs<PointerType>();
1859+
if (!DestPtr)
1860+
return TC_NotApplicable;
1861+
1862+
const FunctionProtoType *DestFnType =
1863+
DestPtr->getPointeeType()->getAs<FunctionProtoType>();
1864+
if (!DestFnType || DestFnType->getNumParams() == 0)
1865+
return TC_NotApplicable;
1866+
1867+
auto *ClsPtr = DestFnType->getParamType(0)->getAs<PointerType>();
1868+
if (!ClsPtr)
1869+
return TC_NotApplicable;
1870+
1871+
auto *ClsRec = ClsPtr->getPointeeType()->getAs<RecordType>();
1872+
if (!ClsRec)
1873+
return TC_NotApplicable;
1874+
1875+
auto *ClsTy = ClsRec->getAsCXXRecordDecl();
1876+
if (!ClsTy)
1877+
return TC_NotApplicable;
1878+
1879+
auto EPI = DestFnType->getExtProtoInfo();
1880+
EPI.TypeQuals = ClsPtr->getPointeeType().getQualifiers();
1881+
auto FuncTy =
1882+
Self.Context.getFunctionType(DestFnType->getCallResultType(Self.Context),
1883+
DestFnType->param_types().drop_front(), EPI);
1884+
auto DestPMFTy = Self.Context.getMemberPointerType(FuncTy, nullptr, ClsTy);
1885+
1886+
ExprResult Result = SrcExpr;
1887+
1888+
if (SrcType.getCanonicalType() != DestPMFTy) {
1889+
TryCastResult Res = TryStaticMemberPointerUpcast(
1890+
Self, Result, SrcType, DestType, CStyle, OpRange, msg, Kind, BasePath);
1891+
if (Res == TC_NotApplicable)
1892+
return TC_NotApplicable;
1893+
}
1894+
1895+
DestPMFTy->dump();
1896+
1897+
// SrcExpr = Result;
1898+
return TC_NotApplicable;
1899+
}
1900+
18371901
/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2
18381902
/// is valid:
18391903
///

clang/lib/Sema/TreeTransform.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,6 +3329,16 @@ class TreeTransform {
33293329
return getSema().BuildBuiltinBitCastExpr(KWLoc, TSI, Sub, RParenLoc);
33303330
}
33313331

3332+
/// Build a new C++ bound pointer-to-member-function to function pointer
3333+
/// conversion expression.
3334+
///
3335+
/// By default, performs semantic analysis to build the new expression.
3336+
/// Subclasses may override this routine to provide different behavior.
3337+
ExprResult RebuildBoundPointerToMemberFunctionToFunctionPointerCastExpr(
3338+
TypeSourceInfo *TSI, Expr *Sub, Expr *Base) {
3339+
return ExprError();
3340+
}
3341+
33323342
/// Build a new C++ typeid(type) expression.
33333343
///
33343344
/// By default, performs semantic analysis to build the new expression.
@@ -14175,6 +14185,31 @@ TreeTransform<Derived>::TransformBuiltinBitCastExpr(BuiltinBitCastExpr *BCE) {
1417514185
Sub.get(), BCE->getEndLoc());
1417614186
}
1417714187

14188+
template <typename Derived>
14189+
ExprResult TreeTransform<Derived>::
14190+
TransformBoundPointerToMemberFunctionToFunctionPointerCastExpr(
14191+
BoundPointerToMemberFunctionToFunctionPointerCastExpr *E) {
14192+
TypeSourceInfo *TSI = getDerived().TransformType(E->getTypeInfoAsWritten());
14193+
if (!TSI)
14194+
return ExprError();
14195+
14196+
ExprResult Sub = getDerived().TransformExpr(E->getSubExpr());
14197+
if (Sub.isInvalid())
14198+
return ExprError();
14199+
14200+
auto *Base = E->getBaseExpr();
14201+
if (Base) {
14202+
ExprResult NewBase = getDerived().TransformExpr(Base);
14203+
if (NewBase.isInvalid())
14204+
return ExprError();
14205+
Base = NewBase.get();
14206+
}
14207+
14208+
return getDerived()
14209+
.RebuildBoundPointerToMemberFunctionToFunctionPointerCastExpr(
14210+
TSI, Sub.get(), Base);
14211+
}
14212+
1417814213
template<typename Derived>
1417914214
ExprResult
1418014215
TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) {

clang/lib/Serialization/ASTReaderStmt.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,12 @@ void ASTStmtReader::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *E) {
18461846
E->RParenLoc = readSourceLocation();
18471847
}
18481848

1849+
void ASTStmtReader::VisitBoundPointerToMemberFunctionToFunctionPointerCastExpr(
1850+
BoundPointerToMemberFunctionToFunctionPointerCastExpr *E) {
1851+
VisitExplicitCastExpr(E);
1852+
E->BaseExpr = Record.readSubExpr();
1853+
}
1854+
18491855
void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
18501856
VisitCallExpr(E);
18511857
E->UDSuffixLoc = readSourceLocation();
@@ -4150,6 +4156,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
41504156
break;
41514157
}
41524158

4159+
case EXPR_PMF_CAST: {
4160+
#ifndef NDEBUG
4161+
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
4162+
assert(PathSize == 0 && "Wrong PathSize!");
4163+
#endif
4164+
S = new (Context)
4165+
BoundPointerToMemberFunctionToFunctionPointerCastExpr(Empty);
4166+
break;
4167+
}
4168+
41534169
case EXPR_USER_DEFINED_LITERAL: {
41544170
auto NumArgs = Record[ASTStmtReader::NumExprFields];
41554171
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);

0 commit comments

Comments
 (0)