]> granicus.if.org Git - clang/commitdiff
[Sema] Improve diagnostics for const- and ref-qualified member functions
authorJacob Bandes-Storch <jacob@bandes-stor.ch>
Sun, 31 Dec 2017 18:27:29 +0000 (18:27 +0000)
committerJacob Bandes-Storch <jacob@bandes-stor.ch>
Sun, 31 Dec 2017 18:27:29 +0000 (18:27 +0000)
(Re-submission of D39937 with fixed tests.)

Adjust wording for const-qualification mismatch to be a little more clear.

Also add another diagnostic for a ref qualifier mismatch, which previously produced a useless error (this error path is simply very old; see rL119336):

Before:
  error: cannot initialize object parameter of type 'X0' with an expression of type 'X0'

After:
  error: 'this' argument to member function 'rvalue' is an lvalue, but function has rvalue ref-qualifier

Reviewers: aaron.ballman

Reviewed By: aaron.ballman

Subscribers: lebedev.ri, cfe-commits

Differential Revision: https://reviews.llvm.org/D41646

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@321609 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaOverload.cpp
test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
test/SemaCXX/copy-initialization.cpp
test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp
test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp

index 01e819942f686fcfcff3de882234280fc91f169d..e4649d3a44daf7673cfa761e1ed34816705e7808 100644 (file)
@@ -1589,12 +1589,20 @@ def err_non_virtual_pure : Error<
 def ext_pure_function_definition : ExtWarn<
   "function definition with pure-specifier is a Microsoft extension">,
   InGroup<MicrosoftPureDefinition>;
-def err_implicit_object_parameter_init : Error<
-  "cannot initialize object parameter of type %0 with an expression "
-  "of type %1">;
 def err_qualified_member_of_unrelated : Error<
   "%q0 is not a member of class %1">;
 
+def err_member_function_call_bad_cvr : Error<
+  "'this' argument to member function %0 has type %1, but function is not marked "
+  "%select{const|restrict|const or restrict|volatile|const or volatile|"
+  "volatile or restrict|const, volatile, or restrict}2">;
+def err_member_function_call_bad_ref : Error<
+  "'this' argument to member function %0 is an %select{lvalue|rvalue}1, "
+  "but function has %select{non-const lvalue|rvalue}2 ref-qualifier">;
+def err_member_function_call_bad_type : Error<
+  "cannot initialize object parameter of type %0 with an expression "
+  "of type %1">;
+
 def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning<
   "call to pure virtual member function %0 has undefined behavior; "
   "overrides of %0 in subclasses are not available in the "
@@ -1815,10 +1823,6 @@ def warn_temporary_array_to_pointer_decay : Warning<
 def err_init_list_bad_dest_type : Error<
   "%select{|non-aggregate }0type %1 cannot be initialized with an initializer "
   "list">;
-def err_member_function_call_bad_cvr : Error<"member function %0 not viable: "
-    "'this' argument has type %1, but function is not marked "
-    "%select{const|restrict|const or restrict|volatile|const or volatile|"
-    "volatile or restrict|const, volatile, or restrict}2">;
 
 def err_reference_bind_to_bitfield : Error<
   "%select{non-const|volatile}0 reference cannot bind to "
