From: Douglas Gregor Date: Fri, 4 Feb 2011 12:57:49 +0000 (+0000) Subject: When calling a bound pointer to member function, check the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fdc13a00a0077383eabf6d994de10203568415bb;p=clang When calling a bound pointer to member function, check the cv-qualifiers on the object against the cv-qualifiers on the member function. Fixes PR8315. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124865 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b5e1b81bf8..df4c39e4ce 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1585,6 +1585,8 @@ def ext_template_arg_extra_parens : ExtWarn< "address non-type template argument cannot be surrounded by parentheses">; def err_pointer_to_member_type : Error< "invalid use of pointer to member type after %select{.*|->*}0">; +def err_pointer_to_member_call_drops_quals : Error< + "call to pointer to member function of type %0 drops '%1' qualifier%s2">; def err_pointer_to_member_oper_value_classify: Error< "pointer-to-member function type %0 can only be called on an " "%select{rvalue|lvalue}1">; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 01fc1c4e6f..0d4950fd16 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4328,6 +4328,26 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, QualType ResultTy = FPT->getCallResultType(Context); ExprValueKind VK = Expr::getValueKindForType(FPT->getResultType()); + // Check that the object type isn't more qualified than the + // member function we're calling. + Qualifiers FuncQuals = Qualifiers::fromCVRMask(FPT->getTypeQuals()); + Qualifiers ObjectQuals + = BO->getOpcode() == BO_PtrMemD + ? BO->getLHS()->getType().getQualifiers() + : BO->getLHS()->getType()->getAs() + ->getPointeeType().getQualifiers(); + + Qualifiers Difference = ObjectQuals - FuncQuals; + Difference.removeObjCGCAttr(); + Difference.removeAddressSpace(); + if (Difference) { + std::string QualsString = Difference.getAsString(); + Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals) + << BO->getType().getUnqualifiedType() + << QualsString + << (QualsString.find(' ') == std::string::npos? 1 : 2); + } + CXXMemberCallExpr *TheCall = new (Context) CXXMemberCallExpr(Context, Fn, Args, NumArgs, ResultTy, VK, diff --git a/test/CXX/expr/expr.mptr.oper/p5.cpp b/test/CXX/expr/expr.mptr.oper/p5.cpp new file mode 100644 index 0000000000..7380b5d480 --- /dev/null +++ b/test/CXX/expr/expr.mptr.oper/p5.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct X0 { + void f0(); + void f1() const; + void f2() volatile; + void f3() const volatile; +}; + +void test_object_cvquals(void (X0::*pm)(), + void (X0::*pmc)() const, + void (X0::*pmv)() volatile, + void (X0::*pmcv)() const volatile, + X0 *p, + const X0 *pc, + volatile X0 *pv, + const volatile X0 *pcv, + X0 &o, + const X0 &oc, + volatile X0 &ov, + const volatile X0 &ocv) { + (p->*pm)(); + (p->*pmc)(); + (p->*pmv)(); + (p->*pmcv)(); + + (pc->*pm)(); // expected-error{{call to pointer to member function of type 'void ()' drops 'const' qualifier}} + (pc->*pmc)(); + (pc->*pmv)(); // expected-error{{call to pointer to member function of type 'void () volatile' drops 'const' qualifier}} + (pc->*pmcv)(); + + (pv->*pm)(); // expected-error{{call to pointer to member function of type 'void ()' drops 'volatile' qualifier}} + (pv->*pmc)(); // expected-error{{call to pointer to member function of type 'void () const' drops 'volatile' qualifier}} + (pv->*pmv)(); + (pv->*pmcv)(); + + (pcv->*pm)(); // expected-error{{call to pointer to member function of type 'void ()' drops 'const volatile' qualifiers}} + (pcv->*pmc)(); // expected-error{{call to pointer to member function of type 'void () const' drops 'volatile' qualifier}} + (pcv->*pmv)(); // expected-error{{call to pointer to member function of type 'void () volatile' drops 'const' qualifier}} + (pcv->*pmcv)(); + + (o.*pm)(); + (o.*pmc)(); + (o.*pmv)(); + (o.*pmcv)(); + + (oc.*pm)(); // expected-error{{call to pointer to member function of type 'void ()' drops 'const' qualifier}} + (oc.*pmc)(); + (oc.*pmv)(); // expected-error{{call to pointer to member function of type 'void () volatile' drops 'const' qualifier}} + (oc.*pmcv)(); + + (ov.*pm)(); // expected-error{{call to pointer to member function of type 'void ()' drops 'volatile' qualifier}} + (ov.*pmc)(); // expected-error{{call to pointer to member function of type 'void () const' drops 'volatile' qualifier}} + (ov.*pmv)(); + (ov.*pmcv)(); + + (ocv.*pm)(); // expected-error{{call to pointer to member function of type 'void ()' drops 'const volatile' qualifiers}} + (ocv.*pmc)(); // expected-error{{call to pointer to member function of type 'void () const' drops 'volatile' qualifier}} + (ocv.*pmv)(); // expected-error{{call to pointer to member function of type 'void () volatile' drops 'const' qualifier}} + (ocv.*pmcv)(); +}