diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1064,6 +1064,21 @@ /// 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 @@ 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); } diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2391,7 +2391,7 @@ 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 @@ const PointerType *SrcPPtr = cast(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(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10087,10 +10087,8 @@ 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(); - const PointerType *rhsPtr = RHSExpr->getType()->castAs(); - 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 @@ if (LCanPointeeTy != RCanPointeeTy) { // Treat NULL constant as a special case in OpenCL. if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) { - const PointerType *LHSPtr = LHSType->castAs(); - if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs())) { + if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ diff --git a/clang/test/Sema/address_spaces.c b/clang/test/Sema/address_spaces.c --- a/clang/test/Sema/address_spaces.c +++ b/clang/test/Sema/address_spaces.c @@ -74,6 +74,10 @@ 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; diff --git a/clang/test/SemaCXX/address-space-arithmetic.cpp b/clang/test/SemaCXX/address-space-arithmetic.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/address-space-arithmetic.cpp @@ -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}} +}