ebevhan updated this revision to Diff 203559.
ebevhan added a comment.

Replaced `compatiblyIncludes` and its dependents with ASTContext accessors 
instead.


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

https://reviews.llvm.org/D62574

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/CanonicalType.h
  include/clang/AST/Type.h
  include/clang/Basic/TargetInfo.h
  lib/AST/ASTContext.cpp
  lib/Sema/SemaCast.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaFixItUtils.cpp
  lib/Sema/SemaInit.cpp
  lib/Sema/SemaOpenMP.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/SemaTemplateDeduction.cpp
  test/Sema/address_space_print_macro.c
  test/Sema/address_spaces.c

Index: test/Sema/address_spaces.c
===================================================================
--- test/Sema/address_spaces.c
+++ test/Sema/address_spaces.c
@@ -71,7 +71,8 @@
 
 // Clang extension doesn't forbid operations on pointers to different address spaces.
 char* cmp(_AS1 char *x,  _AS2 char *y) {
-  return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type  ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}}
+  return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type  ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}} \
+                        // expected-error{{comparison between  ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}}
 }
 
 struct SomeStruct {
Index: test/Sema/address_space_print_macro.c
===================================================================
--- test/Sema/address_space_print_macro.c
+++ test/Sema/address_space_print_macro.c
@@ -14,7 +14,8 @@
 }
 
 char *cmp(AS1 char *x, AS2 char *y) {
-  return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type  ('AS1 char *' and 'AS2 char *') which are pointers to non-overlapping address spaces}}
+  return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type  ('AS1 char *' and 'AS2 char *') which are pointers to non-overlapping address spaces}} \
+                        // expected-error{{comparison between  ('AS1 char *' and 'AS2 char *') which are pointers to non-overlapping address spaces}}
 }
 
 __attribute__((address_space(1))) char test_array[10];
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -1444,7 +1444,8 @@
       // C++ [temp.deduct.conv]p4:
       //   If the original A is a reference type, A can be more cv-qualified
       //   than the deduced A
-      if (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers()))
+      if (!S.Context.compatiblyIncludes(Arg.getQualifiers(),
+                                        Param.getQualifiers()))
         return Sema::TDK_NonDeducedMismatch;
 
       // Strip out all extra qualifiers from the argument to figure out the
@@ -3212,7 +3213,7 @@
 
     if (AQuals == DeducedAQuals) {
       // Qualifiers match; there's nothing to do.
-    } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
+    } else if (!S.Context.compatiblyIncludes(DeducedAQuals, AQuals)) {
       return Failed();
     } else {
       // Qualifiers are compatible, so have the argument type adopt the
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -2394,7 +2394,7 @@
   if (TQs == Qs)
     return T;
 
-  if (Qs.compatiblyIncludes(TQs))
+  if (Context.compatiblyIncludes(Qs, TQs))
     return Context.getQualifiedType(T, Qs);
 
   return Context.getQualifiedType(T.getUnqualifiedType(), Qs);
@@ -2430,8 +2430,8 @@
       const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType();
       const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType();
       if (getLangOpts().CPlusPlus && LHS && RHS &&
-          !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs(
-                                                FromObjCPtr->getPointeeType()))
+          !Context.isAtLeastAsQualifiedAs(ToObjCPtr->getPointeeType(),
+                                          FromObjCPtr->getPointeeType()))
         return false;
       ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
                                                    ToObjCPtr->getPointeeType(),
@@ -2617,7 +2617,7 @@
 
   // Make sure that we have compatible qualifiers.
   FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing);
-  if (!ToQuals.compatiblyIncludes(FromQuals))
+  if (!Context.compatiblyIncludes(ToQuals, FromQuals))
     return false;
 
   // Remove qualifiers from the pointee type we're converting from; they
@@ -3146,7 +3146,7 @@
 
     //   -- for every j > 0, if const is in cv 1,j then const is in cv
     //      2,j, and similarly for volatile.
-    if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
+    if (!CStyle && !Context.compatiblyIncludes(ToQuals, FromQuals))
       return false;
 
     //   -- if the cv 1,j and cv 2,j are different, then const is in
