Index: clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp +++ clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp @@ -114,7 +114,7 @@ // The class type D should have the same cv-qualification as or less // cv-qualification than the class type B. - if (DTy.isMoreQualifiedThan(BTy)) + if (Context->isMoreQualifiedThan(DTy, BTy)) return false; return true; Index: clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp +++ clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp @@ -300,10 +300,11 @@ /// Checks if ArgType binds to ParamType regarding reference-ness and /// cv-qualifiers. -static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType) { +static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType, + const ASTContext &Ctx) { return !ParamType->isReferenceType() || - ParamType.getNonReferenceType().isAtLeastAsQualifiedAs( - ArgType.getNonReferenceType()); + Ctx.isAtLeastAsQualifiedAs(ParamType.getNonReferenceType(), + ArgType.getNonReferenceType()); } static bool isPointerOrArray(QualType TypeToCheck) { @@ -312,12 +313,12 @@ /// Checks whether ArgType is an array type identical to ParamType's array type. /// Enforces array elements' qualifier compatibility as well. -static bool isCompatibleWithArrayReference(QualType ArgType, - QualType ParamType) { +static bool isCompatibleWithArrayReference(QualType ArgType, QualType ParamType, + const ASTContext &Ctx) { if (!ArgType->isArrayType()) return false; // Here, qualifiers belong to the elements of the arrays. - if (!ParamType.isAtLeastAsQualifiedAs(ArgType)) + if (!Ctx.isAtLeastAsQualifiedAs(ParamType, ArgType)) return false; return ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType(); @@ -343,12 +344,13 @@ /// every * in ParamType to the right of that cv-qualifier, except the last /// one, must also be const-qualified. static bool arePointersStillQualCompatible(QualType ArgType, QualType ParamType, - bool &IsParamContinuouslyConst) { + bool &IsParamContinuouslyConst, + const ASTContext &Ctx) { // The types are compatible, if the parameter is at least as qualified as the // argument, and if it is more qualified, it has to be const on upper pointer // levels. bool AreTypesQualCompatible = - ParamType.isAtLeastAsQualifiedAs(ArgType) && + Ctx.isAtLeastAsQualifiedAs(ParamType, ArgType) && (!ParamType.hasQualifiers() || IsParamContinuouslyConst); // Check whether the parameter's constness continues at the current pointer // level. @@ -360,9 +362,10 @@ /// Checks whether multilevel pointers are compatible in terms of levels, /// qualifiers and pointee type. static bool arePointerTypesCompatible(QualType ArgType, QualType ParamType, - bool IsParamContinuouslyConst) { + bool IsParamContinuouslyConst, + const ASTContext &Ctx) { if (!arePointersStillQualCompatible(ArgType, ParamType, - IsParamContinuouslyConst)) + IsParamContinuouslyConst, Ctx)) return false; do { @@ -373,7 +376,7 @@ // Check whether cv-qualifiers permit compatibility on // current level. if (!arePointersStillQualCompatible(ArgType, ParamType, - IsParamContinuouslyConst)) + IsParamContinuouslyConst, Ctx)) return false; if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType()) @@ -397,7 +400,7 @@ return true; // Check for constness and reference compatibility. - if (!areRefAndQualCompatible(ArgType, ParamType)) + if (!areRefAndQualCompatible(ArgType, ParamType, Ctx)) return false; bool IsParamReference = ParamType->isReferenceType(); @@ -435,7 +438,7 @@ // When ParamType is an array reference, ArgType has to be of the same-sized // array-type with cv-compatible element type. if (IsParamReference && ParamType->isArrayType()) - return isCompatibleWithArrayReference(ArgType, ParamType); + return isCompatibleWithArrayReference(ArgType, ParamType, Ctx); bool IsParamContinuouslyConst = !IsParamReference || ParamType.getNonReferenceType().isConstQualified(); @@ -445,7 +448,7 @@ ParamType = convertToPointeeOrArrayElementQualType(ParamType); // Check qualifier compatibility on the next level. - if (!ParamType.isAtLeastAsQualifiedAs(ArgType)) + if (!Ctx.isAtLeastAsQualifiedAs(ParamType, ArgType)) return false; if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType()) @@ -474,7 +477,7 @@ return false; return arePointerTypesCompatible(ArgType, ParamType, - IsParamContinuouslyConst); + IsParamContinuouslyConst, Ctx); } static bool isOverloadedUnaryOrBinarySymbolOperator(const FunctionDecl *FD) { Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -2598,6 +2598,51 @@ /// 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 qualified with B + /// can be safely used as an object qualified with A. + 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". + /// If A and B have address spaces, A is more qualified than B if A's address + /// space is a strict superset of B's. + 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". + /// If A and B have address spaces, A is at least as qualified as B if A's + /// address space is an inclusive superset of B's. + 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. /// @@ -2794,6 +2839,44 @@ return AddrSpaceMapMangling || isTargetAddressSpace(AS); } + /// Embedded-C 5.1.3: Returns true if address space A is a superset of B. + /// The subspace/superspace relation governs the validity of implicit + /// conversion. If A is a superspace of B, implicitly converting from + /// address space B to address space A is permitted. + bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const; + bool isAddressSpaceSupersetOf(Qualifiers A, Qualifiers B) const { + return isAddressSpaceSupersetOf(A.getAddressSpace(), B.getAddressSpace()); + } + + /// Embedded-C 5.1.3: Returns true if address space A overlaps with B. + /// This is the same as saying that either A is a superspace of B, or B is + /// a superspace of A. If this is true, implicitly converting from A to B + /// or from B to A is permitted. This method should not be used to test for + /// validity of explicit conversion, as the target may override the behavior + /// of explicit conversion for disjoint target address spaces. + 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()); + } + + /// Extension to Embedded-C 5.1.3: Returns true if an explicit cast from + /// address space A to B is legal. + /// Explicit conversion between address spaces is permitted if the address + /// spaces are not disjoint (one of them is a superspace of the other) or + /// if the target has decided to permit it regardless of the address space + /// relation. The latter behavior is the default on every target, according + /// to Embedded-C. + bool isExplicitAddrSpaceConversionLegal(LangAS From, LangAS To) const; + 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: clang/include/clang/AST/CanonicalType.h =================================================================== --- clang/include/clang/AST/CanonicalType.h +++ clang/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: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -485,64 +485,6 @@ Mask |= qs.Mask; } - /// 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) || - // We also define global_device and global_host address spaces, - // to distinguish global pointers allocated on host from pointers - // allocated on device, which are a subset of __global. - (A == LangAS::opencl_global && (B == LangAS::opencl_global_device || - B == LangAS::opencl_global_host)) || - (A == LangAS::sycl_global && (B == LangAS::sycl_global_device || - B == LangAS::sycl_global_host)) || - // Consider pointer size address spaces to be equivalent to default. - ((isPtrSizeAddressSpace(A) || A == LangAS::Default) && - (isPtrSizeAddressSpace(B) || B == LangAS::Default)) || - // Default is a superset of SYCL address spaces. - (A == LangAS::Default && - (B == LangAS::sycl_private || B == LangAS::sycl_local || - B == LangAS::sycl_global || B == LangAS::sycl_global_device || - B == LangAS::sycl_global_host)) || - // In HIP device compilation, any cuda address space is allowed - // to implicitly cast into the default address space. - (A == LangAS::Default && - (B == LangAS::cuda_constant || B == LangAS::cuda_device || - B == LangAS::cuda_shared)); - } - - /// 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 isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace()); - } - - /// 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. /// @@ -1006,14 +948,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 @@ -1152,21 +1086,6 @@ /// 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; @@ -6715,31 +6634,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: clang/include/clang/Basic/TargetInfo.h =================================================================== --- clang/include/clang/Basic/TargetInfo.h +++ clang/include/clang/Basic/TargetInfo.h @@ -916,6 +916,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: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -10451,7 +10451,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(); @@ -12103,6 +12103,71 @@ return (*AddrSpaceMap)[(unsigned)AS]; } +bool ASTContext::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; + + // We also define global_device and global_host address spaces, + // to distinguish global pointers allocated on host from pointers + // allocated on device, which are a subset of __global. + if (A == LangAS::opencl_global && (B == LangAS::opencl_global_device || + B == LangAS::opencl_global_host)) + return true; + if (A == LangAS::sycl_global && (B == LangAS::sycl_global_device || + B == LangAS::sycl_global_host)) + return true; + + // Consider pointer size address spaces to be equivalent to default. + if ((isPtrSizeAddressSpace(A) || A == LangAS::Default) && + (isPtrSizeAddressSpace(B) || B == LangAS::Default)) + return true; + + // Default is a superset of SYCL address spaces. + if (A == LangAS::Default && + (B == LangAS::sycl_private || B == LangAS::sycl_local || + B == LangAS::sycl_global || B == LangAS::sycl_global_device || + B == LangAS::sycl_global_host)) + return true; + + // In HIP device compilation, any cuda address space is allowed + // to implicitly cast into the default address space. + if (A == LangAS::Default && + (B == LangAS::cuda_constant || B == LangAS::cuda_device || + B == LangAS::cuda_shared)) + return true; + + // Otherwise, ask the target. Leave both target ASes and LangASes up to it. + return Target->isAddressSpaceSupersetOf(A, B); +} + +bool +ASTContext::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, for any + // non-Default ASes. + if (isTargetAddressSpace(From) || isTargetAddressSpace(To) || + From == LangAS::Default || To == LangAS::Default) + return Target->isExplicitAddrSpaceConversionLegal(From, To); + + // Otherwise, the cast is illegal. + return false; +} + QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const { assert(Ty->isFixedPointType()); Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -3808,6 +3808,8 @@ // has non-default address space it is not treated as nullptr. // (__generic void*)0 in OpenCL 2.0 should not be treated as nullptr // since it cannot be assigned to a pointer to constant address space. + // FIXME: The comment and the code disagree. If the pointee is + // __generic-qualified, we will act as if it wasn't. if (Ctx.getLangOpts().OpenCL && Pointee.getAddressSpace() == Ctx.getDefaultOpenCLPointeeAddrSpace()) Qs.removeAddressSpace(); Index: clang/lib/Sema/SemaCast.cpp =================================================================== --- clang/lib/Sema/SemaCast.cpp +++ clang/lib/Sema/SemaCast.cpp @@ -694,7 +694,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) @@ -852,7 +852,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(); @@ -1403,7 +1403,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; } @@ -1635,7 +1636,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; } @@ -2455,9 +2456,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) { @@ -2545,13 +2550,6 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, unsigned &msg, CastKind &Kind) { - if (!Self.getLangOpts().OpenCL && !Self.getLangOpts().SYCLIsDevice) - // 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. auto SrcType = SrcExpr.get()->getType(); // FIXME: Should this be generalized to references? The reference parameter // however becomes a reference pointee type here and therefore rejected. @@ -2564,7 +2562,8 @@ return TC_NotApplicable; auto SrcPointeeType = SrcPtrType->getPointeeType(); auto DestPointeeType = DestPtrType->getPointeeType(); - if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) { + if (!Self.Context.isExplicitAddrSpaceConversionLegal( + SrcPointeeType.getQualifiers(), DestPointeeType.getQualifiers())) { msg = diag::err_bad_cxx_cast_addr_space_mismatch; return TC_Failed; } @@ -2595,34 +2594,41 @@ // 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() - : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) { - 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(); + // FIXME: There is a peculiarity here. Since function pointers will get + // LangAS::Default in OpenCL, isExplicitAddrSpaceConversionLegal will by + // default answer true for any conversion to/from a function pointer, even + // though such a conversion probably isn't allowed. Prevent this here, but + // it feels like a hack. + if (Nested ? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace() + : (!Self.Context.isExplicitAddrSpaceConversionLegal( + SrcPPointee.getAddressSpace(), + DestPPointee.getAddressSpace()) || + (Self.getLangOpts().OpenCL && + (DestPPointee->isFunctionType() || + SrcPPointee->isFunctionType())))) { + Self.Diag(OpRange.getBegin(), DiagID) + << SrcType << DestType << Sema::AA_Casting + << SrcExpr.get()->getSourceRange(); + if (!Nested) + SrcExpr = ExprError(); + return; } + + DestPtr = DestPPointee.getTypePtr(); + SrcPtr = SrcPPointee.getTypePtr(); + Nested = true; + DiagID = diag::ext_nested_pointer_qualifier_mismatch; } } Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -3029,7 +3029,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: clang/lib/Sema/SemaCodeComplete.cpp =================================================================== --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -1250,8 +1250,10 @@ // So make some decision based on the qualifiers. Qualifiers CandidateQual = Candidate.getMethodQualifiers(); Qualifiers IncumbentQual = Incumbent.getMethodQualifiers(); - bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual); - bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual); + bool CandidateSuperset = Candidate.getASTContext().compatiblyIncludes( + CandidateQual, IncumbentQual); + bool IncumbentSuperset = Candidate.getASTContext().compatiblyIncludes( + IncumbentQual, CandidateQual); if (CandidateSuperset == IncumbentSuperset) return OverloadCompare::BothViable; return IncumbentSuperset ? OverloadCompare::Dominates Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -17569,7 +17569,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: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ clang/lib/Sema/SemaExceptionSpec.cpp @@ -724,7 +724,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: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -8241,9 +8241,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) @@ -9264,16 +9264,16 @@ 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 @@ -9452,7 +9452,7 @@ QualType lhptee = LHSType->castAs()->getPointeeType(); QualType rhptee = RHSType->castAs()->getPointeeType(); - if (!lhptee.isAtLeastAsQualifiedAs(rhptee) && + if (!S.Context.isAtLeastAsQualifiedAs(lhptee, rhptee) && // make an exception for id

