hamzasood created this revision.

This patch provides an implementation for P0704R1 <http://wg21.link/p0704r1>.

I also made it work pre-C++2a as an extension (with a warning) since that's how 
Clang seems to deal with small additions like this. Hopefully someone more 
knowledgable on the matter can clarify whether that's appropriate.


https://reviews.llvm.org/D36584

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExprCXX.cpp
  test/CXX/expr/expr.mptr.oper/p6-0x.cpp
  test/CXX/expr/expr.mptr.oper/p6-2a.cpp
  www/cxx_status.html

Index: www/cxx_status.html
===================================================================
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -777,13 +777,12 @@
 
 <h2 id="cxx20">C++2a implementation status</h2>
 
-<p>Clang does not yet support any of the proposed features of
-<!--<p>Clang has <b>experimental</b> support for some proposed features of-->
+<p>Clang has <b>experimental</b> support for some proposed features of
 the C++ standard following C++17, provisionally named C++2a.
 Note that support for these features may change or be removed without notice,
 as the draft C++2a standard evolves.
 
-<!--<p>You can use Clang in C++2a mode with the <code>-std=c++2a</code> option.</p>-->
+<p>You can use Clang in C++2a mode with the <code>-std=c++2a</code> option.</p>
 
 <details open>
 <summary>List of features and minimum Clang version with support</summary>
@@ -803,7 +802,7 @@
     <tr>
       <td><tt>const&amp;</tt>-qualified pointers to members</td>
       <td><a href="http://wg21.link/p0704r1";>P0704R1</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td>Allow <i>lambda-capture</i> <tt>[=, this]</tt></td>
Index: test/CXX/expr/expr.mptr.oper/p6-2a.cpp
===================================================================
--- test/CXX/expr/expr.mptr.oper/p6-2a.cpp
+++ test/CXX/expr/expr.mptr.oper/p6-2a.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+// expected-no-diagnostics
+
+struct X { void foo() const&; };
+
+void test() {
+  // Example from P0704R1.
+  X{}.foo();
+  (X{}.*&X::foo)();
+}
Index: test/CXX/expr/expr.mptr.oper/p6-0x.cpp
===================================================================
--- test/CXX/expr/expr.mptr.oper/p6-0x.cpp
+++ test/CXX/expr/expr.mptr.oper/p6-0x.cpp
@@ -12,14 +12,20 @@
 // expression whose object expression is an lvalue, the program is
 // ill-formed if the second operand is a pointer to member function
 // with ref-qualifier &&.
-void test(X *xp, int (X::*pmf)(int), int (X::*l_pmf)(int) &, 
-          int (X::*r_pmf)(int) &&) {
+void test(X *xp, int (X::*pmf)(int), int (X::*const_l_pmf)(int) const&,
+          int (X::*l_pmf)(int) &, int (X::*r_pmf)(int) &&) {
   // No ref-qualifier.
   (lvalue<X>().*pmf)(17);
   (xvalue<X>().*pmf)(17);
   (prvalue<X>().*pmf)(17);
   (xp->*pmf)(17);
 
+  // Const Lvalue ref-qualifier.
+  (lvalue<X>().*const_l_pmf)(17);
+  (xvalue<X>().*const_l_pmf)(17); // expected-warning {{C++2a extension}}
+  (prvalue<X>().*const_l_pmf)(17); // expected-warning {{C++2a extension}}
+  (xp->*const_l_pmf)(17);
+
   // Lvalue ref-qualifier.
   (lvalue<X>().*l_pmf)(17);
   (xvalue<X>().*l_pmf)(17); // expected-error-re{{pointer-to-member function type 'int (X::*)(int){{( __attribute__\(\(thiscall\)\))?}} &' can only be called on an lvalue}}
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5162,22 +5162,32 @@
   QualType Result = MemPtr->getPointeeType();
   Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers());
 
-  // C++0x [expr.mptr.oper]p6:
+  // C++2a [expr.mptr.oper]p6:
   //   In a .* expression whose object expression is an rvalue, the program is
-  //   ill-formed if the second operand is a pointer to member function with
-  //   ref-qualifier &. In a ->* expression or in a .* expression whose object
-  //   expression is an lvalue, the program is ill-formed if the second operand
-  //   is a pointer to member function with ref-qualifier &&.
+  //   ill-formed if the second operand is a pointer to member function whose
+  //   ref-qualifier is &, unless its cv-qualifier-seq is const. In an ->*
+  //   expression or in a .* expression whose object expression is an lvalue,
+  //   the program is ill-formed if the second operand is a pointer to member
+  //   function with ref-qualifier &&.
   if (const FunctionProtoType *Proto = Result->getAs<FunctionProtoType>()) {
     switch (Proto->getRefQualifier()) {
     case RQ_None:
       // Do nothing
       break;
 
     case RQ_LValue:
-      if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-        Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-          << RHSType << 1 << LHS.get()->getSourceRange();
+      if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+        if (Proto->isConst() && !Proto->isVolatile())
+          Diag(Loc,
+               !getLangOpts().CPlusPlus2a
+                   ? diag::
+                     ext_const_amp_pointer_to_member_on_rvalue_cxx2a
+                   : diag::
+                     warn_cxx1z_compat_const_amp_pointer_to_member_on_rvalue);
+        else
+          Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+            << RHSType << 1 << LHS.get()->getSourceRange();
+      }
       break;
 
     case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4111,6 +4111,13 @@
 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">;
+def warn_cxx1z_compat_const_amp_pointer_to_member_on_rvalue : Warning<
+  "invocation of a 'const&' qualified pointer-to-member function on an rvalue "
+  "is incompatible with C++ standards before C++2a">,
+  InGroup<CXXPre2aCompat>, DefaultIgnore;
+def ext_const_amp_pointer_to_member_on_rvalue_cxx2a : ExtWarn<
+  "invocation of a 'const&' qualified pointer-to-member function on an rvalue "
+  "is a C++2a extension">, InGroup<CXX2a>;
 def ext_ms_deref_template_argument: ExtWarn<
   "non-type template argument containing a dereference operation is a "
   "Microsoft extension">, InGroup<MicrosoftTemplate>;
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -167,6 +167,9 @@
 def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">;
 def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic",
                                        [CXXPre1zCompat]>;
+def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++1z-compat">;
+def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++1z-compat-pedantic",
+                                       [CXXPre2aCompat]>;
 
 def CXX98CompatBindToTemporaryCopy :
   DiagGroup<"c++98-compat-bind-to-temporary-copy">;
@@ -780,6 +783,10 @@
 // earlier C++ versions.
 def CXX1z : DiagGroup<"c++1z-extensions">;
 
+// A warning group for warnings about using C++2a features as extensions in
+// earlier C++ versions.
+def CXX2a : DiagGroup<"c++2a-extensions">;
+
 def : DiagGroup<"c++0x-extensions", [CXX11]>;
 def : DiagGroup<"c++1y-extensions", [CXX14]>;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to