Qualifiers lhQual = lhptee.getQualifiers();
Qualifiers rhQual = rhptee.getQualifiers();
+ unsigned ResultAddrSpace = 0;
+ unsigned LAddrSpace = lhQual.getAddressSpace();
+ unsigned RAddrSpace = rhQual.getAddressSpace();
+ if (S.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
+ // spaces is disallowed.
+ if (lhQual.isAddressSpaceSupersetOf(rhQual))
+ ResultAddrSpace = LAddrSpace;
+ else if (rhQual.isAddressSpaceSupersetOf(lhQual))
+ ResultAddrSpace = RAddrSpace;
+ else {
+ S.Diag(Loc,
+ diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
+ << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+ }
+
unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers();
+ auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast;
lhQual.removeCVRQualifiers();
rhQual.removeCVRQualifiers();
+ // OpenCL v2.0 specification doesn't extend compatibility of type qualifiers
+ // (C99 6.7.3) for address spaces. We assume that the check should behave in
+ // the same manner as it's defined for CVR qualifiers, so for OpenCL two
+ // qual types are compatible iff
+ // * corresponded types are compatible
+ // * CVR qualifiers are equal
+ // * address spaces are equal
+ // Thus for conditional operator we merge CVR and address space unqualified
+ // pointees and if there is a composite type we return a pointer to it with
+ // merged qualifiers.
+ if (S.getLangOpts().OpenCL) {
+ LHSCastKind = LAddrSpace == ResultAddrSpace
+ ? CK_BitCast
+ : CK_AddressSpaceConversion;
+ RHSCastKind = RAddrSpace == ResultAddrSpace
+ ? CK_BitCast
+ : CK_AddressSpaceConversion;
+ lhQual.removeAddressSpace();
+ rhQual.removeAddressSpace();
+ }
+
lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual);
rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual);
- // For OpenCL:
- // 1. If LHS and RHS types match exactly and:
- // (a) AS match => use standard C rules, no bitcast or addrspacecast
- // (b) AS overlap => generate addrspacecast
- // (c) AS don't overlap => give an error
- // 2. if LHS and RHS types don't match:
- // (a) AS match => use standard C rules, generate bitcast
- // (b) AS overlap => generate addrspacecast instead of bitcast
- // (c) AS don't overlap => give an error
-
- // For OpenCL, non-null composite type is returned only for cases 1a and 1b.
QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
- // OpenCL cases 1c, 2a, 2b, and 2c.
if (CompositeTy.isNull()) {
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy;
- if (S.getLangOpts().OpenCL) {
- // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
- // spaces is disallowed.
- unsigned ResultAddrSpace;
- if (lhQual.isAddressSpaceSupersetOf(rhQual)) {
- // Cases 2a and 2b.
- ResultAddrSpace = lhQual.getAddressSpace();
- } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) {
- // Cases 2a and 2b.
- ResultAddrSpace = rhQual.getAddressSpace();
- } else {
- // Cases 1c and 2c.
- S.Diag(Loc,
- diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
- << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
- return QualType();
- }
-
- // Continue handling cases 2a and 2b.
- incompatTy = S.Context.getPointerType(
- S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace));
- LHS = S.ImpCastExprToType(LHS.get(), incompatTy,
- (lhQual.getAddressSpace() != ResultAddrSpace)
- ? CK_AddressSpaceConversion /* 2b */
- : CK_BitCast /* 2a */);
- RHS = S.ImpCastExprToType(RHS.get(), incompatTy,
- (rhQual.getAddressSpace() != ResultAddrSpace)
- ? CK_AddressSpaceConversion /* 2b */
- : CK_BitCast /* 2a */);
- } else {
- S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
- incompatTy = S.Context.getPointerType(S.Context.VoidTy);
- LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
- }
+ incompatTy = S.Context.getPointerType(
+ S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace));
+ LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind);
+ RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind);
+ // FIXME: For OpenCL the warning emission and cast to void* leaves a room
+ // for casts between types with incompatible address space qualifiers.
+ // For the following code the compiler produces casts between global and
+ // local address spaces of the corresponded innermost pointees:
+ // local int *global *a;
+ // global int *global *b;
+ // a = (0 ? a : b); // see C99 6.5.16.1.p1.
+ S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
+ << LHSTy << RHSTy << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
return incompatTy;
}
// The pointer types are compatible.
- QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual);
- auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast;
+ // In case of OpenCL ResultTy should have the address space qualifier
+ // which is a superset of address spaces of both the 2nd and the 3rd
+ // operands of the conditional operator.
+ QualType ResultTy = [&, ResultAddrSpace]() {
+ if (S.getLangOpts().OpenCL) {
+ Qualifiers CompositeQuals = CompositeTy.getQualifiers();
+ CompositeQuals.setAddressSpace(ResultAddrSpace);
+ return S.Context
+ .getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals)
+ .withCVRQualifiers(MergedCVRQual);
+ } else
+ return CompositeTy.withCVRQualifiers(MergedCVRQual);
+ }();
if (IsBlockPointer)
ResultTy = S.Context.getBlockPointerType(ResultTy);
else {
- // Cases 1a and 1b for OpenCL.
- auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace();
- LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace
- ? CK_BitCast /* 1a */
- : CK_AddressSpaceConversion /* 1b */;
- RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace
- ? CK_BitCast /* 1a */
- : CK_AddressSpaceConversion /* 1b */;
ResultTy = S.Context.getPointerType(ResultTy);
}
- // For case 1a of OpenCL, S.ImpCastExprToType will not insert bitcast
- // if the target type does not change.
LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind);
RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind);
return ResultTy;
if (LQuals != RQuals)
ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
- if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType))
+ // FIXME: OpenCL doesn't define the exact compile time semantics for a block
+ // assignment.
+ // The current behavior is similar to C++ lambdas. A block might be
+ // assigned to a variable iff its return type and parameters are compatible
+ // (C99 6.2.7) with the corresponding return type and parameters of the LHS of
+ // an assignment. Presumably it should behave in way that a function pointer
+ // assignment does in C, so for each parameter and return type:
+ // * CVR and address space of LHS should be a superset of CVR and address
+ // space of RHS.
+ // * unqualified types should be compatible.
+ if (S.getLangOpts().OpenCL) {
+ if (!S.Context.typesAreBlockPointerCompatible(
+ S.Context.getQualifiedType(LHSType.getUnqualifiedType(), LQuals),
+ S.Context.getQualifiedType(RHSType.getUnqualifiedType(), RQuals)))
+ return Sema::IncompatibleBlockPointer;
+ } else if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType))
return Sema::IncompatibleBlockPointer;
return ConvTy;
#ifdef GENERIC
#define AS generic
+#define AS_COMP local
+#define AS_INCOMP constant
#endif
#ifdef GLOBAL
#define AS global
+#define AS_COMP global
+#define AS_INCOMP local
#endif
#ifdef CONSTANT
#define AS constant
+#define AS_COMP constant
+#define AS_INCOMP global
#endif
void f_glob(global int *arg_glob) {}
var_void_gen = 0 ? var_cond : var_glob_ch;
#ifdef CONSTANT
// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__global char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning-re@-4{{pointer type mismatch ('__{{global|generic}} int *' and '__global char *')}}
#endif
local char *var_loc_ch;
var_void_gen = 0 ? var_cond : var_loc_ch;
#ifndef GENERIC
// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and '__local char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning@-4{{pointer type mismatch ('__generic int *' and '__local char *')}}
#endif
constant void *var_void_const;
var_void_const = 0 ? var_cond : var_const_ch;
#ifndef CONSTANT
// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|generic}} int *' and '__constant char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning@-4{{pointer type mismatch ('__constant int *' and '__constant char *')}}
#endif
private char *var_priv_ch;
var_void_gen = 0 ? var_cond : var_priv_ch;
#ifndef GENERIC
// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and 'char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning@-4{{pointer type mismatch ('__generic int *' and 'char *')}}
#endif
generic char *var_gen_ch;
var_void_gen = 0 ? var_cond : var_gen_ch;
#ifdef CONSTANT
// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic char *') which are pointers to non-overlapping address spaces}}
+#else
+// expected-warning-re@-4{{pointer type mismatch ('__{{global|generic}} int *' and '__generic char *')}}
#endif
}
+void test_pointer_chains() {
+ AS int *AS *var_as_as_int;
+ AS int *AS_COMP *var_asc_as_int;
+ AS_INCOMP int *AS_COMP *var_asc_asn_int;
+ AS_COMP int *AS_COMP *var_asc_asc_int;
+
+ // Case 1:
+ // * address spaces of corresponded most outer pointees overlaps, their canonical types are equal
+ // * CVR, address spaces and canonical types of the rest of pointees are equivalent.
+ var_as_as_int = 0 ? var_as_as_int : var_asc_as_int;
+
+ // Case 2: Corresponded inner pointees has non-overlapping address spaces.
+ var_as_as_int = 0 ? var_as_as_int : var_asc_asn_int;
+// expected-warning-re@-1{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(constant|local|global)}} *')}}
+
+ // Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces.
+#ifdef GENERIC
+ var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int;
+// expected-warning-re@-1{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(local|global|constant)}} *')}}
+#endif
+}