@@ -3161,12 +3161,17 @@
       = PreviousToQualsIncludeConst && ToQuals.hasConst();
   }
 
-  // Allows address space promotion by language rules implemented in
-  // Type::Qualifiers::isAddressSpaceSupersetOf.
+  // FIXME: This should *really* be testing implicit conversions with
+  // 'isAddressSpaceSupersetOf' and explicit conversions with
+  // 'isExplicitAddrSpaceConversionLegal', but IsQualificationConversion isn't
+  // aware of whether the conversion is implicit or explicit. Add that?
+  //
+  // Also, I don't really understand why we do this. How does preventing
+  // qualification conversion for disjoint address spaces make address space
+  // casts *work*?
   Qualifiers FromQuals = FromType.getQualifiers();
   Qualifiers ToQuals = ToType.getQualifiers();
-  if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
-      !FromQuals.isAddressSpaceSupersetOf(ToQuals)) {
+  if (!Context.isAddressSpaceOverlapping(ToQuals, FromQuals)) {
     return false;
   }
 
@@ -3896,9 +3901,9 @@
         T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
       if (isa<ArrayType>(T2) && T2Quals)
         T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
-      if (T2.isMoreQualifiedThan(T1))
+      if (S.Context.isMoreQualifiedThan(T2, T1))
         return ImplicitConversionSequence::Better;
-      else if (T1.isMoreQualifiedThan(T2))
+      else if (S.Context.isMoreQualifiedThan(T1, T2))
         return ImplicitConversionSequence::Worse;
     }
   }
@@ -4017,7 +4022,7 @@
       // ObjC ownership quals are omitted above as they interfere with
       // the ARC overload rule.
       ;
-    else if (T2.isMoreQualifiedThan(T1)) {
+    else if (S.Context.isMoreQualifiedThan(T2, T1)) {
       // T1 has fewer qualifiers, so it could be the better sequence.
       if (Result == ImplicitConversionSequence::Worse)
         // Neither has qualifiers that are a subset of the other's
@@ -4025,7 +4030,7 @@
         return ImplicitConversionSequence::Indistinguishable;
 
       Result = ImplicitConversionSequence::Better;
-    } else if (T1.isMoreQualifiedThan(T2)) {
+    } else if (S.Context.isMoreQualifiedThan(T1, T2)) {
       // T2 has fewer qualifiers, so it could be the better sequence.
       if (Result == ImplicitConversionSequence::Better)
         // Neither has qualifiers that are a subset of the other's
@@ -4373,7 +4378,7 @@
   T1Quals.removeUnaligned();
   T2Quals.removeUnaligned();
 
-  if (T1Quals.compatiblyIncludes(T2Quals))
+  if (Context.compatiblyIncludes(T1Quals, T2Quals))
     return Ref_Compatible;
   else
     return Ref_Related;
@@ -4702,7 +4707,7 @@
     // MS compiler ignores __unaligned qualifier for references; do the same.
     T1Quals.removeUnaligned();
     T2Quals.removeUnaligned();
-    if (!T1Quals.compatiblyIncludes(T2Quals))
+    if (!S.Context.compatiblyIncludes(T1Quals, T2Quals))
       return ICS;
   }
 
@@ -5136,16 +5141,20 @@
   QualType FromTypeCanon = S.Context.getCanonicalType(FromType);
   if (ImplicitParamType.getCVRQualifiers()
                                     != FromTypeCanon.getLocalCVRQualifiers() &&
-      !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
+      !S.Context.isAtLeastAsQualifiedAs(ImplicitParamType, FromTypeCanon)) {
     ICS.setBad(BadConversionSequence::bad_qualifiers,
                FromType, ImplicitParamType);
     return ICS;
   }
 
+  // FIXME: hasAddressSpace is wrong; this check will be skipped if FromType is
+  // not qualified with an address space, but if there's no implicit conversion
+  // from Default to ImplicitParamType's AS, that's an error.
   if (FromTypeCanon.getQualifiers().hasAddressSpace()) {
     Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers();
     Qualifiers QualsFromType = FromTypeCanon.getQualifiers();
-    if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) {
+    if (!S.Context.isAddressSpaceSupersetOf(QualsImplicitParamType,
+                                            QualsFromType)) {
       ICS.setBad(BadConversionSequence::bad_qualifiers,
                  FromType, ImplicitParamType);
       return ICS;
@@ -9752,7 +9761,7 @@
   }
 
   if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
-      !CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
+      !S.Context.isAtLeastAsQualifiedAs(CToTy, CFromTy)) {
     Qualifiers FromQs = CFromTy.getQualifiers();
     Qualifiers ToQs = CToTy.getQualifiers();
 
@@ -9845,8 +9854,8 @@
   unsigned BaseToDerivedConversion = 0;
   if (const PointerType *FromPtrTy = FromTy->getAs<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(),
@@ -9859,12 +9868,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: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -11450,7 +11450,7 @@
             Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
               if (!D->isInvalidDecl() &&
                   SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) &&
-                  !Ty.isMoreQualifiedThan(D->getType()))
+                  !SemaRef.Context.isMoreQualifiedThan(Ty, D->getType()))
                 return D;
               return nullptr;
             })) {
@@ -13723,7 +13723,7 @@
           Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * {
             if (!D->isInvalidDecl() &&
                 SemaRef.IsDerivedFrom(Loc, Type, D->getType()) &&
-                !Type.isMoreQualifiedThan(D->getType()))
+                !SemaRef.Context.isMoreQualifiedThan(Type, D->getType()))
               return D;
             return nullptr;
           })) {
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -4813,7 +4813,7 @@
   unsigned T2CVRQuals = T2Quals.getCVRQualifiers();
   if ((RefRelationship == Sema::Ref_Related &&
        (T1CVRQuals | T2CVRQuals) != T1CVRQuals) ||
-      !T1Quals.isAddressSpaceSupersetOf(T2Quals)) {
+      !S.Context.isAddressSpaceSupersetOf(T1Quals, T2Quals)) {
     Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
     return;
   }
Index: lib/Sema/SemaFixItUtils.cpp
===================================================================
--- lib/Sema/SemaFixItUtils.cpp
+++ lib/Sema/SemaFixItUtils.cpp
@@ -24,7 +24,7 @@
                                                   Sema &S,
                                                   SourceLocation Loc,
                                                   ExprValueKind FromVK) {
-  if (!To.isAtLeastAsQualifiedAs(From))
+  if (!S.Context.isAtLeastAsQualifiedAs(To, From))
     return false;
 
   From = From.getNonReferenceType();
@@ -42,7 +42,7 @@
   const CanQualType ToUnq = To.getUnqualifiedType();
 
   if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) &&