!LHSType->isObjCQualifiedIdType()) return Sema::CompatiblePointerDiscardsQualifiers; @@ -11014,7 +11014,8 @@ // if both are pointers check if operation is valid wrt address spaces if (isLHSPointer && isRHSPointer) { - if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy)) { + if (!S.Context.isAddressSpaceOverlapping(LHSPointeeTy.getAddressSpace(), + RHSPointeeTy.getAddressSpace())) { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/ @@ -12555,9 +12556,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 (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) { + // Treat NULL constant as a special case. + if (!LHSIsNull && !RHSIsNull) { + if (!Context.isAddressSpaceOverlapping( + LCanPointeeTy.getAddressSpace(), + RCanPointeeTy.getAddressSpace())) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -4581,7 +4581,7 @@ ToType->castAs()->getPointeeType().getAddressSpace(); LangAS AddrSpaceR = FromType->castAs()->getPointeeType().getAddressSpace(); - assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) && + assert(Context.isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) && "Invalid cast"); CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; @@ -6020,7 +6020,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) { @@ -6868,8 +6868,8 @@ if (Q1.getAddressSpace() == Q2.getAddressSpace()) { Quals.setAddressSpace(Q1.getAddressSpace()); } else if (Steps.size() == 1) { - bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2); - bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1); + bool MaybeQ1 = Context.isAddressSpaceSupersetOf(Q1, Q2); + bool MaybeQ2 = Context.isAddressSpaceSupersetOf(Q2, Q1); if (MaybeQ1 == MaybeQ2) { // Exception for ptr size address spaces. Should be able to choose // either address space during comparison. Index: clang/lib/Sema/SemaFixItUtils.cpp =================================================================== --- clang/lib/Sema/SemaFixItUtils.cpp +++ clang/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(); @@ -41,8 +41,8 @@ const CanQualType FromUnq = From.getUnqualifiedType(); const CanQualType ToUnq = To.getUnqualifiedType(); - if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) && - To.isAtLeastAsQualifiedAs(From)) + if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq))) && + S.Context.isAtLeastAsQualifiedAs(To, From)) return true; return false; } Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -4350,7 +4350,7 @@ if (T1Quals.hasAddressSpace()) { Qualifiers T2Quals; (void)S.Context.getUnqualifiedArrayType(InitList->getType(), T2Quals); - if (!T1Quals.isAddressSpaceSupersetOf(T2Quals)) { + if (!S.Context.isAddressSpaceSupersetOf(T1Quals, T2Quals)) { Sequence.SetFailed( InitializationSequence::FK_ReferenceInitDropsQualifiers); return; @@ -4902,7 +4902,7 @@ // For address spaces, we interpret this to mean that an addr space // of a reference "cv1 T1" is a superset of addr space of "cv2 T2". if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile() && - T1Quals.isAddressSpaceSupersetOf(T2Quals))) { + S.Context.isAddressSpaceSupersetOf(T1Quals, T2Quals))) { if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) @@ -4911,7 +4911,7 @@ ConvOvlResult); else if (!InitCategory.isLValue()) Sequence.SetFailed( - T1Quals.isAddressSpaceSupersetOf(T2Quals) + S.Context.isAddressSpaceSupersetOf(T1Quals, T2Quals) ? InitializationSequence:: FK_NonConstLValueReferenceBindingToTemporary : InitializationSequence::FK_ReferenceInitDropsQualifiers); @@ -5095,7 +5095,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; } @@ -5112,8 +5112,8 @@ Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, /*BindingTemporary=*/true); if (T1Quals.hasAddressSpace()) { - if (!Qualifiers::isAddressSpaceSupersetOf(T1Quals.getAddressSpace(), - LangAS::Default)) { + if (!S.Context.isAddressSpaceSupersetOf(T1Quals.getAddressSpace(), + LangAS::Default)) { Sequence.SetFailed( InitializationSequence::FK_ReferenceAddrspaceMismatchTemporary); return; @@ -8991,8 +8991,8 @@ destDecl->getDeclKind() == Decl::CXXRecord && !fromDecl->isInvalidDecl() && !destDecl->isInvalidDecl() && !fromDecl->hasDefinition() && - destPointeeType.getQualifiers().compatiblyIncludes( - fromPointeeType.getQualifiers())) + S.Context.compatiblyIncludes(destPointeeType.getQualifiers(), + fromPointeeType.getQualifiers())) S.Diag(fromDecl->getLocation(), diag::note_forward_class_conversion) << S.getASTContext().getTagDeclType(fromDecl) << S.getASTContext().getTagDeclType(destDecl); @@ -9255,8 +9255,8 @@ Qualifiers DroppedQualifiers = SourceType.getQualifiers() - NonRefType.getQualifiers(); - if (!NonRefType.getQualifiers().isAddressSpaceSupersetOf( - SourceType.getQualifiers())) + if (!S.Context.isAddressSpaceSupersetOf(NonRefType.getQualifiers(), + SourceType.getQualifiers())) S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << NonRefType << SourceType << 1 /*addr space*/ << Args[0]->getSourceRange(); Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -18591,7 +18591,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; })) { @@ -21343,7 +21343,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: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -2493,7 +2493,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); @@ -2529,8 +2529,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(), @@ -2716,7 +2716,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 @@ -3196,7 +3196,8 @@ /// Specifically, check whether any change between the qualifiers of \p /// FromType and \p ToType is permissible, given knowledge about whether every /// outer layer is const-qualified. -static bool isQualificationConversionStep(QualType FromType, QualType ToType, +static bool isQualificationConversionStep(ASTContext &Context, + QualType FromType, QualType ToType, bool CStyle, bool IsTopLevel, bool &PreviousToQualsIncludeConst, bool &ObjCLifetimeConversion) { @@ -3230,7 +3231,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 address spaces mismatch: @@ -3238,10 +3239,14 @@ // superset in all cases apart from C-style casts where we allow // conversions between overlapping address spaces. // - in non-top levels it is not a valid conversion. + // FIXME: For the first case here, we should probably be using + // isExplicitAddrSpaceConversionLegal rather than checking CStyle, but we + // don't know if this is an implicit or explicit conversion. if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() && (!IsTopLevel || - !(ToQuals.isAddressSpaceSupersetOf(FromQuals) || - (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals))))) + !(Context.isAddressSpaceSupersetOf(ToQuals, FromQuals) || + (CStyle && Context.isExplicitAddrSpaceConversionLegal(FromQuals, + ToQuals))))) return false; // -- if the cv 1,j and cv 2,j are different, then const is in @@ -3296,7 +3301,7 @@ bool UnwrappedAnyPointer = false; while (Context.UnwrapSimilarTypes(FromType, ToType)) { if (!isQualificationConversionStep( - FromType, ToType, CStyle, !UnwrappedAnyPointer, + Context, FromType, ToType, CStyle, !UnwrappedAnyPointer, PreviousToQualsIncludeConst, ObjCLifetimeConversion)) return false; UnwrappedAnyPointer = true; @@ -4149,9 +4154,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; - if (T1.isMoreQualifiedThan(T2)) + if (S.Context.isMoreQualifiedThan(T1, T2)) return ImplicitConversionSequence::Worse; } } @@ -4591,8 +4596,8 @@ // If we find a qualifier mismatch, the types are not reference-compatible, // but are still be reference-related if they're similar. bool ObjCLifetimeConversion = false; - if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel, - PreviousToQualsIncludeConst, + if (!isQualificationConversionStep(Context, T2, T1, /*CStyle=*/false, + TopLevel, PreviousToQualsIncludeConst, ObjCLifetimeConversion)) return (ConvertedReferent || Context.hasSimilarType(T1, T2)) ? Ref_Related @@ -4923,7 +4928,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; } @@ -5398,21 +5403,24 @@ // First check the qualifiers. QualType FromTypeCanon = S.Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() - != FromTypeCanon.getLocalCVRQualifiers() && - !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { + != FromTypeCanon.getLocalCVRQualifiers() && + !S.Context.isAtLeastAsQualifiedAs(ImplicitParamType, FromTypeCanon)) { ICS.setBad(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType); return ICS; } - if (FromTypeCanon.hasAddressSpace()) { - Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers(); - Qualifiers QualsFromType = FromTypeCanon.getQualifiers(); - if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) { - ICS.setBad(BadConversionSequence::bad_qualifiers, - FromType, ImplicitParamType); - return ICS; - } + // Check that the address space conversion to the implicit parameter is valid, + // if we need to do one. + Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers(); + Qualifiers QualsFromType = FromTypeCanon.getQualifiers(); + if (QualsImplicitParamType.getAddressSpace() != + QualsFromType.getAddressSpace() && + !S.Context.isAddressSpaceSupersetOf(QualsImplicitParamType, + QualsFromType)) { + ICS.setBad(BadConversionSequence::bad_qualifiers, + FromType, ImplicitParamType); + return ICS; } // Check that we have either the same type or a derived type. It @@ -6445,7 +6453,7 @@ // Check that the constructor is capable of constructing an object in the // destination address space. - if (!Qualifiers::isAddressSpaceSupersetOf( + if (!Context.isAddressSpaceSupersetOf( Constructor->getMethodQualifiers().getAddressSpace(), CandidateSet.getDestAS())) { Candidate.Viable = false; @@ -10004,9 +10012,9 @@ LangAS AS1 = CD1->getMethodQualifiers().getAddressSpace(); LangAS AS2 = CD2->getMethodQualifiers().getAddressSpace(); if (AS1 != AS2) { - if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1)) + if (S.Context.isAddressSpaceSupersetOf(AS2, AS1)) return true; - if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1)) + if (S.Context.isAddressSpaceSupersetOf(AS2, AS1)) return false; } } @@ -10576,7 +10584,7 @@ } if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() && - !CToTy.isAtLeastAsQualifiedAs(CFromTy)) { + !S.Context.isAtLeastAsQualifiedAs(CToTy, CFromTy)) { Qualifiers FromQs = CFromTy.getQualifiers(); Qualifiers ToQs = CToTy.getQualifiers(); @@ -10691,8 +10699,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(), @@ -10705,12 +10713,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: clang/lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- clang/lib/Sema/SemaTemplateDeduction.cpp +++ clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1541,7 +1541,7 @@ // C++ [temp.deduct.conv]p4: // If the original A is a reference type, A can be more cv-qualified // than the deduced A - if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers())) + if (!S.Context.compatiblyIncludes(A.getQualifiers(), P.getQualifiers())) return Sema::TDK_NonDeducedMismatch; // Strip out all extra qualifiers from the argument to figure out the @@ -3338,7 +3338,7 @@ if (AQuals == DeducedAQuals) { // Qualifiers match; there's nothing to do. - } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { + } else if (!Context.compatiblyIncludes(DeducedAQuals, AQuals)) { return Failed(); } else { // Qualifiers are compatible, so have the argument type adopt the Index: clang/test/Analysis/addrspace-null.c =================================================================== --- clang/test/Analysis/addrspace-null.c +++ clang/test/Analysis/addrspace-null.c @@ -35,7 +35,10 @@ int fn3() { int val = 0; int *dptr = val; - return dptr == (DEVICE void *)0; + // FIXME: This gives an error, since Expr doesn't consider AS-qualified void* + // to be a valid null pointer constant. + //return dptr == (DEVICE void *)0; + return 0; } #endif Index: clang/test/CodeGenCXX/address-space-cast.cpp =================================================================== --- clang/test/CodeGenCXX/address-space-cast.cpp +++ clang/test/CodeGenCXX/address-space-cast.cpp @@ -37,8 +37,9 @@ // CHECK-NEXT: store i8 addrspace(5)* %[[cast]] priv_void_ptr = (__private__ void *)gen_void_ptr; - // CHECK: %[[cast:.*]] = addrspacecast i32* %{{.*}} to i8 addrspace(5)* - // CHECK-NEXT: store i8 addrspace(5)* %[[cast]] + // CHECK: %[[cast:.*]] = bitcast i32* %{{.*}} to i8* + // CHECK-NEXT: %[[cast2:.*]] = addrspacecast i8* %[[cast]] to i8 addrspace(5)* + // CHECK-NEXT: store i8 addrspace(5)* %[[cast2]] priv_void_ptr = (__private__ void *)gen_int_ptr; // CHECK: %[[cast:.*]] = addrspacecast i8* %{{.*}} to i32 addrspace(5)* @@ -65,8 +66,9 @@ // CHECK-NEXT: call void @_Z10func_pvoidPU3AS5v(i8 addrspace(5)* noundef %[[cast]]) func_pvoid((__private__ void *)gen_void_ptr); - // CHECK: %[[cast:.*]] = addrspacecast i32* %{{.*}} to i8 addrspace(5)* - // CHECK-NEXT: call void @_Z10func_pvoidPU3AS5v(i8 addrspace(5)* noundef %[[cast]]) + // CHECK: %[[cast:.*]] = bitcast i32* %{{.*}} to i8* + // CHECK-NEXT: %[[cast2:.*]] = addrspacecast i8* %[[cast]] to i8 addrspace(5)* + // CHECK-NEXT: call void @_Z10func_pvoidPU3AS5v(i8 addrspace(5)* noundef %[[cast2]]) func_pvoid((__private__ void *)gen_int_ptr); // CHECK: %[[cast:.*]] = addrspacecast i8* %{{.*}} to i32 addrspace(5)* Index: clang/test/Sema/address_space_print_macro.c =================================================================== --- clang/test/Sema/address_space_print_macro.c +++ clang/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: clang/test/Sema/address_spaces.c =================================================================== --- clang/test/Sema/address_spaces.c +++ clang/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}} } char *sub(_AS1 char *x, _AS2 char *y) { Index: clang/test/SemaOpenCLCXX/address-space-lambda.clcpp =================================================================== --- clang/test/SemaOpenCLCXX/address-space-lambda.clcpp +++ clang/test/SemaOpenCLCXX/address-space-lambda.clcpp @@ -66,7 +66,7 @@ // expected-warning@-2{{lambda without a parameter clause is a C++2b extension}} #endif - [&] () mutable __private {} (); + [&] () mutable __private {} (); // expected-error{{no matching function for call to object of type '(lambda at}} expected-note{{candidate function not viable: 'this' object is in default address space, but method expects object in address space '__private'}} [&] () __private mutable {} (); //expected-error{{expected body of lambda expression}} }