Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -2350,6 +2350,49 @@ /// Determine if two types are similar, ignoring only CVR qualifiers. bool hasCvrSimilarType(QualType T1, QualType T2); + /// Determines if the qualifiers A compatibly include another set B. + /// Generally this answers the question of whether an object with B's + /// qualifiers can be safely used as an object with A's qualifiers. + bool compatiblyIncludes(Qualifiers A, Qualifiers B) const { + return isAddressSpaceSupersetOf(A, B) && + // ObjC GC qualifiers can match, be added, or be removed, but can't + // be changed. + (A.getObjCGCAttr() == B.getObjCGCAttr() || !A.hasObjCGCAttr() || + !B.hasObjCGCAttr()) && + // ObjC lifetime qualifiers must match exactly. + A.getObjCLifetime() == B.getObjCLifetime() && + // CVR qualifiers may subset. + ((A.getCVRQualifiers() | B.getCVRQualifiers()) == + A.getCVRQualifiers()) && + // U qualifier may superset. + (!B.hasUnaligned() || A.hasUnaligned()); + } + + /// Determine whether the type A is more + /// qualified than the type B. For example, "const volatile int" + /// is more qualified than "const int", "volatile int", and + /// "int". However, it is not more qualified than "const volatile + /// int". + bool isMoreQualifiedThan(QualType A, QualType B) const { + Qualifiers AQuals = A.getQualifiers(); + Qualifiers BQuals = B.getQualifiers(); + return (AQuals != BQuals && compatiblyIncludes(AQuals, BQuals)); + } + + /// Determine whether the type A is at least + /// as qualified as the type B. For example, "const volatile + /// int" is at least as qualified as "const int", "volatile int", + /// "int", and "const volatile int". + bool isAtLeastAsQualifiedAs(QualType A, QualType B) const { + Qualifiers BQuals = B.getQualifiers(); + + // Ignore __unaligned qualifier if A is a void. + if (A.getUnqualifiedType()->isVoidType()) + BQuals.removeUnaligned(); + + return compatiblyIncludes(A.getQualifiers(), BQuals); + } + /// Retrieves the "canonical" nested name specifier for a /// given nested name specifier. /// @@ -2528,6 +2571,60 @@ return AddrSpaceMapMangling || isTargetAddressSpace(AS); } + /// Returns true if address space A is a superset of B. + bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const { + // All address spaces are supersets of themselves. + if (A == B) + return true; + + // 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. + if (A == LangAS::opencl_generic && + B != LangAS::opencl_constant) + return true; + + // Otherwise, ask the target. + return Target->isAddressSpaceSupersetOf(A, B); + } + bool isAddressSpaceSupersetOf(Qualifiers A, Qualifiers B) const { + return isAddressSpaceSupersetOf(A.getAddressSpace(), B.getAddressSpace()); + } + + /// Returns true if address space A overlaps with B. + bool isAddressSpaceOverlapping(LangAS A, LangAS B) const { + // A overlaps with B if either is a superset of the other. + return isAddressSpaceSupersetOf(A, B) || + isAddressSpaceSupersetOf(B, A); + } + bool isAddressSpaceOverlapping(Qualifiers A, Qualifiers B) const { + return isAddressSpaceOverlapping(A.getAddressSpace(), B.getAddressSpace()); + } + + /// Returns true if an explicit cast from address space A to B is legal. + bool isExplicitAddrSpaceConversionLegal(LangAS From, LangAS To) const { + // If From and To overlap, the cast is legal. + if (isAddressSpaceOverlapping(From, To)) + return true; + + // Or, if either From or To are target address spaces, the target can + // decide whether or not to allow the cast regardless of overlap. + if (isTargetAddressSpace(From) || isTargetAddressSpace(To) || + From == LangAS::Default || To == LangAS::Default) + return Target->isExplicitAddrSpaceConversionLegal(From, To); + + // Otherwise, the cast is illegal. + return false; + } + bool isExplicitAddrSpaceConversionLegal(Qualifiers From, + Qualifiers To) const { + return isExplicitAddrSpaceConversionLegal(From.getAddressSpace(), + To.getAddressSpace()); + } + private: // Helper for integer ordering unsigned getIntegerRank(const Type *T) const; Index: include/clang/AST/CanonicalType.h =================================================================== --- include/clang/AST/CanonicalType.h +++ include/clang/AST/CanonicalType.h @@ -162,18 +162,6 @@ return Stored.withConst(); } - /// Determines whether this canonical type is more qualified than - /// the @p Other canonical type. - bool isMoreQualifiedThan(CanQual Other) const { - return Stored.isMoreQualifiedThan(Other.Stored); - } - - /// Determines whether this canonical type is at least as qualified as - /// the @p Other canonical type. - bool isAtLeastAsQualifiedAs(CanQual Other) const { - return Stored.isAtLeastAsQualifiedAs(Other.Stored); - } - /// If the canonical type is a reference type, returns the type that /// it refers to; otherwise, returns the type itself. CanQual getNonReferenceType() const; Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -460,40 +460,6 @@ Mask |= qs.Mask; } - /// Returns true if this address space is a superset of the other one. - /// 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. - 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); - } - - /// Determines if these qualifiers compatibly include another set. - /// Generally this answers the question of whether an object with the other - /// qualifiers can be safely used as an object with these qualifiers. - bool compatiblyIncludes(Qualifiers other) const { - return isAddressSpaceSupersetOf(other) && - // ObjC GC qualifiers can match, be added, or be removed, but can't - // be changed. - (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || - !other.hasObjCGCAttr()) && - // ObjC lifetime qualifiers must match exactly. - getObjCLifetime() == other.getObjCLifetime() && - // CVR qualifiers may subset. - (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) && - // U qualifier may superset. - (!other.hasUnaligned() || hasUnaligned()); - } - /// Determines if these qualifiers compatibly include another set of /// qualifiers from the narrow perspective of Objective-C ARC lifetime. /// @@ -908,14 +874,6 @@ /// ASTContext::getUnqualifiedArrayType. inline SplitQualType getSplitUnqualifiedType() const; - /// Determine whether this type is more qualified than the other - /// given type, requiring exact equality for non-CVR qualifiers. - bool isMoreQualifiedThan(QualType Other) const; - - /// Determine whether this type is at least as qualified as the other - /// given type, requiring exact equality for non-CVR qualifiers. - bool isAtLeastAsQualifiedAs(QualType Other) const; - QualType getNonReferenceType() const; /// Determine the type of a (typically non-lvalue) expression with the @@ -2561,22 +2519,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); } @@ -6255,31 +6197,6 @@ return getFunctionExtInfo(*t); } -/// Determine whether this type is more -/// qualified than the Other type. For example, "const volatile int" -/// is more qualified than "const int", "volatile int", and -/// "int". However, it is not more qualified than "const volatile -/// int". -inline bool QualType::isMoreQualifiedThan(QualType other) const { - Qualifiers MyQuals = getQualifiers(); - Qualifiers OtherQuals = other.getQualifiers(); - return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals)); -} - -/// Determine whether this type is at last -/// as qualified as the Other type. For example, "const volatile -/// int" is at least as qualified as "const int", "volatile int", -/// "int", and "const volatile int". -inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { - Qualifiers OtherQuals = other.getQualifiers(); - - // Ignore __unaligned qualifier if this type is a void. - if (getUnqualifiedType()->isVoidType()) - OtherQuals.removeUnaligned(); - - return getQualifiers().compatiblyIncludes(OtherQuals); -} - /// If Type is a reference type (e.g., const /// int&), returns the type that the reference refers to ("const /// int"). Otherwise, returns the type itself. This routine is used Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -741,6 +741,22 @@ return UseAddrSpaceMapMangling; } + /// Return true if address space A is a superspace of B. + /// By default, all target address spaces are disjoint. + virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const { + return false; + } + + /// Return true if an explicit cast from address space From to To is legal. + /// This lets targets override the behavior when neither address space is a + /// true superset of the other, but the target still wants explicit casting + /// between them. + /// By default, explicit casting between all target address spaces is + /// permitted. + virtual bool isExplicitAddrSpaceConversionLegal(LangAS From, LangAS To) const{ + return true; + } + ///===---- Other target property query methods --------------------------===// /// Appends the target-specific \#define values for this Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8879,7 +8879,7 @@ Qualifiers RHSPteeQual = RHSPointee.getQualifiers(); // Blocks can't be an expression in a ternary operator (OpenCL v2.0 // 6.12.5) thus the following check is asymmetric. - if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual)) + if (!isAddressSpaceSupersetOf(LHSPteeQual, RHSPteeQual)) return {}; LHSPteeQual.removeAddressSpace(); RHSPteeQual.removeAddressSpace(); Index: lib/Sema/SemaCast.cpp =================================================================== --- lib/Sema/SemaCast.cpp +++ lib/Sema/SemaCast.cpp @@ -615,7 +615,7 @@ *CastAwayQualifiers = SrcCvrQuals - DestCvrQuals; // If we removed a cvr-qualifier, this is casting away 'constness'. - if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) { + if (!Self.Context.compatiblyIncludes(DestCvrQuals, SrcCvrQuals)) { if (TheOffendingSrcType) *TheOffendingSrcType = PrevUnwrappedSrcType; if (TheOffendingDestType) @@ -771,7 +771,7 @@ assert(SrcRecord && "Bad source pointee slipped through."); // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. - if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { + if (!Self.Context.isAtLeastAsQualifiedAs(DestPointee, SrcPointee)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away) << CT_Dynamic << OrigSrcType << this->DestType << OpRange; SrcExpr = ExprError(); @@ -1193,7 +1193,8 @@ SrcPointeeQuals.removeObjCGCAttr(); SrcPointeeQuals.removeObjCLifetime(); if (DestPointeeQuals != SrcPointeeQuals && - !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) { + !Self.Context.compatiblyIncludes(DestPointeeQuals, + SrcPointeeQuals)) { msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -1420,7 +1421,7 @@ // FIXME: Being 100% compliant here would be nice to have. // Must preserve cv, as always, unless we're in C-style mode. - if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) { + if (!CStyle && !Self.Context.isAtLeastAsQualifiedAs(DestType, SrcType)) { msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -2215,9 +2216,13 @@ if (IsAddressSpaceConversion(SrcType, DestType)) { Kind = CK_AddressSpaceConversion; assert(SrcType->isPointerType() && DestType->isPointerType()); - if (!CStyle && - !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf( - SrcType->getPointeeType().getQualifiers())) { + auto SrcQ = SrcType->getPointeeType().getQualifiers(); + auto DestQ = DestType->getPointeeType().getQualifiers(); + // Real reinterpret_casts can only do address space conversions which are + // 'implicit', such as subspace->superspace. For C-style casts, check if + // the cast is explicitly legal as well. + if (CStyle ? !Self.Context.isExplicitAddrSpaceConversionLegal(SrcQ, DestQ) + : !Self.Context.isAddressSpaceSupersetOf(DestQ, SrcQ)) { SuccessResult = TC_Failed; } } else if (IsLValueCast) { @@ -2286,14 +2291,7 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, - unsigned &msg) { - if (!Self.getLangOpts().OpenCL) - // FIXME: As compiler doesn't have any information about overlapping addr - // spaces at the moment we have to be permissive here. - return TC_NotApplicable; - // Even though the logic below is general enough and can be applied to - // non-OpenCL mode too, we fast-path above because no other languages - // define overlapping address spaces currently. + unsigned &msg, CastKind &Kind) { auto SrcType = SrcExpr.get()->getType(); auto SrcPtrType = SrcType->getAs(); if (!SrcPtrType) @@ -2305,7 +2303,8 @@ auto DestPointeeType = DestPtrType->getPointeeType(); if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()) return TC_NotApplicable; - if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { + if (!Self.Context.isExplicitAddrSpaceConversionLegal( + SrcPointeeType.getQualifiers(), DestPointeeType.getQualifiers())) { msg = diag::err_bad_cxx_cast_addr_space_mismatch; return TC_Failed; } @@ -2313,10 +2312,12 @@ Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType()); auto DestPointeeTypeWithoutAS = Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType()); - return Self.Context.hasSameType(SrcPointeeTypeWithoutAS, - DestPointeeTypeWithoutAS) - ? TC_Success - : TC_NotApplicable; + if (!Self.Context.hasSameType(SrcPointeeTypeWithoutAS, + DestPointeeTypeWithoutAS)) + return TC_NotApplicable; + + Kind = CK_AddressSpaceConversion; + return TC_Success; } void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { @@ -2331,34 +2332,34 @@ // local int ** p; // return (generic int **) p; // warn even though local -> generic is permitted. - if (Self.getLangOpts().OpenCL) { - const Type *DestPtr, *SrcPtr; - bool Nested = false; - unsigned DiagID = diag::err_typecheck_incompatible_address_space; - DestPtr = Self.getASTContext().getCanonicalType(DestType.getTypePtr()), - SrcPtr = Self.getASTContext().getCanonicalType(SrcType.getTypePtr()); - - while (isa(DestPtr) && isa(SrcPtr)) { - const PointerType *DestPPtr = cast(DestPtr); - const PointerType *SrcPPtr = cast(SrcPtr); - QualType DestPPointee = DestPPtr->getPointeeType(); - QualType SrcPPointee = SrcPPtr->getPointeeType(); - if (Nested ? DestPPointee.getAddressSpace() != - SrcPPointee.getAddressSpace() - : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) { - Self.Diag(OpRange.getBegin(), DiagID) - << SrcType << DestType << Sema::AA_Casting - << SrcExpr.get()->getSourceRange(); - if (!Nested) - SrcExpr = ExprError(); - return; - } - - DestPtr = DestPPtr->getPointeeType().getTypePtr(); - SrcPtr = SrcPPtr->getPointeeType().getTypePtr(); - Nested = true; - DiagID = diag::ext_nested_pointer_qualifier_mismatch; + const Type *DestPtr, *SrcPtr; + bool Nested = false; + unsigned DiagID = diag::err_typecheck_incompatible_address_space; + DestPtr = Self.getASTContext().getCanonicalType(DestType.getTypePtr()), + SrcPtr = Self.getASTContext().getCanonicalType(SrcType.getTypePtr()); + + while (isa(DestPtr) && isa(SrcPtr)) { + const PointerType *DestPPtr = cast(DestPtr); + const PointerType *SrcPPtr = cast(SrcPtr); + QualType DestPPointee = DestPPtr->getPointeeType(); + QualType SrcPPointee = SrcPPtr->getPointeeType(); + if (Nested ? DestPPointee.getAddressSpace() != + SrcPPointee.getAddressSpace() + : !Self.Context.isExplicitAddrSpaceConversionLegal( + SrcPPointee.getAddressSpace(), + DestPPointee.getAddressSpace())) { + Self.Diag(OpRange.getBegin(), DiagID) + << SrcType << DestType << Sema::AA_Casting + << SrcExpr.get()->getSourceRange(); + if (!Nested) + SrcExpr = ExprError(); + return; } + + DestPtr = DestPPtr->getPointeeType().getTypePtr(); + SrcPtr = SrcPPtr->getPointeeType().getTypePtr(); + Nested = true; + DiagID = diag::ext_nested_pointer_qualifier_mismatch; } } @@ -2447,7 +2448,8 @@ Sema::CheckedConversionKind CCK = FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { - tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg); + tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg, + Kind); if (SrcExpr.isInvalid()) return; if (tcr == TC_NotApplicable) { Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1739,7 +1739,7 @@ // Issue a warning if the cast is dodgy. CastKind CastNeeded = CK_NoOp; - if (!AddrType.isAtLeastAsQualifiedAs(ValType)) { + if (!Context.isAtLeastAsQualifiedAs(AddrType, ValType)) { CastNeeded = CK_BitCast; Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers) << PointerArg->getType() << Context.getPointerType(AddrType) Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -14888,7 +14888,7 @@ // The new class type must have the same or less qualifiers as the old type. - if (NewClassTy.isMoreQualifiedThan(OldClassTy)) { + if (Context.isMoreQualifiedThan(NewClassTy, OldClassTy)) { Diag(New->getLocation(), diag::err_covariant_return_type_class_type_more_qualified) << New->getDeclName() << NewTy << OldTy Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -692,7 +692,7 @@ ExceptionType->getPointeeType(), EQuals); HandlerType = Context.getUnqualifiedArrayType( HandlerType->getPointeeType(), HQuals); - if (!HQuals.compatiblyIncludes(EQuals)) + if (!Context.compatiblyIncludes(HQuals, EQuals)) return false; if (HandlerType->isVoidType() && ExceptionType->isObjectType()) Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -6792,9 +6792,9 @@ // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address // spaces is disallowed. - if (lhQual.isAddressSpaceSupersetOf(rhQual)) + if (S.Context.isAddressSpaceSupersetOf(lhQual, rhQual)) ResultAddrSpace = LAddrSpace; - else if (rhQual.isAddressSpaceSupersetOf(lhQual)) + else if (S.Context.isAddressSpaceSupersetOf(rhQual, lhQual)) ResultAddrSpace = RAddrSpace; else { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) @@ -7743,16 +7743,17 @@ rhq.removeObjCLifetime(); } - if (!lhq.compatiblyIncludes(rhq)) { + if (!S.Context.compatiblyIncludes(lhq, rhq)) { // Treat address-space mismatches as fatal. - if (!lhq.isAddressSpaceSupersetOf(rhq)) + if (!S.Context.isAddressSpaceSupersetOf(lhq, rhq)) return Sema::IncompatiblePointerDiscardsQualifiers; // It's okay to add or remove GC or lifetime qualifiers when converting to // and from void*. - else if (lhq.withoutObjCGCAttr().withoutObjCLifetime() - .compatiblyIncludes( - rhq.withoutObjCGCAttr().withoutObjCLifetime()) + else if (S.Context.compatiblyIncludes(lhq.withoutObjCGCAttr() + .withoutObjCLifetime(), + rhq.withoutObjCGCAttr() + .withoutObjCLifetime()) && (lhptee->isVoidType() || rhptee->isVoidType())) ; // keep old @@ -7927,7 +7928,7 @@ QualType lhptee = LHSType->getAs()->getPointeeType(); QualType rhptee = RHSType->getAs()->getPointeeType(); - if (!lhptee.isAtLeastAsQualifiedAs(rhptee) && + if (!S.Context.isAtLeastAsQualifiedAs(lhptee, rhptee) && // make an exception for id

