Anastasia created this revision.
Anastasia added a reviewer: rjmccall.
Herald added subscribers: ebevhan, javed.absar.

Extend reference binding behavior to account for address spaces. This change 
also fixes the diagnostic wording (for qualifier mismatch in reference binding) 
and simplifies it by using Qualifiers print method.

This patch is rebased from https://reviews.llvm.org/D58060 that got lost 
somehow.


https://reviews.llvm.org/D62914

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaInit.cpp
  test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
  test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
  test/CXX/expr/expr.post/expr.static.cast/p3-p4-0x.cpp
  test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
  test/Misc/diag-template-diffing.cpp
  test/SemaCXX/builtins-arm.cpp
  test/SemaCXX/err_reference_bind_drops_quals.cpp
  test/SemaCXX/references.cpp
  test/SemaOpenCLCXX/address-space-references.cl

Index: test/SemaOpenCLCXX/address-space-references.cl
===================================================================
--- test/SemaOpenCLCXX/address-space-references.cl
+++ test/SemaOpenCLCXX/address-space-references.cl
@@ -3,3 +3,13 @@
 __global const int& f(__global float &ref) {
   return ref; // expected-error{{reference of type 'const __global int &' cannot bind to a temporary object because of address space mismatch}}
 }
+
+int bar(const __global unsigned int &i); // expected-note{{passing argument to parameter 'i' here}}
+//FIXME: With the overload below the call should be resolved
+// successfully. However, current overload resolution logic
+// can't detect this case and therefore fails.
+int bar(const unsigned int &i);
+
+void foo() {
+  bar(1) // expected-error{{binding reference of type 'const __global unsigned int' to value of type 'int' changes address space}}
+}
Index: test/SemaCXX/references.cpp
===================================================================
--- test/SemaCXX/references.cpp
+++ test/SemaCXX/references.cpp
@@ -55,13 +55,13 @@
 void test5() {
   //  const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
   const volatile int cvi = 1;
-  const int& r = cvi; // expected-error{{binding value of type 'const volatile int' to reference to type 'const int' drops 'volatile' qualifier}}
+  const int& r = cvi; // expected-error{{binding reference of type 'const int' to value of type 'const volatile int' drops 'volatile' qualifier}}
 
 #if __cplusplus >= 201103L
-  const int& r2{cvi}; // expected-error{{binding value of type 'const volatile int' to reference to type 'const int' drops 'volatile' qualifier}}
+  const int& r2{cvi}; // expected-error{{binding reference of type 'const int' to value of type 'const volatile int' drops 'volatile' qualifier}}
 
   const int a = 2;
-  int& r3{a}; // expected-error{{binding value of type 'const int' to reference to type 'int' drops 'const'}}
+  int& r3{a}; // expected-error{{binding reference of type 'int' to value of type 'const int' drops 'const' qualifier}}
 
   const int&& r4{a}; // expected-error{{rvalue reference to type 'const int' cannot bind to lvalue of type 'const int'}}
 
Index: test/SemaCXX/err_reference_bind_drops_quals.cpp
===================================================================
--- test/SemaCXX/err_reference_bind_drops_quals.cpp
+++ test/SemaCXX/err_reference_bind_drops_quals.cpp
@@ -6,31 +6,31 @@
            volatile ptr vp, const volatile ptr cvp, restrict volatile ptr rvp,
            const restrict volatile ptr crvp) {
   ptr& p1 = p;
-  ptr& p2 = cp; // expected-error {{drops 'const' qualifier}}
-  ptr& p3 = rp; // expected-error {{drops 'restrict' qualifier}}
-  ptr& p4 = crp; // expected-error {{drops 'const' and 'restrict' qualifiers}}
-  ptr& p5 = vp; // expected-error {{drops 'volatile' qualifier}}
-  ptr& p6 = cvp; // expected-error {{drops 'const' and 'volatile' qualifiers}}
-  ptr& p7 = rvp; // expected-error {{drops 'restrict' and 'volatile' qualifiers}}
-  ptr& p8 = crvp; // expected-error {{drops 'const', 'restrict', and 'volatile' qualifiers}}
+  ptr& p2 = cp;   // expected-error {{drops 'const' qualifier}}
+  ptr& p3 = rp;   // expected-error {{drops '__restrict' qualifier}}
+  ptr& p4 = crp;  // expected-error {{drops 'const __restrict' qualifiers}}
+  ptr& p5 = vp;   // expected-error {{drops 'volatile' qualifier}}
+  ptr& p6 = cvp;  // expected-error {{drops 'const volatile' qualifiers}}
+  ptr& p7 = rvp;  // expected-error {{drops 'volatile __restrict' qualifiers}}
+  ptr& p8 = crvp; // expected-error {{drops 'const volatile __restrict' qualifiers}}
 
   const ptr& cp1 = p;
   const ptr& cp2 = cp;
-  const ptr& cp3 = rp; // expected-error {{drops 'restrict' qualifier}}
-  const ptr& cp4 = crp; // expected-error {{drops 'restrict' qualifier}}
-  const ptr& cp5 = vp; // expected-error {{drops 'volatile' qualifier}}
-  const ptr& cp6 = cvp; // expected-error {{drops 'volatile' qualifier}}
-  const ptr& cp7 = rvp; // expected-error {{drops 'restrict' and 'volatile' qualifiers}}
-  const ptr& cp8 = crvp; // expected-error {{drops 'restrict' and 'volatile' qualifiers}}
+  const ptr& cp3 = rp;   // expected-error {{drops '__restrict' qualifier}}
+  const ptr& cp4 = crp;  // expected-error {{drops '__restrict' qualifier}}
+  const ptr& cp5 = vp;   // expected-error {{drops 'volatile' qualifier}}
+  const ptr& cp6 = cvp;  // expected-error {{drops 'volatile' qualifier}}
+  const ptr& cp7 = rvp;  // expected-error {{drops 'volatile __restrict' qualifiers}}
+  const ptr& cp8 = crvp; // expected-error {{drops 'volatile __restrict' qualifiers}}
 
   const volatile ptr& cvp1 = p;
   const volatile ptr& cvp2 = cp;
-  const volatile ptr& cvp3 = rp; // expected-error {{drops 'restrict' qualifier}}
-  const volatile ptr& cvp4 = crp; // expected-error {{drops 'restrict' qualifier}}
+  const volatile ptr& cvp3 = rp;  // expected-error {{drops '__restrict' qualifier}}
+  const volatile ptr& cvp4 = crp; // expected-error {{drops '__restrict' qualifier}}
   const volatile ptr& cvp5 = vp;
   const volatile ptr& cvp6 = cvp;
-  const volatile ptr& cvp7 = rvp; // expected-error {{drops 'restrict' qualifier}}
-  const volatile ptr& cvp8 = crvp; // expected-error {{drops 'restrict' qualifier}}
+  const volatile ptr& cvp7 = rvp;  // expected-error {{drops '__restrict' qualifier}}
+  const volatile ptr& cvp8 = crvp; // expected-error {{drops '__restrict' qualifier}}
 
   const restrict volatile ptr& crvp1 = p;
   const restrict volatile ptr& crvp2 = cp;
Index: test/SemaCXX/builtins-arm.cpp
===================================================================
--- test/SemaCXX/builtins-arm.cpp
+++ test/SemaCXX/builtins-arm.cpp
@@ -2,5 +2,5 @@
 
 // va_list on ARM AAPCS is struct { void* __ap }.
 int test1(const __builtin_va_list &ap) {
-  return __builtin_va_arg(ap, int); // expected-error {{binding value of type 'const __builtin_va_list' to reference to type '__builtin_va_list' drops 'const' qualifier}}
+  return __builtin_va_arg(ap, int); // expected-error {{binding reference of type '__builtin_va_list' to value of type 'const __builtin_va_list' drops 'const' qualifier}}
 }
Index: test/Misc/diag-template-diffing.cpp
===================================================================
--- test/Misc/diag-template-diffing.cpp
+++ test/Misc/diag-template-diffing.cpp
@@ -1252,7 +1252,7 @@
 void foo(const T &t) {
   T &t2 = t;
 }
-// CHECK-ELIDE-NOTREE: binding value of type 'const condition<...>' to reference to type 'condition<...>' drops 'const' qualifier
+// CHECK-ELIDE-NOTREE: binding reference of type 'condition<...>' to value of type 'const condition<...>' drops 'const' qualifier
 }
 
 namespace BoolArgumentBitExtended {
Index: test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
===================================================================
--- test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
+++ test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
@@ -21,20 +21,20 @@
     }();
   }();
 