index 2144845f4dd367464d779c21b84563526b423ce1..07d931552f35bef041f6e32c18a5739be6c5019e 100644 (file)
@@ -5145,7 +5145,8 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
       *this, From->getLocStart(), From->getType(), FromClassification, Method,
       Method->getParent());
   if (ICS.isBad()) {
-    if (ICS.Bad.Kind == BadConversionSequence::bad_qualifiers) {
+    switch (ICS.Bad.Kind) {
+    case BadConversionSequence::bad_qualifiers: {
       Qualifiers FromQs = FromRecordType.getQualifiers();
       Qualifiers ToQs = DestType.getQualifiers();
       unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
@@ -5158,10 +5159,28 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
           << Method->getDeclName();
         return ExprError();
       }
+      break;
+    }
+
+    case BadConversionSequence::lvalue_ref_to_rvalue:
+    case BadConversionSequence::rvalue_ref_to_lvalue: {
+      bool IsRValueQualified =
+        Method->getRefQualifier() == RefQualifierKind::RQ_RValue;
+      Diag(From->getLocStart(), diag::err_member_function_call_bad_ref)
+        << Method->getDeclName() << FromClassification.isRValue()
+        << IsRValueQualified;
+      Diag(Method->getLocation(), diag::note_previous_decl)
+        << Method->getDeclName();
+      return ExprError();
+    }
+
+    case BadConversionSequence::no_conversion:
+    case BadConversionSequence::unrelated_class:
+      break;
     }
 
     return Diag(From->getLocStart(),
-                diag::err_implicit_object_parameter_init)
+                diag::err_member_function_call_bad_type)
        << ImplicitParamRecordType << FromRecordType << From->getSourceRange();
   }
 
index 68c79900b95124d25c7143614b83d03e898b3461..df7762703c0fede6970956cb0f3767ed7b287969 100644 (file)
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 template<typename T> T &lvalue();
 template<typename T> T &&xvalue();
