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
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362604
91177308-0d34-0410-b5e6-
96231b3b80d8
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.
"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<
/// Reference binding drops qualifiers.
FK_ReferenceInitDropsQualifiers,
+ /// Reference with mismatching address space binding to temporary.
+ FK_ReferenceAddrspaceMismatchTemporary,
+
/// Reference binding failed.
FK_ReferenceInitFailed,
case FK_NonConstLValueReferenceBindingToVectorElement:
case FK_NonConstLValueReferenceBindingToUnrelated:
case FK_RValueReferenceBindingToLValue:
+ case FK_ReferenceAddrspaceMismatchTemporary:
case FK_ReferenceInitDropsQualifiers:
case FK_ReferenceInitFailed:
case FK_ConversionFailed:
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
<< 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();
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;
--- /dev/null
+// 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}}
+}