-  int a; 
-  [=]{ 
-    [&] { 
-      int &x = a;  // expected-error{{binding value of type 'const int' to reference to type 'int' drops 'const' qualifier}}
-      int &x2 = a;  // expected-error{{binding value of type 'const int' to reference to type 'int' drops 'const' qualifier}}
-    }(); 
-  }(); 
+  int a;
+  [=] {
+    [&] {
+      int &x = a;  // expected-error{{binding reference of type 'int' to value of type 'const int' drops 'const' qualifier}}
+      int &x2 = a; // expected-error{{binding reference of type 'int' to value of type 'const int' drops 'const' qualifier}}
+    }();
+  }();
 
-  [=]{ 
-    [&a] { 
-      [&] { 
-        int &x = a;  // expected-error{{binding value of type 'const int' to reference to type 'int' drops 'const' qualifier}}
-        int &x2 = a;  // expected-error{{binding value of type 'const int' to reference to type 'int' drops 'const' qualifier}}
+  [=] {
+    [&a] {
+      [&] {
+        int &x = a;  // expected-error{{binding reference of type 'int' to value of type 'const int' drops 'const' qualifier}}
+        int &x2 = a; // expected-error{{binding reference of type 'int' to value of type 'const int' drops 'const' qualifier}}
       }();
-    }(); 
-  }(); 
+    }();
+  }();
 }
