diff options
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 147 |
1 files changed, 84 insertions, 63 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e422fe02263..88f32bb6b3b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6335,92 +6335,98 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, 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; @@ -7399,7 +7405,22 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType, 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; |