-      To.isAtLeastAsQualifiedAs(From))
+      S.Context.isAtLeastAsQualifiedAs(To, From))
     return true;
   return false;
 }
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5623,7 +5623,7 @@
     //         same type as, or a base class of, the class of T1, and
     //         [cv2 > cv1].
     if (FRec == TRec || FDerivedFromT) {
-      if (TTy.isAtLeastAsQualifiedAs(FTy)) {
+      if (Self.Context.isAtLeastAsQualifiedAs(TTy, FTy)) {
         InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
         InitializationSequence InitSeq(Self, Entity, Kind, From);
         if (InitSeq) {
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -6792,9 +6792,9 @@
 
   // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
   // spaces is disallowed.
-  if (lhQual.isAddressSpaceSupersetOf(rhQual))
+  if (S.Context.isAddressSpaceSupersetOf(lhQual, rhQual))
     ResultAddrSpace = LAddrSpace;
-  else if (rhQual.isAddressSpaceSupersetOf(lhQual))
+  else if (S.Context.isAddressSpaceSupersetOf(rhQual, lhQual))
     ResultAddrSpace = RAddrSpace;
   else {
     S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
@@ -7743,16 +7743,17 @@
     rhq.removeObjCLifetime();
   }
 
-  if (!lhq.compatiblyIncludes(rhq)) {
+  if (!S.Context.compatiblyIncludes(lhq, rhq)) {
     // Treat address-space mismatches as fatal.
-    if (!lhq.isAddressSpaceSupersetOf(rhq))
+    if (!S.Context.isAddressSpaceSupersetOf(lhq, rhq))
       return Sema::IncompatiblePointerDiscardsQualifiers;
 
     // It's okay to add or remove GC or lifetime qualifiers when converting to
     // and from void*.
-    else if (lhq.withoutObjCGCAttr().withoutObjCLifetime()
-                        .compatiblyIncludes(
-                                rhq.withoutObjCGCAttr().withoutObjCLifetime())
+    else if (S.Context.compatiblyIncludes(lhq.withoutObjCGCAttr()
+                                             .withoutObjCLifetime(),
+                                          rhq.withoutObjCGCAttr()
+                                             .withoutObjCLifetime())
              && (lhptee->isVoidType() || rhptee->isVoidType()))
       ; // keep old
 
@@ -7927,7 +7928,7 @@
   QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
   QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
 
-  if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
+  if (!S.Context.isAtLeastAsQualifiedAs(lhptee, rhptee) &&
       // make an exception for id<P>
       !LHSType->isObjCQualifiedIdType())
     return Sema::CompatiblePointerDiscardsQualifiers;
@@ -9244,10 +9245,12 @@
   if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType();
 
   // if both are pointers check if operation is valid wrt address spaces
-  if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) {
+  if (isLHSPointer && isRHSPointer) {
     const PointerType *lhsPtr = LHSExpr->getType()->getAs<PointerType>();
     const PointerType *rhsPtr = RHSExpr->getType()->getAs<PointerType>();
-    if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) {
+    if (!S.Context.isAddressSpaceOverlapping(
+          lhsPtr->getPointeeType().getAddressSpace(),
+          rhsPtr->getPointeeType().getAddressSpace())) {
       S.Diag(Loc,
              diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
           << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/
@@ -10582,10 +10585,11 @@
       diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false);
     }
     if (LCanPointeeTy != RCanPointeeTy) {
-      // Treat NULL constant as a special case in OpenCL.
-      if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
+      if (!LHSIsNull && !RHSIsNull) {
         const PointerType *LHSPtr = LHSType->getAs<PointerType>();
-        if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) {
+        if (!Context.isAddressSpaceOverlapping(
+              LHSPtr->getPointeeType().getAddressSpace(),
+              RHSType->getPointeeType().getAddressSpace())) {
           Diag(Loc,
                diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
               << LHSType << RHSType << 0 /* comparison */
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -692,7 +692,7 @@
         ExceptionType->getPointeeType(), EQuals);
     HandlerType = Context.getUnqualifiedArrayType(
         HandlerType->getPointeeType(), HQuals);
-    if (!HQuals.compatiblyIncludes(EQuals))
+    if (!Context.compatiblyIncludes(HQuals, EQuals))
       return false;
 
     if (HandlerType->isVoidType() && ExceptionType->isObjectType())
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -14888,7 +14888,7 @@
 
 
   // The new class type must have the same or less qualifiers as the old type.
-  if (NewClassTy.isMoreQualifiedThan(OldClassTy)) {
+  if (Context.isMoreQualifiedThan(NewClassTy, OldClassTy)) {
     Diag(New->getLocation(),
          diag::err_covariant_return_type_class_type_more_qualified)
         << New->getDeclName() << NewTy << OldTy
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -1739,7 +1739,7 @@
 
   // Issue a warning if the cast is dodgy.
   CastKind CastNeeded = CK_NoOp;
-  if (!AddrType.isAtLeastAsQualifiedAs(ValType)) {
+  if (!Context.isAtLeastAsQualifiedAs(AddrType, ValType)) {
     CastNeeded = CK_BitCast;
     Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)
         << PointerArg->getType() << Context.getPointerType(AddrType)
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -615,7 +615,7 @@
           *CastAwayQualifiers = SrcCvrQuals - DestCvrQuals;
 
         // If we removed a cvr-qualifier, this is casting away 'constness'.
-        if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) {
+        if (!Self.Context.compatiblyIncludes(DestCvrQuals, SrcCvrQuals)) {
           if (TheOffendingSrcType)
             *TheOffendingSrcType = PrevUnwrappedSrcType;
           if (TheOffendingDestType)
@@ -771,7 +771,7 @@
   assert(SrcRecord && "Bad source pointee slipped through.");
 
   // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
-  if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
+  if (!Self.Context.isAtLeastAsQualifiedAs(DestPointee, SrcPointee)) {
     Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
       << CT_Dynamic << OrigSrcType << this->DestType << OpRange;
     SrcExpr = ExprError();
@@ -1193,7 +1193,8 @@
             SrcPointeeQuals.removeObjCGCAttr();
             SrcPointeeQuals.removeObjCLifetime();
             if (DestPointeeQuals != SrcPointeeQuals &&
-                !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
+                !Self.Context.compatiblyIncludes(DestPointeeQuals,
+                                                 SrcPointeeQuals)) {
               msg = diag::err_bad_cxx_cast_qualifiers_away;
               return TC_Failed;
             }
@@ -1420,7 +1421,7 @@
   // FIXME: Being 100% compliant here would be nice to have.
 
   // Must preserve cv, as always, unless we're in C-style mode.
-  if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
+  if (!CStyle && !Self.Context.isAtLeastAsQualifiedAs(DestType, SrcType)) {
     msg = diag::err_bad_cxx_cast_qualifiers_away;
     return TC_Failed;
   }
@@ -2215,9 +2216,13 @@
   if (IsAddressSpaceConversion(SrcType, DestType)) {
     Kind = CK_AddressSpaceConversion;
     assert(SrcType->isPointerType() && DestType->isPointerType());
-    if (!CStyle &&
-        !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf(
-            SrcType->getPointeeType().getQualifiers())) {
+    auto SrcQ = SrcType->getPointeeType().getQualifiers();
+    auto DestQ = DestType->getPointeeType().getQualifiers();
+    // Real reinterpret_casts can only do address space conversions which are
+    // 'implicit', such as subspace->superspace. For C-style casts, check if
+    // the cast is explicitly legal as well.
+    if (CStyle ? !Self.Context.isExplicitAddrSpaceConversionLegal(SrcQ, DestQ)
+               : !Self.Context.isAddressSpaceSupersetOf(DestQ, SrcQ)) {
       SuccessResult = TC_Failed;
     }
   } else if (IsLValueCast) {
@@ -2286,14 +2291,7 @@
 
 static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
                                          QualType DestType, bool CStyle,
-                                         unsigned &msg) {
-  if (!Self.getLangOpts().OpenCL)
-    // FIXME: As compiler doesn't have any information about overlapping addr
-    // spaces at the moment we have to be permissive here.
-    return TC_NotApplicable;
-  // Even though the logic below is general enough and can be applied to
-  // non-OpenCL mode too, we fast-path above because no other languages
-  // define overlapping address spaces currently.
+                                         unsigned &msg, CastKind &Kind) {
   auto SrcType = SrcExpr.get()->getType();
   auto SrcPtrType = SrcType->getAs<PointerType>();
   if (!SrcPtrType)
@@ -2305,7 +2303,8 @@
   auto DestPointeeType = DestPtrType->getPointeeType();
   if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace())
     return TC_NotApplicable;
-  if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) {
+  if (!Self.Context.isExplicitAddrSpaceConversionLegal(
+        SrcPointeeType.getQualifiers(), DestPointeeType.getQualifiers())) {
     msg = diag::err_bad_cxx_cast_addr_space_mismatch;
     return TC_Failed;
   }
@@ -2313,10 +2312,12 @@
       Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType());
   auto DestPointeeTypeWithoutAS =
       Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType());
-  return Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
-                                  DestPointeeTypeWithoutAS)
-             ? TC_Success
-             : TC_NotApplicable;
+  if (!Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
+                                  DestPointeeTypeWithoutAS))
+    return TC_NotApplicable;
+
+  Kind = CK_AddressSpaceConversion;
+  return TC_Success;
 }
 
 void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
@@ -2331,34 +2332,34 @@
   //   local int ** p;
   //   return (generic int **) p;
   // warn even though local -> generic is permitted.
-  if (Self.getLangOpts().OpenCL) {
-    const Type *DestPtr, *SrcPtr;
-    bool Nested = false;
-    unsigned DiagID = diag::err_typecheck_incompatible_address_space;
-    DestPtr = Self.getASTContext().getCanonicalType(DestType.getTypePtr()),
-    SrcPtr  = Self.getASTContext().getCanonicalType(SrcType.getTypePtr());
-
-    while (isa<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()
-                 : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) {
-        Self.Diag(OpRange.getBegin(), DiagID)
-            << SrcType << DestType << Sema::AA_Casting
-            << SrcExpr.get()->getSourceRange();
-        if (!Nested)
-          SrcExpr = ExprError();
-        return;
-      }
-
-      DestPtr = DestPPtr->getPointeeType().getTypePtr();
-      SrcPtr = SrcPPtr->getPointeeType().getTypePtr();
-      Nested = true;
-      DiagID = diag::ext_nested_pointer_qualifier_mismatch;
+  const Type *DestPtr, *SrcPtr;
+  bool Nested = false;
+  unsigned DiagID = diag::err_typecheck_incompatible_address_space;
+  DestPtr = Self.getASTContext().getCanonicalType(DestType.getTypePtr()),
+  SrcPtr  = Self.getASTContext().getCanonicalType(SrcType.getTypePtr());
+
+  while (isa<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;
   }
 }
 
@@ -2447,7 +2448,8 @@
   Sema::CheckedConversionKind CCK =
       FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast;
   if (tcr == TC_NotApplicable) {
-    tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg);
+    tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg,
+                              Kind);
     if (SrcExpr.isInvalid())
       return;
     if (tcr == TC_NotApplicable) {
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -8879,7 +8879,7 @@
       Qualifiers RHSPteeQual = RHSPointee.getQualifiers();
       // Blocks can't be an expression in a ternary operator (OpenCL v2.0
       // 6.12.5) thus the following check is asymmetric.
-      if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual))
+      if (!isAddressSpaceSupersetOf(LHSPteeQual, RHSPteeQual))
         return {};
       LHSPteeQual.removeAddressSpace();
       RHSPteeQual.removeAddressSpace();
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -741,6 +741,22 @@
     return UseAddrSpaceMapMangling;
   }
 
+  /// Return true if address space A is a superspace of B.
+  /// By default, all target address spaces are disjoint.
+  virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const {
+    return false;
+  }
+
+  /// Return true if an explicit cast from address space From to To is legal.
+  /// This lets targets override the behavior when neither address space is a
+  /// true superset of the other, but the target still wants explicit casting
+  /// between them.
+  /// By default, explicit casting between all target address spaces is
+  /// permitted.
+  virtual bool isExplicitAddrSpaceConversionLegal(LangAS From, LangAS To) const{
+    return true;
+  }
+
   ///===---- Other target property query methods --------------------------===//
 
   /// Appends the target-specific \#define values for this
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -460,40 +460,6 @@
     Mask |= qs.Mask;
   }
 
-  /// Returns true if this address space is a superset of the other one.
-  /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of
-  /// overlapping address spaces.
-  /// CL1.1 or CL1.2:
-  ///   every address space is a superset of itself.
-  /// CL2.0 adds:
-  ///   __generic is a superset of any address space except for __constant.
-  bool isAddressSpaceSupersetOf(Qualifiers other) const {
-    return
-        // Address spaces must match exactly.
-        getAddressSpace() == other.getAddressSpace() ||
-        // Otherwise in OpenCLC v2.0 s6.5.5: every address space except
-        // for __constant can be used as __generic.
-        (getAddressSpace() == LangAS::opencl_generic &&
-         other.getAddressSpace() != LangAS::opencl_constant);
-  }
-
-  /// Determines if these qualifiers compatibly include another set.
-  /// Generally this answers the question of whether an object with the other
-  /// qualifiers can be safely used as an object with these qualifiers.
-  bool compatiblyIncludes(Qualifiers other) const {
-    return isAddressSpaceSupersetOf(other) &&
-           // ObjC GC qualifiers can match, be added, or be removed, but can't
-           // be changed.
-           (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||
-            !other.hasObjCGCAttr()) &&
-           // ObjC lifetime qualifiers must match exactly.
-           getObjCLifetime() == other.getObjCLifetime() &&
-           // CVR qualifiers may subset.
-           (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) &&
-           // U qualifier may superset.
-           (!other.hasUnaligned() || hasUnaligned());
-  }
-
   /// Determines if these qualifiers compatibly include another set of
   /// qualifiers from the narrow perspective of Objective-C ARC lifetime.
   ///
@@ -908,14 +874,6 @@
   /// ASTContext::getUnqualifiedArrayType.
   inline SplitQualType getSplitUnqualifiedType() const;
 
-  /// Determine whether this type is more qualified than the other
-  /// given type, requiring exact equality for non-CVR qualifiers.
-  bool isMoreQualifiedThan(QualType Other) const;
-
-  /// Determine whether this type is at least as qualified as the other
-  /// given type, requiring exact equality for non-CVR qualifiers.
-  bool isAtLeastAsQualifiedAs(QualType Other) const;
-
   QualType getNonReferenceType() const;
 
   /// Determine the type of a (typically non-lvalue) expression with the
@@ -2561,22 +2519,6 @@
 public:
   QualType getPointeeType() const { return PointeeType; }
 
-  /// Returns true if address spaces of pointers overlap.
-  /// OpenCL v2.0 defines conversion rules for pointers to different
-  /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping
-  /// address spaces.
-  /// CL1.1 or CL1.2:
-  ///   address spaces overlap iff they are they same.
-  /// CL2.0 adds:
-  ///   __generic overlaps with any address space except for __constant.
-  bool isAddressSpaceOverlapping(const PointerType &other) const {
-    Qualifiers thisQuals = PointeeType.getQualifiers();
-    Qualifiers otherQuals = other.getPointeeType().getQualifiers();
-    // Address spaces overlap if at least one of them is a superset of another
-    return thisQuals.isAddressSpaceSupersetOf(otherQuals) ||
-           otherQuals.isAddressSpaceSupersetOf(thisQuals);
-  }
-
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
 
@@ -6255,31 +6197,6 @@
   return getFunctionExtInfo(*t);
 }
 
-/// Determine whether this type is more
-/// qualified than the Other type. For example, "const volatile int"
-/// is more qualified than "const int", "volatile int", and
-/// "int". However, it is not more qualified than "const volatile
-/// int".
-inline bool QualType::isMoreQualifiedThan(QualType other) const {
-  Qualifiers MyQuals = getQualifiers();
-  Qualifiers OtherQuals = other.getQualifiers();
-  return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals));
-}
-
-/// Determine whether this type is at last
-/// as qualified as the Other type. For example, "const volatile
-/// int" is at least as qualified as "const int", "volatile int",
-/// "int", and "const volatile int".
-inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const {
-  Qualifiers OtherQuals = other.getQualifiers();
-
-  // Ignore __unaligned qualifier if this type is a void.
-  if (getUnqualifiedType()->isVoidType())
-    OtherQuals.removeUnaligned();
-
-  return getQualifiers().compatiblyIncludes(OtherQuals);
-}
-
 /// If Type is a reference type (e.g., const
 /// int&), returns the type that the reference refers to ("const
 /// int"). Otherwise, returns the type itself. This routine is used
Index: include/clang/AST/CanonicalType.h
===================================================================
--- include/clang/AST/CanonicalType.h
+++ include/clang/AST/CanonicalType.h
@@ -162,18 +162,6 @@
     return Stored.withConst();
   }
 
-  /// Determines whether this canonical type is more qualified than
-  /// the @p Other canonical type.
-  bool isMoreQualifiedThan(CanQual<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: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -2350,6 +2350,49 @@
   /// Determine if two types are similar, ignoring only CVR qualifiers.
   bool hasCvrSimilarType(QualType T1, QualType T2);
 
+  /// Determines if the qualifiers A compatibly include another set B.
+  /// Generally this answers the question of whether an object with B's
+  /// qualifiers can be safely used as an object with A's qualifiers.
+  bool compatiblyIncludes(Qualifiers A, Qualifiers B) const {
+    return isAddressSpaceSupersetOf(A, B) &&
+           // ObjC GC qualifiers can match, be added, or be removed, but can't
+           // be changed.
+           (A.getObjCGCAttr() == B.getObjCGCAttr() || !A.hasObjCGCAttr() ||
+            !B.hasObjCGCAttr()) &&
+           // ObjC lifetime qualifiers must match exactly.
+           A.getObjCLifetime() == B.getObjCLifetime() &&
+           // CVR qualifiers may subset.
+           ((A.getCVRQualifiers() | B.getCVRQualifiers()) ==
+            A.getCVRQualifiers()) &&
+           // U qualifier may superset.
+           (!B.hasUnaligned() || A.hasUnaligned());
+  }
+
+  /// Determine whether the type A is more
+  /// qualified than the type B. For example, "const volatile int"
+  /// is more qualified than "const int", "volatile int", and
+  /// "int". However, it is not more qualified than "const volatile
+  /// int".
+  bool isMoreQualifiedThan(QualType A, QualType B) const {
+    Qualifiers AQuals = A.getQualifiers();
+    Qualifiers BQuals = B.getQualifiers();
+    return (AQuals != BQuals && compatiblyIncludes(AQuals, BQuals));
+  }
+
+  /// Determine whether the type A is at least
+  /// as qualified as the type B. For example, "const volatile
+  /// int" is at least as qualified as "const int", "volatile int",
+  /// "int", and "const volatile int".
+  bool isAtLeastAsQualifiedAs(QualType A, QualType B) const {
+    Qualifiers BQuals = B.getQualifiers();
+
+    // Ignore __unaligned qualifier if A is a void.
+    if (A.getUnqualifiedType()->isVoidType())
+      BQuals.removeUnaligned();
+
+    return compatiblyIncludes(A.getQualifiers(), BQuals);
+  }
+
   /// Retrieves the "canonical" nested name specifier for a
   /// given nested name specifier.
   ///
@@ -2528,6 +2571,60 @@
     return AddrSpaceMapMangling || isTargetAddressSpace(AS);
   }
 
+  /// Returns true if address space A is a superset of B.
+  bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const {
+    // All address spaces are supersets of themselves.
+    if (A == B)
+      return true;
+
+    // OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of
+    // overlapping address spaces.
+    // CL1.1 or CL1.2:
+    //   every address space is a superset of itself.
+    // CL2.0 adds:
+    //   __generic is a superset of any address space except for __constant.
+    if (A == LangAS::opencl_generic &&
+        B != LangAS::opencl_constant)
+      return true;
+
+    // Otherwise, ask the target.
+    return Target->isAddressSpaceSupersetOf(A, B);
+  }
+  bool isAddressSpaceSupersetOf(Qualifiers A, Qualifiers B) const {
+    return isAddressSpaceSupersetOf(A.getAddressSpace(), B.getAddressSpace());
+  }
+
+  /// Returns true if address space A overlaps with B.
+  bool isAddressSpaceOverlapping(LangAS A, LangAS B) const {
+    // A overlaps with B if either is a superset of the other.
+    return isAddressSpaceSupersetOf(A, B) ||
+           isAddressSpaceSupersetOf(B, A);
+  }
+  bool isAddressSpaceOverlapping(Qualifiers A, Qualifiers B) const {
+    return isAddressSpaceOverlapping(A.getAddressSpace(), B.getAddressSpace());
+  }
+
+  /// Returns true if an explicit cast from address space A to B is legal.
+  bool isExplicitAddrSpaceConversionLegal(LangAS From, LangAS To) const {
+    // If From and To overlap, the cast is legal.
+    if (isAddressSpaceOverlapping(From, To))
+      return true;
+
+    // Or, if either From or To are target address spaces, the target can
+    // decide whether or not to allow the cast regardless of overlap.
+    if (isTargetAddressSpace(From) || isTargetAddressSpace(To) ||
+        From == LangAS::Default || To == LangAS::Default)
+      return Target->isExplicitAddrSpaceConversionLegal(From, To);
+
+    // Otherwise, the cast is illegal.
+    return false;
+  }
+  bool isExplicitAddrSpaceConversionLegal(Qualifiers From,
+                                          Qualifiers To) const {
+    return isExplicitAddrSpaceConversionLegal(From.getAddressSpace(),
+                                              To.getAddressSpace());
+  }
+
 private:
   // Helper for integer ordering
   unsigned getIntegerRank(const Type *T) const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to