Index: test/CXX/expr/expr.post/expr.static.cast/p3-p4-0x.cpp
===================================================================
--- test/CXX/expr/expr.post/expr.static.cast/p3-p4-0x.cpp
+++ test/CXX/expr/expr.post/expr.static.cast/p3-p4-0x.cpp
@@ -28,8 +28,8 @@
   A &&ar6 = static_cast<A&&>(xvalue<D>());
   A &&ar7 = static_cast<A&&>(prvalue<D>());
 
-  A &&ar8 = static_cast<A&&>(prvalue<const A>()); // expected-error {{binding value of type 'const A' to reference to type 'A' drops 'const' qualifier}}
-  A &&ar9 = static_cast<A&&>(lvalue<const A>()); // expected-error {{cannot cast from lvalue of type 'const A'}}
+  A &&ar8 = static_cast<A&&>(prvalue<const A>()); // expected-error {{binding reference of type 'A' to value of type 'const A' drops 'const' qualifier}}
+  A &&ar9 = static_cast<A&&>(lvalue<const A>());  // expected-error {{cannot cast from lvalue of type 'const A'}}
   A &&ar10 = static_cast<A&&>(xvalue<const A>()); // expected-error {{cannot cast from rvalue of type 'const A'}}
 
   const A &&ar11 = static_cast<const A&&>(prvalue<A>());
@@ -39,5 +39,5 @@
   const A &&ar15 = static_cast<const A&&>(prvalue<C>());
   const A &&ar16 = static_cast<const A&&>(lvalue<D>());
 
-  const A &&ar17 = static_cast<const A&&>(prvalue<A const volatile>()); // expected-error {{binding value of type 'const volatile A' to reference to type 'const A' drops 'volatile' qualifier}}
+  const A &&ar17 = static_cast<const A&&>(prvalue<A const volatile>()); // expected-error {{binding reference of type 'const A' to value of type 'const volatile A' drops 'volatile' qualifier}}
 }
Index: test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
===================================================================
--- test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
+++ test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
@@ -69,10 +69,10 @@
                        volatile const int ivc) {
   volatile Base &bvr1 = b;
   volatile Base &bvr2 = d;
-  volatile Base &bvr3 = bvc; // expected-error{{binding value of type 'const volatile Base' to reference to type 'volatile Base' drops 'const' qualifier}}
-  volatile Base &bvr4 = dvc; // expected-error{{binding value of type 'const volatile Derived' to reference to type 'volatile Base' drops 'const' qualifier}}
-  
-  volatile int &ir = ivc; // expected-error{{binding value of type 'const volatile int' to reference to type 'volatile int' drops 'const' qualifier}}
+  volatile Base &bvr3 = bvc; // expected-error{{binding reference of type 'volatile Base' to value of type 'const volatile Base' drops 'const' qualifier}}
+  volatile Base &bvr4 = dvc; // expected-error{{binding reference of type 'volatile Base' to value of type 'const volatile Derived' drops 'const' qualifier}}
+
+  volatile int &ir = ivc; // expected-error{{binding reference of type 'volatile int' to value of type 'const volatile int' drops 'const' qualifier}}
 
   const volatile Base &bcvr1 = b;
   const volatile Base &bcvr2 = d;
@@ -123,8 +123,8 @@
   const Base &br3 = create<const Base>();
   const Base &br4 = create<const Derived>();
 
-  const Base &br5 = create<const volatile Base>(); // expected-error{{binding value of type 'const volatile Base' to reference to type 'const Base' drops 'volatile' qualifier}}
-  const Base &br6 = create<const volatile Derived>(); // expected-error{{binding value of type 'const volatile Derived' to reference to type 'const Base' drops 'volatile' qualifier}}
+  const Base &br5 = create<const volatile Base>();    // expected-error{{binding reference of type 'const Base' to value of type 'const volatile Base' drops 'volatile' qualifier}}
+  const Base &br6 = create<const volatile Derived>(); // expected-error{{binding reference of type 'const Base' to value of type 'const volatile Derived' drops 'volatile' qualifier}}
 
   const int &ir = create<int>();
 }
