[Sema] Prevent binding incompatible addr space ref to temporaries
References to arbitrary address spaces can't always be bound to
temporaries. This change extends the reference binding logic to
check that the address space of a temporary can be implicitly
converted to the address space in a reference when temporary
materialization is performed.
Differential Revision: https://reviews.llvm.org/D61318
llvm-svn: 362604
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 3f71a7e..00a2b76 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -460,21 +460,25 @@
Mask |= qs.Mask;
}
- /// Returns true if this address space is a superset of the other one.
+ /// Returns true if address space A is equal to or a superset of B.
/// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of
/// overlapping address spaces.
/// CL1.1 or CL1.2:
/// every address space is a superset of itself.
/// CL2.0 adds:
/// __generic is a superset of any address space except for __constant.
+ static bool isAddressSpaceSupersetOf(LangAS A, LangAS B) {
+ // Address spaces must match exactly.
+ return A == B ||
+ // Otherwise in OpenCLC v2.0 s6.5.5: every address space except
+ // for __constant can be used as __generic.
+ (A == LangAS::opencl_generic && B != LangAS::opencl_constant);
+ }
+
+ /// Returns true if the address space in these qualifiers is equal to or
+ /// a superset of the address space in the argument qualifiers.
bool isAddressSpaceSupersetOf(Qualifiers other) const {
- return
- // Address spaces must match exactly.
- getAddressSpace() == other.getAddressSpace() ||
- // Otherwise in OpenCLC v2.0 s6.5.5: every address space except
- // for __constant can be used as __generic.
- (getAddressSpace() == LangAS::opencl_generic &&
- other.getAddressSpace() != LangAS::opencl_constant);
+ return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace());
}
/// Determines if these qualifiers compatibly include another set.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 761bd22..d34720c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1857,6 +1857,9 @@
"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 "
"incompatible type}0,3">;
+def err_reference_bind_temporary_addrspace : Error<
+ "reference of type %0 cannot bind to a temporary object because of "
+ "address space mismatch">;
def err_reference_bind_init_list : Error<
"reference to type %0 cannot bind to an initializer list">;
def err_init_list_bad_dest_type : Error<
diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h
index 14d8aa8..1c522e4 100644
--- a/clang/include/clang/Sema/Initialization.h
+++ b/clang/include/clang/Sema/Initialization.h
@@ -1012,6 +1012,9 @@
/// Reference binding drops qualifiers.
FK_ReferenceInitDropsQualifiers,
+ /// Reference with mismatching address space binding to temporary.
+ FK_ReferenceAddrspaceMismatchTemporary,
+
/// Reference binding failed.
FK_ReferenceInitFailed,
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 45456af..25aff40 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3344,6 +3344,7 @@
case FK_NonConstLValueReferenceBindingToVectorElement:
case FK_NonConstLValueReferenceBindingToUnrelated:
case FK_RValueReferenceBindingToLValue:
+ case FK_ReferenceAddrspaceMismatchTemporary:
case FK_ReferenceInitDropsQualifiers:
case FK_ReferenceInitFailed:
case FK_ConversionFailed:
@@ -4837,9 +4838,16 @@
Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, /*bindingTemporary=*/true);
- if (T1Quals.hasAddressSpace())
+ if (T1Quals.hasAddressSpace()) {
+ if (!Qualifiers::isAddressSpaceSupersetOf(T1Quals.getAddressSpace(),
+ LangAS::Default)) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_ReferenceAddrspaceMismatchTemporary);
+ return;
+ }
Sequence.AddQualificationConversionStep(cv1T1, isLValueRef ? VK_LValue
: VK_XValue);
+ }
}
/// Attempt character array initialization from a string literal
@@ -8516,6 +8524,11 @@
<< Args[0]->getSourceRange();
break;
+ case FK_ReferenceAddrspaceMismatchTemporary:
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_temporary_addrspace)
+ << DestType << Args[0]->getSourceRange();
+ break;
+
case FK_ReferenceInitDropsQualifiers: {
QualType SourceType = OnlyArg->getType();
QualType NonRefType = DestType.getNonReferenceType();
@@ -8851,6 +8864,10 @@
OS << "reference initialization drops qualifiers";
break;
+ case FK_ReferenceAddrspaceMismatchTemporary:
+ OS << "reference with mismatching address space bound to temporary";
+ break;
+
case FK_ReferenceInitFailed:
OS << "reference initialization failed";
break;
diff --git a/clang/test/SemaOpenCLCXX/address-space-references.cl b/clang/test/SemaOpenCLCXX/address-space-references.cl
new file mode 100644
index 0000000..c359bbd
--- /dev/null
+++ b/clang/test/SemaOpenCLCXX/address-space-references.cl
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -fsyntax-only
+
+__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}}
+}