]> granicus.if.org Git - clang/commitdiff
When calling a bound pointer to member function, check the
authorDouglas Gregor <dgregor@apple.com>
Fri, 4 Feb 2011 12:57:49 +0000 (12:57 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 4 Feb 2011 12:57:49 +0000 (12:57 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/CXX/expr/expr.mptr.oper/p5.cpp [new file with mode: 0644]

index b5e1b81bf8634387580f68b1251cbf636fe42a26..df4c39e4ce78a9d749e429ea0e937b86860f5186 100644 (file)
@@ -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">;
index 01fc1c4e6f5efb73fa7ae50f01579271b6a89a7e..0d4950fd16caa0cb0054326d0b25fa90560a0c45 100644 (file)
@@ -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<PointerType>()
+                                            ->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 (file)
index 0000000..7380b5d
--- /dev/null
@@ -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)();
+}