From 908200b4754e1544a13c602c412e66ce32d74635 Mon Sep 17 00:00:00 2001 From: Argiris Kirtzidis Date: Mon, 1 Nov 2010 18:49:26 +0000 Subject: [PATCH] Emit error when using a bound member function for something other than calling it. Also avoids IRGen crashes due to accepting invalid code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117943 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 3 +++ include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ lib/AST/Expr.cpp | 6 ++++++ lib/Sema/SemaCXXCast.cpp | 9 +++++++++ lib/Sema/SemaExpr.cpp | 4 ++++ lib/Sema/SemaStmt.cpp | 6 ++++++ test/SemaCXX/ptrtomember.cpp | 14 ++++++++++++++ 7 files changed, 44 insertions(+) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index ba4a38029..3ba0667ef 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -396,6 +396,9 @@ public: /// write barrier. bool isOBJCGCCandidate(ASTContext &Ctx) const; + /// \brief Returns true if this expression is a bound member function. + bool isBoundMemberFunction(ASTContext &Ctx) const; + /// \brief Result type of CanThrow(). enum CanThrowResult { CT_Cannot, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 88e3126f2..2972e9b16 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2641,6 +2641,8 @@ def err_not_tag_in_scope : Error< def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; +def err_invalid_use_of_bound_member_func : Error< + "a bound member function may only be used to call it">; def err_incomplete_object_call : Error< "incomplete type in call to object of type %0">; def err_incomplete_pointer_to_member_return : Error< diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 682955773..078bd7c8a 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1324,6 +1324,12 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { } } +bool Expr::isBoundMemberFunction(ASTContext &Ctx) const { + if (isTypeDependent()) + return false; + return isLvalue(Ctx) == Expr::LV_MemberFunction; +} + static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1, Expr::CanThrowResult CT2) { // CanThrowResult constants are ordered so that the maximum is the correct diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 7b1e34a7c..fc9ef73a5 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -146,6 +146,10 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, // FIXME: should we check this in a more fine-grained manner? bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent(); + if (Ex->isBoundMemberFunction(Context)) + Diag(Ex->getLocStart(), diag::err_invalid_use_of_bound_member_func) + << Ex->getSourceRange(); + switch (Kind) { default: assert(0 && "Unknown C++ cast!"); @@ -1273,6 +1277,11 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, CastKind &Kind, CXXCastPath &BasePath, bool FunctionalStyle) { + if (CastExpr->isBoundMemberFunction(Context)) + return Diag(CastExpr->getLocStart(), + diag::err_invalid_use_of_bound_member_func) + << CastExpr->getSourceRange(); + // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6f6d3714e..9e28172c9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8206,6 +8206,10 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { DiagnoseAssignmentAsCondition(E); if (!E->isTypeDependent()) { + if (E->isBoundMemberFunction(Context)) + return Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) + << E->getSourceRange(); + DefaultFunctionArrayLvalueConversion(E); QualType T = E->getType(); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index ddee9cca6..4c586e5e0 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -74,6 +74,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (!E) return; + if (E->isBoundMemberFunction(Context)) { + Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) + << E->getSourceRange(); + return; + } + SourceLocation Loc; SourceRange R1, R2; if (!E->isUnusedResultAWarning(Loc, R1, R2, Context)) diff --git a/test/SemaCXX/ptrtomember.cpp b/test/SemaCXX/ptrtomember.cpp index e84e931ee..f26f13f19 100644 --- a/test/SemaCXX/ptrtomember.cpp +++ b/test/SemaCXX/ptrtomember.cpp @@ -16,3 +16,17 @@ struct S2 { }; int S2::*pf = &S2::bitfield; // expected-error {{address of bit-field requested}} + +struct S3 { + void m(); +}; + +void f3(S3* p, void (S3::*m)()) { + p->*m; // expected-error {{a bound member function may only be used to call it}} + (void)(p->*m); // expected-error {{a bound member function may only be used to call it}} + (void)(void*)(p->*m); // expected-error {{a bound member function may only be used to call it}} + (void)reinterpret_cast(p->*m); // expected-error {{a bound member function may only be used to call it}} + if (p->*m) {} // expected-error {{a bound member function may only be used to call it}} + + p->m; // expected-error {{a bound member function may only be used to call it}} +} -- 2.11.4.GIT