Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -5325,7 +5325,9 @@ "composite pointer type %2">, InGroup; def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error< "%select{comparison between %diff{ ($ and $)|}0,1" - "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1}2" + "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1" + "|conditional operator with the second and third operands of type " + "%diff{ ($ and $)|}0,1}2" " which are pointers to non-overlapping address spaces">; def err_typecheck_assign_const : Error< Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -7609,6 +7609,15 @@ Qualifiers LQuals = LHSCan.getLocalQualifiers(); Qualifiers RQuals = RHSCan.getLocalQualifiers(); if (LQuals != RQuals) { + if (getLangOpts().OpenCL) { + if (LHS.getUnqualifiedType() != RHS.getUnqualifiedType() || + LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers()) + return QualType(); + if (LQuals.isAddressSpaceSupersetOf(RQuals)) + return LHS; + if (RQuals.isAddressSpaceSupersetOf(LQuals)) + return RHS; + } // If any of these qualifiers are different, we have a type // mismatch. if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -171,7 +171,6 @@ // Don't do this for enums, they can't be redeclared. if (isa(D) || isa(D)) break; - bool Warn = !AA->isInherited(); // Objective-C method declarations in categories are not modelled as // redeclarations, so manually look for a redeclaration in a category @@ -6165,30 +6164,80 @@ 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 QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); if (CompositeTy.isNull()) { - S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); // 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 = S.Context.getPointerType(S.Context.VoidTy); - LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast); + QualType incompatTy; + if (S.getLangOpts().OpenCL) { + // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address + // spaces is disallowed. + // OpenCL v2.0 s6.5.6 - Clause 6.5.15 Conditional operator, add another + // constraint paragraph: If the second and third operands are pointers + // into different address spaces, the address spaces must overlap. + unsigned ResultAddrSpace; + if (lhQual.isAddressSpaceSupersetOf(rhQual)) { + ResultAddrSpace = lhQual.getAddressSpace(); + } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) { + ResultAddrSpace = rhQual.getAddressSpace(); + } else { + S.Diag(Loc, + diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) + << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + incompatTy = S.Context.getPointerType( + S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); + LHS = S.ImpCastExprToType(LHS.get(), incompatTy, + (lhQual.getAddressSpace() != ResultAddrSpace) + ? CK_AddressSpaceConversion + : CK_BitCast); + RHS = S.ImpCastExprToType(RHS.get(), incompatTy, + (rhQual.getAddressSpace() != ResultAddrSpace) + ? CK_AddressSpaceConversion + : CK_BitCast); + } 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); + } return incompatTy; } // The pointer types are compatible. QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual); + auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast; if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); - else + else { + auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace(); + LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace + ? CK_BitCast + : CK_AddressSpaceConversion; + RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace + ? CK_BitCast + : CK_AddressSpaceConversion; ResultTy = S.Context.getPointerType(ResultTy); + } - LHS = S.ImpCastExprToType(LHS.get(), ResultTy, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), ResultTy, CK_BitCast); + LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); + RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); return ResultTy; } Index: test/CodeGenOpenCL/address-spaces-conversions.cl =================================================================== --- test/CodeGenOpenCL/address-spaces-conversions.cl +++ test/CodeGenOpenCL/address-spaces-conversions.cl @@ -3,20 +3,35 @@ // test that we generate address space casts everywhere we need conversions of // pointers to different address spaces -void test(global int *arg_glob, generic int *arg_gen) { +void test(global int *arg_glob, generic int *arg_gen, global float *arg_glob_f, + generic void *arg_gen_v) { int var_priv; + arg_gen = arg_glob; // implicit cast global -> generic // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)* + arg_gen = &var_priv; // implicit cast with obtaining adr, private -> generic // CHECK: %{{[0-9]+}} = addrspacecast i32* %var_priv to i32 addrspace(4)* + arg_glob = (global int *)arg_gen; // explicit cast // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(4)* %{{[0-9]+}} to i32 addrspace(1)* + global int *var_glob = (global int *)arg_glob; // explicit cast in the same address space // CHECK-NOT: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(1)* + var_priv = arg_gen - arg_glob; // arithmetic operation // CHECK: %{{.*}} = ptrtoint i32 addrspace(4)* %{{.*}} to i64 // CHECK: %{{.*}} = ptrtoint i32 addrspace(1)* %{{.*}} to i64 + var_priv = arg_gen > arg_glob; // comparison // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)* + + // condition operator + arg_gen = arg_glob ? arg_gen : arg_glob; // operands of overlapping addr spaces and the same type + // CHECK: %{{[0-9]+}} = addrspacecast i32 addrspace(1)* %{{[0-9]+}} to i32 addrspace(4)* + + arg_gen_v = arg_glob ? arg_gen : arg_glob_f; // operands of overlapping addr spaces and different types + // CHECK: %{{[0-9]+}} = bitcast i32 addrspace(4)* %{{[0-9]+}} to i8 addrspace(4)* + // CHECK: %{{[0-9]+}} = addrspacecast float addrspace(1)* %{{[0-9]+}} to i8 addrspace(4)* } Index: test/SemaOpenCL/address-spaces-conversions-cl2.0.cl =================================================================== --- test/SemaOpenCL/address-spaces-conversions-cl2.0.cl +++ test/SemaOpenCL/address-spaces-conversions-cl2.0.cl @@ -225,3 +225,69 @@ // expected-error@-2{{passing '__constant int *' to parameter of type '__generic int *' changes address space of pointer}} #endif } + +void test_ternary() { + AS int *var_cond; + generic int *arg_gen; + global int *arg_glob; + arg_gen = 0 ? var_cond : arg_glob; +#ifdef CONSTANT +// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__global int *') which are pointers to non-overlapping address spaces}} +#endif + + local int *arg_loc; + arg_gen = 0 ? var_cond : arg_loc; +#ifndef GENERIC +// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and '__local int *') which are pointers to non-overlapping address spaces}} +#endif + + constant int *arg_const; + var_cond = 0 ? var_cond : arg_const; +#ifndef CONSTANT +// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|generic}} int *' and '__constant int *') which are pointers to non-overlapping address spaces}} +#endif + + private int *arg_priv; + arg_gen = 0 ? var_cond : arg_priv; +#ifndef GENERIC +// expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and 'int *') which are pointers to non-overlapping address spaces}} +#endif + + arg_gen = 0 ? var_cond : arg_gen; +#ifdef CONSTANT +// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic int *') which are pointers to non-overlapping address spaces}} +#endif + + void *var_void_gen; + global char *arg_glob_ch; + var_void_gen = 0 ? var_cond : arg_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}} +#endif + + local char *arg_loc_ch; + var_void_gen = 0 ? var_cond : arg_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}} +#endif + + constant void *var_void_const; + constant char *arg_const_ch; + var_void_const = 0 ? var_cond : arg_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}} +#endif + + private char *arg_priv_ch; + var_void_gen = 0 ? var_cond : arg_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}} +#endif + + generic char *arg_gen_ch; + var_void_gen = 0 ? var_cond : arg_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}} +#endif +} +