Index: test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
===================================================================
--- test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
+++ test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
@@ -122,8 +122,8 @@
 
   const double& rcd2 = 2;
   double&& rrd = 2;
-  const volatile int cvi = 1; 
-  const int& r2 = cvi; // expected-error{{binding value of type 'const volatile int' to reference to type 'const int' drops 'volatile' qualifier}}
+  const volatile int cvi = 1;
+  const int& r2 = cvi; // expected-error{{binding reference of type 'const int' to value of type 'const volatile int' drops 'volatile' qualifier}}
 
   double d;
   double&& rrd2 = d; // expected-error{{rvalue reference to type 'double' cannot bind to lvalue of type 'double'}}
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -4640,7 +4640,10 @@
   //     - Otherwise, the reference shall be an lvalue reference to a
   //       non-volatile const type (i.e., cv1 shall be const), or the reference
   //       shall be an rvalue reference.
-  if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile())) {
+  //       For address spaces, we interpret this to mean that an addr space
+  //       of a reference "cv1 T1" is a superset of addr space of "cv2 T2".
+  if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile() &&
+                       T1Quals.isAddressSpaceSupersetOf(T2Quals))) {
     if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy)
       Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
     else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
@@ -4649,7 +4652,10 @@
                                   ConvOvlResult);
     else if (!InitCategory.isLValue())
       Sequence.SetFailed(
-          InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
+          T1Quals.isAddressSpaceSupersetOf(T2Quals)
+              ? InitializationSequence::
+                    FK_NonConstLValueReferenceBindingToTemporary
+              : InitializationSequence::FK_ReferenceInitDropsQualifiers);
     else {
       InitializationSequence::FailureKind FK;
       switch (RefRelationship) {
@@ -8535,11 +8541,16 @@
     Qualifiers DroppedQualifiers =
         SourceType.getQualifiers() - NonRefType.getQualifiers();
 
-    S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
-      << SourceType
-      << NonRefType
-      << DroppedQualifiers.getCVRQualifiers()
-      << Args[0]->getSourceRange();
+    if (!NonRefType.getQualifiers().isAddressSpaceSupersetOf(
+            SourceType.getQualifiers()))
+      S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
+          << NonRefType << SourceType << 1 /*addr space*/
+          << Args[0]->getSourceRange();
+    else
+      S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
+          << NonRefType << SourceType << 0 /*cv quals*/
+          << Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
+          << DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange();
     break;
   }
 
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1849,10 +1849,8 @@
   "%diff{to type $ cannot bind to a value of unrelated type $|"
   "cannot bind to a value of unrelated type}1,2">;
 def err_reference_bind_drops_quals : Error<
-  "binding value %diff{of type $ to reference to type $|to reference}0,1 "
-  "drops %select{<<ERROR>>|'const'|'restrict'|'const' and 'restrict'|"
-  "'volatile'|'const' and 'volatile'|'restrict' and 'volatile'|"
-  "'const', 'restrict', and 'volatile'}2 qualifier%plural{1:|2:|4:|:s}2">;
+  "binding reference %diff{of type $ to value of type $|to value}0,1 "
+  "%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address space}2">;
 def err_reference_bind_failed : Error<
   "reference %diff{to %select{type|incomplete type}1 $ could not bind to an "
   "%select{rvalue|lvalue}2 of type $|could not bind to %select{rvalue|lvalue}2 of "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to