Skip to content

Commit

Permalink
[Sema] Prevent binding incompatible addr space ref to temporaries
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Anastasia Stulova committed Jun 5, 2019
1 parent 22e99c4 commit 5145b1e
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 9 deletions.
20 changes: 12 additions & 8 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,21 +460,25 @@ class Qualifiers {
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.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,9 @@ 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 "
"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<
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,9 @@ class InitializationSequence {
/// Reference binding drops qualifiers.
FK_ReferenceInitDropsQualifiers,

/// Reference with mismatching address space binding to temporary.
FK_ReferenceAddrspaceMismatchTemporary,

/// Reference binding failed.
FK_ReferenceInitFailed,

Expand Down
19 changes: 18 additions & 1 deletion clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3344,6 +3344,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_NonConstLValueReferenceBindingToVectorElement:
case FK_NonConstLValueReferenceBindingToUnrelated:
case FK_RValueReferenceBindingToLValue:
case FK_ReferenceAddrspaceMismatchTemporary:
case FK_ReferenceInitDropsQualifiers:
case FK_ReferenceInitFailed:
case FK_ConversionFailed:
Expand Down Expand Up @@ -4837,9 +4838,16 @@ static void TryReferenceInitializationCore(Sema &S,

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
Expand Down Expand Up @@ -8516,6 +8524,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< 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();
Expand Down Expand Up @@ -8851,6 +8864,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
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;
Expand Down
5 changes: 5 additions & 0 deletions clang/test/SemaOpenCLCXX/address-space-references.cl
Original file line number Diff line number Diff line change
@@ -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}}
}

0 comments on commit 5145b1e

Please sign in to comment.