@@ -20,6 +19,18 @@ struct X0 {
 
   void g();
 
+  void c() const; // expected-note {{'c' declared here}}
+  void v() volatile; // expected-note {{'v' declared here}}
+  void r() __restrict__; // expected-note {{'r' declared here}}
+  void cr() const __restrict__; // expected-note {{'cr' declared here}}
+  void cv() const volatile;
+  void vr() volatile __restrict__; // expected-note {{'vr' declared here}}
+  void cvr() const volatile __restrict__;
+
+  void lvalue() &; // expected-note 2 {{'lvalue' declared here}}
+  void const_lvalue() const&;
+  void rvalue() &&; // expected-note {{'rvalue' declared here}}
+
   int &operator+(const X0&) &;
   float &operator+(const X0&) &&;
 
@@ -32,7 +43,7 @@ struct X0 {
   float &h2() const&&;
 };
 
-void X0::g() {
+void X0::g() { // expected-note {{'g' declared here}}
   int &ir1 = f();
   int &ir2 = X0::f();
 }
@@ -69,3 +80,26 @@ void test_ref_qualifier_overloading() {
   float &fr3 = xvalue<X0>().h2();
   float &fr4 = prvalue<X0>().h2();
 }
+
+void test_diagnostics(const volatile X0 &__restrict__ cvr) {
+  cvr.g(); // expected-error {{'this' argument to member function 'g' has type 'const volatile X0', but function is not marked const or volatile}}
+  cvr.c(); // expected-error {{not marked volatile}}
+  cvr.v(); // expected-error {{not marked const}}
+  cvr.r(); // expected-error {{not marked const or volatile}}
+  cvr.cr(); // expected-error {{not marked volatile}}
+  cvr.cv();
+  cvr.vr(); // expected-error {{not marked const}}
+  cvr.cvr();
+
+  lvalue<X0>().lvalue();
+  lvalue<X0>().const_lvalue();
+  lvalue<X0>().rvalue(); // expected-error {{'this' argument to member function 'rvalue' is an lvalue, but function has rvalue ref-qualifier}}
+
+  xvalue<X0>().lvalue(); // expected-error {{'this' argument to member function 'lvalue' is an rvalue, but function has non-const lvalue ref-qualifier}}
+  xvalue<X0>().const_lvalue();
+  xvalue<X0>().rvalue();
+
+  prvalue<X0>().lvalue(); // expected-error {{'this' argument to member function 'lvalue' is an rvalue, but function has non-const lvalue ref-qualifier}}
+  prvalue<X0>().const_lvalue();
+  prvalue<X0>().rvalue();
+}
index ad6086835876cbb49a8d5f88a5ea6d2eca3878db..34202494c0d8024df98012da212889ea9aa2327e 100644 (file)
@@ -215,7 +215,7 @@ template void h<A(&)[13], int>(A(&)[13]); // expected-note {{requested here}}
 template<typename T>
 void i(T t) {
   for (auto u : t) { // expected-error {{invalid range expression of type 'X::A *'; no viable 'begin' function available}} \
-                        expected-error {{member function 'begin' not viable}} \
+                        expected-error {{'this' argument to member function 'begin' has type 'const X::A', but function is not marked const}} \
                         expected-note {{when looking up 'begin' function}}
 
   }
index 4f6c65cf550c80c32b4212245544aa17e8a5a820..cd7e5f07e140d02aef2d7d69399a76cf2a5590ef 100644 (file)
@@ -26,7 +26,7 @@ struct foo {
 };
 
 // PR3600
-void test(const foo *P) { P->bar(); } // expected-error{{'bar' not viable: 'this' argument has type 'const foo', but function is not marked const}}
+void test(const foo *P) { P->bar(); } // expected-error{{'this' argument to member function 'bar' has type 'const foo', but function is not marked const}}
 
 namespace PR6757 {
   struct Foo {
index c7e6074a44374357ef3aa898663704a7cbae94ec..7cb83c6f887633e83d38d2f6d7d3c7f5d9546dfb 100644 (file)
@@ -96,8 +96,8 @@ namespace extended_examples {
 //expected-error@81 {{statement requires expression of integer type ('extended_examples::A1' invalid)}}
 //expected-error@85 {{statement requires expression of integer type ('extended_examples::B2' invalid)}}
 #else
-//expected-error@81 {{cannot initialize object parameter of type 'extended_examples::A1' with an expression of type 'extended_examples::A1'}}
-//expected-error@85 {{cannot initialize object parameter of type 'extended_examples::B2' with an expression of type 'extended_examples::B2'}}
+//expected-error@81 {{'this' argument to member function 'operator int' is an lvalue, but function has rvalue ref-qualifier}} expected-note@54 {{'operator int' declared here}}
+//expected-error@85 {{'this' argument to member function 'operator int' is an lvalue, but function has rvalue ref-qualifier}} expected-note@75 {{'operator int' declared here}}
 #endif
 
 namespace extended_examples_cxx1y {
@@ -149,9 +149,9 @@ namespace extended_examples_cxx1y {
 #ifdef CXX1Y
 //expected-error@139 {{statement requires expression of integer type ('extended_examples_cxx1y::A2' invalid)}}
 #else
-//expected-error@138 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A1' with an expression of type 'extended_examples_cxx1y::A1'}}
-//expected-error@139 {{cannot initialize object parameter of type 'extended_examples_cxx1y::A2' with an expression of type 'extended_examples_cxx1y::A2'}}
-//expected-error@143 {{cannot initialize object parameter of type 'extended_examples_cxx1y::D' with an expression of type 'extended_examples_cxx1y::D'}}
+//expected-error@138 {{'this' argument to member function 'operator int' is an lvalue, but function has rvalue ref-qualifier}} expected-note@106 {{'operator int' declared here}}
+//expected-error@139 {{'this' argument to member function 'operator int' is an lvalue, but function has rvalue ref-qualifier}} expected-note@111 {{'operator int' declared here}}
+//expected-error@143 {{'this' argument to member function 'operator int' is an lvalue, but function has rvalue ref-qualifier}} expected-note@131 {{'operator int' declared here}}
 #endif
 
 namespace extended_examples_array_bounds {
index e9cbb1a18532f2475a7a04ef51bdad8b4446ae05..0bc40c81798384969d6b4b3cc59cdc1c7864f6fc 100644 (file)
@@ -1,12 +1,12 @@
 // RUN: %clang_cc1 -std=c++2a %s -verify
 
 struct X {
-  void ref() & {}
+  void ref() & {} // expected-note{{'ref' declared here}}
   void cref() const& {}
 };
 
 void test() {
-  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}}
+  X{}.ref(); // expected-error{{'this' argument to member function 'ref' is an rvalue, but function has non-const lvalue ref-qualifier}}
   X{}.cref(); // expected-no-error
 
   (X{}.*&X::ref)(); // expected-error-re{{pointer-to-member function type 'void (X::*)() {{.*}}&' can only be called on an lvalue}}