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 @@ -6168,27 +6167,69 @@ 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 - A pointer to address space A can only be assigned + // to a pointer to the same address space A. Casting a pointer to address + // space A to a pointer to address space B is illegal. + // 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/condition-operator-cl2.0.cl =================================================================== --- /dev/null +++ test/SemaOpenCL/condition-operator-cl2.0.cl @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DCONSTANT -cl-std=CL2.0 +// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGLOBAL -cl-std=CL2.0 +// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGENERIC -cl-std=CL2.0 + +// Testing conditional operator with second and third operands of pointer types. + +#ifdef GENERIC +#define AS generic +#endif + +#ifdef GLOBAL +#define AS global +#endif + +#ifdef CONSTANT +#define AS constant +#endif + +void test_conversion(global int *arg_glob, local int *arg_loc, + constant int *arg_const, private int *arg_priv, + generic int *arg_gen, global char *arg_glob_ch, + local char *arg_loc_ch, constant char *arg_const_ch, + private char *arg_priv_ch, generic char *arg_gen_ch) { + + AS int *var_cond; + 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 + + arg_gen = 0 ? var_cond : arg_loc; +#ifdef CONSTANT +// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__local int *') which are pointers to non-overlapping address spaces}} +#elif defined(GLOBAL) +// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__local int *') which are pointers to non-overlapping address spaces}} +#endif + + var_cond = 0 ? var_cond : arg_const; +#ifdef GENERIC +// expected-error@-2{{conditional operator with the second and third operands of type ('__generic int *' and '__constant int *') which are pointers to non-overlapping address spaces}} +#elif defined(GLOBAL) +// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__constant int *') which are pointers to non-overlapping address spaces}} +#endif + + arg_gen = 0 ? var_cond : arg_priv; +#ifdef CONSTANT +// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and 'int *') which are pointers to non-overlapping address spaces}} +#elif defined(GLOBAL) +// expected-error@-4{{conditional operator with the second and third operands of type ('__global 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; + constant void*var_void_const; + 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 + + var_void_gen = 0 ? var_cond : arg_loc_ch; +#ifdef CONSTANT +// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__local char *') which are pointers to non-overlapping address spaces}} +#elif defined(GLOBAL) +// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__local char *') which are pointers to non-overlapping address spaces}} +#endif + + var_void_const = 0 ? var_cond : arg_const_ch; +#ifdef GENERIC +// expected-error@-2{{conditional operator with the second and third operands of type ('__generic int *' and '__constant char *') which are pointers to non-overlapping address spaces}} +#elif defined(GLOBAL) +// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and '__constant char *') which are pointers to non-overlapping address spaces}} +#endif + + var_void_gen = 0 ? var_cond : arg_priv_ch; +#ifdef CONSTANT +// expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and 'char *') which are pointers to non-overlapping address spaces}} +#elif defined(GLOBAL) +// expected-error@-4{{conditional operator with the second and third operands of type ('__global int *' and 'char *') which are pointers to non-overlapping address spaces}} +#endif + + 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 +}