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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits