[SYCL] Prohibit arithmetic operations for incompatible pointers

Summary:
This change enables OpenCL diagnostics for the pointers annotated with
address space attribute SYCL mode.

Move `isAddressSpaceOverlapping` method from PointerType to QualType.

Reviewers: Anastasia, rjmccall

Reviewed By: rjmccall

Subscribers: rjmccall, jeroen.dobbelaere, Fznamznon, yaxunl, ebevhan, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D80317
This commit is contained in:
Alexey Bader 2020-05-20 22:22:30 +03:00
parent 872ee78f65
commit e95ee300c0
5 changed files with 32 additions and 26 deletions

View File

@ -1064,6 +1064,21 @@ public:
/// Return the address space of this type.
inline LangAS getAddressSpace() const;
/// Returns true if address space qualifiers overlap with T address space
/// qualifiers.
/// OpenCL C defines conversion rules for pointers to different address spaces
/// and notion of overlapping address spaces.
/// CL1.1 or CL1.2:
/// address spaces overlap iff they are they same.
/// OpenCL C v2.0 s6.5.5 adds:
/// __generic overlaps with any address space except for __constant.
bool isAddressSpaceOverlapping(QualType T) const {
Qualifiers Q = getQualifiers();
Qualifiers TQ = T.getQualifiers();
// Address spaces overlap if at least one of them is a superset of another
return Q.isAddressSpaceSupersetOf(TQ) || TQ.isAddressSpaceSupersetOf(Q);
}
/// Returns gc attribute of this type.
inline Qualifiers::GC getObjCGCAttr() const;
@ -2631,22 +2646,6 @@ class PointerType : public Type, public llvm::FoldingSetNode {
public:
QualType getPointeeType() const { return PointeeType; }
/// Returns true if address spaces of pointers overlap.
/// OpenCL v2.0 defines conversion rules for pointers to different
/// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping
/// address spaces.
/// CL1.1 or CL1.2:
/// address spaces overlap iff they are they same.
/// CL2.0 adds:
/// __generic overlaps with any address space except for __constant.
bool isAddressSpaceOverlapping(const PointerType &other) const {
Qualifiers thisQuals = PointeeType.getQualifiers();
Qualifiers otherQuals = other.getPointeeType().getQualifiers();
// Address spaces overlap if at least one of them is a superset of another
return thisQuals.isAddressSpaceSupersetOf(otherQuals) ||
otherQuals.isAddressSpaceSupersetOf(thisQuals);
}
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }

View File

@ -2391,7 +2391,7 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
auto SrcPointeeType = SrcPtrType->getPointeeType();
auto DestPointeeType = DestPtrType->getPointeeType();
if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) {
if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) {
msg = diag::err_bad_cxx_cast_addr_space_mismatch;
return TC_Failed;
}
@ -2434,9 +2434,9 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
const PointerType *SrcPPtr = cast<PointerType>(SrcPtr);
QualType DestPPointee = DestPPtr->getPointeeType();
QualType SrcPPointee = SrcPPtr->getPointeeType();
if (Nested ? DestPPointee.getAddressSpace() !=
SrcPPointee.getAddressSpace()
: !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) {
if (Nested
? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace()
: !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) {
Self.Diag(OpRange.getBegin(), DiagID)
<< SrcType << DestType << Sema::AA_Casting
<< SrcExpr.get()->getSourceRange();

View File

@ -10087,10 +10087,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType();
// if both are pointers check if operation is valid wrt address spaces
if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) {
const PointerType *lhsPtr = LHSExpr->getType()->castAs<PointerType>();
const PointerType *rhsPtr = RHSExpr->getType()->castAs<PointerType>();
if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) {
if (isLHSPointer && isRHSPointer) {
if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy)) {
S.Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/
@ -11444,8 +11442,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (LCanPointeeTy != RCanPointeeTy) {
// Treat NULL constant as a special case in OpenCL.
if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
const PointerType *LHSPtr = LHSType->castAs<PointerType>();
if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs<PointerType>())) {
if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) {
Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSType << RHSType << 0 /* comparison */

View File

@ -74,6 +74,10 @@ char* cmp(_AS1 char *x, _AS2 char *y) {
return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}}
}
char *sub(_AS1 char *x, _AS2 char *y) {
return x - y; // expected-error {{arithmetic operation with operands of type ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}}
}
struct SomeStruct {
int a;
long b;

View File

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
int *foo(__attribute__((opencl_private)) int *p,
__attribute__((opencl_local)) int *l) {
return p - l; // expected-error {{arithmetic operation with operands of type ('__private int *' and '__local int *') which are pointers to non-overlapping address spaces}}
}