!LHSType->isObjCQualifiedIdType()) return Sema::CompatiblePointerDiscardsQualifiers; @@ -9244,10 +9245,12 @@ if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType(); // if both are pointers check if operation is valid wrt address spaces - if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) { + if (isLHSPointer && isRHSPointer) { const PointerType *lhsPtr = LHSExpr->getType()->getAs(); const PointerType *rhsPtr = RHSExpr->getType()->getAs(); - if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) { + if (!S.Context.isAddressSpaceOverlapping( + lhsPtr->getPointeeType().getAddressSpace(), + rhsPtr->getPointeeType().getAddressSpace())) { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/ @@ -10582,10 +10585,11 @@ diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } if (LCanPointeeTy != RCanPointeeTy) { - // Treat NULL constant as a special case in OpenCL. - if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) { + if (!LHSIsNull && !RHSIsNull) { const PointerType *LHSPtr = LHSType->getAs(); - if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->getAs())) { + if (!Context.isAddressSpaceOverlapping( + LHSPtr->getPointeeType().getAddressSpace(), + RHSType->getPointeeType().getAddressSpace())) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -5623,7 +5623,7 @@ // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. if (FRec == TRec || FDerivedFromT) { - if (TTy.isAtLeastAsQualifiedAs(FTy)) { + if (Self.Context.isAtLeastAsQualifiedAs(TTy, FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq) { Index: lib/Sema/SemaFixItUtils.cpp =================================================================== --- lib/Sema/SemaFixItUtils.cpp +++ lib/Sema/SemaFixItUtils.cpp @@ -24,7 +24,7 @@ Sema &S, SourceLocation Loc, ExprValueKind FromVK) { - if (!To.isAtLeastAsQualifiedAs(From)) + if (!S.Context.isAtLeastAsQualifiedAs(To, From)) return false; From = From.getNonReferenceType(); @@ -42,7 +42,7 @@ const CanQualType ToUnq = To.getUnqualifiedType(); if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) && - To.isAtLeastAsQualifiedAs(From)) + S.Context.isAtLeastAsQualifiedAs(To, From)) return true; return false; } Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -4813,7 +4813,7 @@ unsigned T2CVRQuals = T2Quals.getCVRQualifiers(); if ((RefRelationship == Sema::Ref_Related && (T1CVRQuals | T2CVRQuals) != T1CVRQuals) || - !T1Quals.isAddressSpaceSupersetOf(T2Quals)) { + !S.Context.isAddressSpaceSupersetOf(T1Quals, T2Quals)) { Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -11450,7 +11450,7 @@ Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { if (!D->isInvalidDecl() && SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && - !Ty.isMoreQualifiedThan(D->getType())) + !SemaRef.Context.isMoreQualifiedThan(Ty, D->getType())) return D; return nullptr; })) { @@ -13723,7 +13723,7 @@ Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * { if (!D->isInvalidDecl() && SemaRef.IsDerivedFrom(Loc, Type, D->getType()) && - !Type.isMoreQualifiedThan(D->getType())) + !SemaRef.Context.isMoreQualifiedThan(Type, D->getType())) return D; return nullptr; })) { Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -2394,7 +2394,7 @@ if (TQs == Qs) return T; - if (Qs.compatiblyIncludes(TQs)) + if (Context.compatiblyIncludes(Qs, TQs)) return Context.getQualifiedType(T, Qs); return Context.getQualifiedType(T.getUnqualifiedType(), Qs); @@ -2430,8 +2430,8 @@ const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType(); const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType(); if (getLangOpts().CPlusPlus && LHS && RHS && - !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs( - FromObjCPtr->getPointeeType())) + !Context.isAtLeastAsQualifiedAs(ToObjCPtr->getPointeeType(), + FromObjCPtr->getPointeeType())) return false; ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), @@ -2617,7 +2617,7 @@ // Make sure that we have compatible qualifiers. FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing); - if (!ToQuals.compatiblyIncludes(FromQuals)) + if (!Context.compatiblyIncludes(ToQuals, FromQuals)) return false; // Remove qualifiers from the pointee type we're converting from; they @@ -3146,7 +3146,7 @@ // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. - if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) + if (!CStyle && !Context.compatiblyIncludes(ToQuals, FromQuals)) return false; // -- if the cv 1,j and cv 2,j are different, then const is in @@ -3161,12 +3161,17 @@ = PreviousToQualsIncludeConst && ToQuals.hasConst(); } - // Allows address space promotion by language rules implemented in - // Type::Qualifiers::isAddressSpaceSupersetOf. + // FIXME: This should *really* be testing implicit conversions with + // 'isAddressSpaceSupersetOf' and explicit conversions with + // 'isExplicitAddrSpaceConversionLegal', but IsQualificationConversion isn't + // aware of whether the conversion is implicit or explicit. Add that? + // + // Also, I don't really understand why we do this. How does preventing + // qualification conversion for disjoint address spaces make address space + // casts *work*? Qualifiers FromQuals = FromType.getQualifiers(); Qualifiers ToQuals = ToType.getQualifiers(); - if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) && - !FromQuals.isAddressSpaceSupersetOf(ToQuals)) { + if (!Context.isAddressSpaceOverlapping(ToQuals, FromQuals)) { return false; } @@ -3896,9 +3901,9 @@ T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); if (isa(T2) && T2Quals) T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); - if (T2.isMoreQualifiedThan(T1)) + if (S.Context.isMoreQualifiedThan(T2, T1)) return ImplicitConversionSequence::Better; - else if (T1.isMoreQualifiedThan(T2)) + else if (S.Context.isMoreQualifiedThan(T1, T2)) return ImplicitConversionSequence::Worse; } } @@ -4017,7 +4022,7 @@ // ObjC ownership quals are omitted above as they interfere with // the ARC overload rule. ; - else if (T2.isMoreQualifiedThan(T1)) { + else if (S.Context.isMoreQualifiedThan(T2, T1)) { // T1 has fewer qualifiers, so it could be the better sequence. if (Result == ImplicitConversionSequence::Worse) // Neither has qualifiers that are a subset of the other's @@ -4025,7 +4030,7 @@ return ImplicitConversionSequence::Indistinguishable; Result = ImplicitConversionSequence::Better; - } else if (T1.isMoreQualifiedThan(T2)) { + } else if (S.Context.isMoreQualifiedThan(T1, T2)) { // T2 has fewer qualifiers, so it could be the better sequence. if (Result == ImplicitConversionSequence::Better) // Neither has qualifiers that are a subset of the other's @@ -4373,7 +4378,7 @@ T1Quals.removeUnaligned(); T2Quals.removeUnaligned(); - if (T1Quals.compatiblyIncludes(T2Quals)) + if (Context.compatiblyIncludes(T1Quals, T2Quals)) return Ref_Compatible; else return Ref_Related; @@ -4702,7 +4707,7 @@ // MS compiler ignores __unaligned qualifier for references; do the same. T1Quals.removeUnaligned(); T2Quals.removeUnaligned(); - if (!T1Quals.compatiblyIncludes(T2Quals)) + if (!S.Context.compatiblyIncludes(T1Quals, T2Quals)) return ICS; } @@ -5136,16 +5141,20 @@ QualType FromTypeCanon = S.Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && - !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { + !S.Context.isAtLeastAsQualifiedAs(ImplicitParamType, FromTypeCanon)) { ICS.setBad(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType); return ICS; } + // FIXME: hasAddressSpace is wrong; this check will be skipped if FromType is + // not qualified with an address space, but if there's no implicit conversion + // from Default to ImplicitParamType's AS, that's an error. if (FromTypeCanon.getQualifiers().hasAddressSpace()) { Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers(); Qualifiers QualsFromType = FromTypeCanon.getQualifiers(); - if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) { + if (!S.Context.isAddressSpaceSupersetOf(QualsImplicitParamType, + QualsFromType)) { ICS.setBad(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType); return ICS; @@ -9752,7 +9761,7 @@ } if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() && - !CToTy.isAtLeastAsQualifiedAs(CFromTy)) { + !S.Context.isAtLeastAsQualifiedAs(CToTy, CFromTy)) { Qualifiers FromQs = CFromTy.getQualifiers(); Qualifiers ToQs = CToTy.getQualifiers(); @@ -9845,8 +9854,8 @@ unsigned BaseToDerivedConversion = 0; if (const PointerType *FromPtrTy = FromTy->getAs()) { if (const PointerType *ToPtrTy = ToTy->getAs()) { - if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs( - FromPtrTy->getPointeeType()) && + if (S.Context.isAtLeastAsQualifiedAs(ToPtrTy->getPointeeType(), + FromPtrTy->getPointeeType()) && !FromPtrTy->getPointeeType()->isIncompleteType() && !ToPtrTy->getPointeeType()->isIncompleteType() && S.IsDerivedFrom(SourceLocation(), ToPtrTy->getPointeeType(), @@ -9859,12 +9868,12 @@ = ToTy->getAs()) if (const ObjCInterfaceDecl *FromIface = FromPtrTy->getInterfaceDecl()) if (const ObjCInterfaceDecl *ToIface = ToPtrTy->getInterfaceDecl()) - if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs( - FromPtrTy->getPointeeType()) && + if (S.Context.isAtLeastAsQualifiedAs(ToPtrTy->getPointeeType(), + FromPtrTy->getPointeeType()) && FromIface->isSuperClassOf(ToIface)) BaseToDerivedConversion = 2; } else if (const ReferenceType *ToRefTy = ToTy->getAs()) { - if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) && + if (S.Context.isAtLeastAsQualifiedAs(ToRefTy->getPointeeType(), FromTy) && !FromTy->isIncompleteType() && !ToRefTy->getPointeeType()->isIncompleteType() && S.IsDerivedFrom(SourceLocation(), ToRefTy->getPointeeType(), FromTy)) { Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -1444,7 +1444,8 @@ // C++ [temp.deduct.conv]p4: // If the original A is a reference type, A can be more cv-qualified // than the deduced A - if (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers())) + if (!S.Context.compatiblyIncludes(Arg.getQualifiers(), + Param.getQualifiers())) return Sema::TDK_NonDeducedMismatch; // Strip out all extra qualifiers from the argument to figure out the @@ -3212,7 +3213,7 @@ if (AQuals == DeducedAQuals) { // Qualifiers match; there's nothing to do. - } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { + } else if (!S.Context.compatiblyIncludes(DeducedAQuals, AQuals)) { return Failed(); } else { // Qualifiers are compatible, so have the argument type adopt the Index: test/Sema/address_space_print_macro.c =================================================================== --- test/Sema/address_space_print_macro.c +++ test/Sema/address_space_print_macro.c @@ -14,7 +14,8 @@ } 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}} + 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}} \ + // expected-error{{comparison between ('AS1 char *' and 'AS2 char *') which are pointers to non-overlapping address spaces}} } __attribute__((address_space(1))) char test_array[10]; Index: test/Sema/address_spaces.c =================================================================== --- test/Sema/address_spaces.c +++ test/Sema/address_spaces.c @@ -71,7 +71,8 @@ // Clang extension doesn't forbid operations on pointers to different address spaces. 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}} + 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}} \ + // expected-error{{comparison between ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}} } struct SomeStruct {