ebevhan updated this revision to Diff 284765.
ebevhan retitled this revision from "Initial draft of target-configurable 
address spaces." to "Add support for target-configurable address spaces.".
ebevhan edited the summary of this revision.
ebevhan added a comment.

Rebased and updated summary.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D62574/new/

https://reviews.llvm.org/D62574

Files:
  clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/CanonicalType.h
  clang/include/clang/AST/Type.h
  clang/include/clang/Basic/TargetInfo.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/Sema/SemaCast.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaFixItUtils.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaOpenMP.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/CodeGenCXX/address-space-cast.cpp
  clang/test/Sema/address_space_print_macro.c
  clang/test/Sema/address_spaces.c

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/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/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)* %[[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)* %[[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)* %[[cast2]])
   func_pvoid((__private__ void *)gen_int_ptr);
 
   // CHECK: %[[cast:.*]] = addrspacecast i8* %{{.*}} to i32 addrspace(5)*
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -1571,7 +1571,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
@@ -3449,7 +3450,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: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -2491,7 +2491,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);
@@ -2527,8 +2527,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(),
@@ -2714,7 +2714,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
@@ -3188,7 +3188,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) {
@@ -3223,7 +3224,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:
@@ -3231,10 +3232,13 @@
   //    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: This should probably be using isExplicitAddrSpaceConversionLegal,
+  // 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
@@ -3276,7 +3280,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;
@@ -4054,9 +4058,9 @@
         T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
       if (isa<ArrayType>(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;
     }
   }
@@ -4169,7 +4173,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
@@ -4177,7 +4181,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
@@ -4521,8 +4525,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
@@ -4850,7 +4854,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;
   }
 
@@ -5276,16 +5280,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.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;
@@ -6278,7 +6286,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;
@@ -10289,7 +10297,7 @@
   }
 
   if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
-      !CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
+      !S.Context.isAtLeastAsQualifiedAs(CToTy, CFromTy)) {
     Qualifiers FromQs = CFromTy.getQualifiers();
     Qualifiers ToQs = CToTy.getQualifiers();
 
@@ -10389,8 +10397,8 @@
   unsigned BaseToDerivedConversion = 0;
   if (const PointerType *FromPtrTy = FromTy->getAs<PointerType>()) {
     if (const PointerType *ToPtrTy = ToTy->getAs<PointerType>()) {
-      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(),
@@ -10403,12 +10411,12 @@
                                         = ToTy->getAs<ObjCObjectPointerType>())
       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<ReferenceType>()) {
-    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/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -14663,7 +14663,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;
             })) {
@@ -17325,7 +17325,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/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -4797,7 +4797,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())
@@ -4806,7 +4806,7 @@
                                   ConvOvlResult);
     else if (!InitCategory.isLValue())
       Sequence.SetFailed(
-          T1Quals.isAddressSpaceSupersetOf(T2Quals)
+          S.Context.isAddressSpaceSupersetOf(T1Quals, T2Quals)
               ? InitializationSequence::
                     FK_NonConstLValueReferenceBindingToTemporary
               : InitializationSequence::FK_ReferenceInitDropsQualifiers);
@@ -4990,7 +4990,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;
   }
@@ -5007,8 +5007,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;
@@ -8976,8 +8976,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/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();
@@ -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: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -4388,7 +4388,7 @@
         ToType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace();
     LangAS AddrSpaceR =
         FromType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace();
-    assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) &&
+    assert(Context.isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) &&
            "Invalid cast");
     CastKind Kind =
         AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
@@ -5777,7 +5777,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) {
@@ -6519,8 +6519,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)
           return QualType(); // No unique best address space.
         Quals.setAddressSpace(MaybeQ1 ? Q1.getAddressSpace()
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -7710,9 +7710,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)
@@ -8710,16 +8710,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
 
@@ -8898,7 +8899,7 @@
   QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
   QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
 
-  if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
+  if (!S.Context.isAtLeastAsQualifiedAs(lhptee, rhptee) &&
       // make an exception for id<P>
       !LHSType->isObjCQualifiedIdType())
     return Sema::CompatiblePointerDiscardsQualifiers;
@@ -10261,7 +10262,9 @@
 
   // 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*/
@@ -11641,9 +11644,10 @@
       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)) {
+      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/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -719,7 +719,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/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16958,7 +16958,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/SemaCodeComplete.cpp
===================================================================
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -1219,8 +1219,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/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -2348,7 +2348,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/SemaCast.cpp
===================================================================
--- clang/lib/Sema/SemaCast.cpp
+++ clang/lib/Sema/SemaCast.cpp
@@ -685,7 +685,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)
@@ -843,7 +843,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();
@@ -1286,7 +1286,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;
             }
@@ -1510,7 +1511,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;
   }
@@ -2313,9 +2314,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) {
@@ -2403,13 +2408,6 @@
 static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
                                          QualType DestType, bool CStyle,
                                          unsigned &msg, CastKind &Kind) {
-  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.
   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.
@@ -2422,7 +2420,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;
   }
@@ -2453,34 +2452,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<PointerType>(DestPtr) && isa<PointerType>(SrcPtr)) {
-      const PointerType *DestPPtr = cast<PointerType>(DestPtr);
-      const PointerType *SrcPPtr = cast<PointerType>(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<PointerType>(DestPtr) && isa<PointerType>(SrcPtr)) {
+    const PointerType *DestPPtr = cast<PointerType>(DestPtr);
+    const PointerType *SrcPPtr = cast<PointerType>(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;
   }
 }
 
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -9472,7 +9472,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();
@@ -10928,6 +10928,53 @@
     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;
+
+  // Consider pointer size address spaces to be equivalent to default.
+  if ((isPtrSizeAddressSpace(A) || A == LangAS::Default) &&
+      (isPtrSizeAddressSpace(B) || B == LangAS::Default))
+    return true;
+
+  // Otherwise, ask the target.
+  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.
+  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/include/clang/Basic/TargetInfo.h
===================================================================
--- clang/include/clang/Basic/TargetInfo.h
+++ clang/include/clang/Basic/TargetInfo.h
@@ -821,6 +821,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/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -467,52 +467,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)) ||
-           // Consider pointer size address spaces to be equivalent to default.
-           ((isPtrSizeAddressSpace(A) || A == LangAS::Default) &&
-            (isPtrSizeAddressSpace(B) || B == LangAS::Default));
-  }
-
-  /// 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.
   ///
@@ -929,14 +883,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
@@ -1075,21 +1021,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;
 
@@ -6533,31 +6464,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/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<T> 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<T> 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<Type> getNonReferenceType() const;
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -2365,6 +2365,47 @@
   /// 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".
+  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.
   ///
@@ -2544,6 +2585,42 @@
     return AddrSpaceMapMangling || isTargetAddressSpace(AS);
   }
 
+  /// 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());
+  }
+
+  /// 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());
+  }
+
+  /// 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.
+  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-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;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to