Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -6271,6 +6271,10 @@ def err_bad_cxx_cast_qualifiers_away : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 casts away qualifiers">; +def err_bad_cxx_cast_addr_space_mismatch : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 converts between mismatching address" + " spaces">; def ext_bad_cxx_cast_qualifiers_away_incoherent : ExtWarn< "ISO C++ does not allow " "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" Index: cfe/trunk/lib/Sema/SemaCast.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCast.cpp +++ cfe/trunk/lib/Sema/SemaCast.cpp @@ -2212,7 +2212,15 @@ /*CheckObjCLifetime=*/CStyle)) SuccessResult = getCastAwayConstnessCastKind(CACK, msg); - if (IsLValueCast) { + if (IsAddressSpaceConversion(SrcType, DestType)) { + Kind = CK_AddressSpaceConversion; + assert(SrcType->isPointerType() && DestType->isPointerType()); + if (!CStyle && + !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf( + SrcType->getPointeeType().getQualifiers())) { + SuccessResult = TC_Failed; + } + } else if (IsLValueCast) { Kind = CK_LValueBitCast; } else if (DestType->isObjCObjectPointerType()) { Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr); @@ -2222,8 +2230,6 @@ } else { Kind = CK_BitCast; } - } else if (IsAddressSpaceConversion(SrcType, DestType)) { - Kind = CK_AddressSpaceConversion; } else { Kind = CK_BitCast; } @@ -2278,6 +2284,41 @@ return SuccessResult; } +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. + auto SrcType = SrcExpr.get()->getType(); + auto SrcPtrType = SrcType->getAs(); + if (!SrcPtrType) + return TC_NotApplicable; + auto DestPtrType = DestType->getAs(); + if (!DestPtrType) + return TC_NotApplicable; + auto SrcPointeeType = SrcPtrType->getPointeeType(); + auto DestPointeeType = DestPtrType->getPointeeType(); + if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()) + return TC_NotApplicable; + if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { + msg = diag::err_bad_cxx_cast_addr_space_mismatch; + return TC_Failed; + } + auto SrcPointeeTypeWithoutAS = + Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType()); + auto DestPointeeTypeWithoutAS = + Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType()); + return Self.Context.hasSameType(SrcPointeeTypeWithoutAS, + DestPointeeTypeWithoutAS) + ? TC_Success + : TC_NotApplicable; +} + void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { // In OpenCL only conversions between pointers to objects in overlapping // addr spaces are allowed. v2.0 s6.5.5 - Generic addr space overlaps @@ -2372,30 +2413,35 @@ // listed above, the interpretation that appears first in the list is used, // even if a cast resulting from that interpretation is ill-formed. // In plain language, this means trying a const_cast ... + // Note that for address space we check compatibility after const_cast. unsigned msg = diag::err_bad_cxx_cast_generic; TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType, - /*CStyle*/true, msg); + /*CStyle*/ true, msg); if (SrcExpr.isInvalid()) return; if (isValidCast(tcr)) Kind = CK_NoOp; - Sema::CheckedConversionKind CCK - = FunctionalStyle? Sema::CCK_FunctionalCast - : Sema::CCK_CStyleCast; + Sema::CheckedConversionKind CCK = + FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { - // ... or if that is not possible, a static_cast, ignoring const, ... - tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, - msg, Kind, BasePath, ListInitialization); + tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg); if (SrcExpr.isInvalid()) return; - if (tcr == TC_NotApplicable) { - // ... and finally a reinterpret_cast, ignoring const. - tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true, - OpRange, msg, Kind); + // ... or if that is not possible, a static_cast, ignoring const, ... + tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind, + BasePath, ListInitialization); if (SrcExpr.isInvalid()) return; + + if (tcr == TC_NotApplicable) { + // ... and finally a reinterpret_cast, ignoring const. + tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true, + OpRange, msg, Kind); + if (SrcExpr.isInvalid()) + return; + } } } @@ -2426,8 +2472,6 @@ } } - checkAddressSpaceCast(SrcExpr.get()->getType(), DestType); - if (isValidCast(tcr)) { if (Kind == CK_BitCast) checkCastAlign(); Index: cfe/trunk/test/CodeGenOpenCLCXX/address-space-castoperators.cpp =================================================================== --- cfe/trunk/test/CodeGenOpenCLCXX/address-space-castoperators.cpp +++ cfe/trunk/test/CodeGenOpenCLCXX/address-space-castoperators.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s + +void test_reinterpret_cast(){ +__private float x; +__private float& y = x; +// We don't need bitcast to cast pointer type and +// address space at the same time. +//CHECK: addrspacecast float* %x to i32 addrspace(4)* +//CHECK: [[REG:%[0-9]+]] = load float*, float** %y +//CHECK: addrspacecast float* [[REG]] to i32 addrspace(4)* +//CHECK-NOT: bitcast +__generic int& rc1 = reinterpret_cast<__generic int&>(x); +__generic int& rc2 = reinterpret_cast<__generic int&>(y); +} Index: cfe/trunk/test/SemaCXX/address-space-conversion.cpp =================================================================== --- cfe/trunk/test/SemaCXX/address-space-conversion.cpp +++ cfe/trunk/test/SemaCXX/address-space-conversion.cpp @@ -131,24 +131,24 @@ void test_reinterpret_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2, A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2, B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2, - const void __attribute__((address_space(1))) *cvp1) { - // reinterpret_cast can be used to cast to a different address space. - (void)reinterpret_cast(ap1); - (void)reinterpret_cast(ap2); + const void __attribute__((address_space(1))) * cvp1) { + // reinterpret_cast can't be used to cast to a different address space unless they are matching (i.e. overlapping). + (void)reinterpret_cast(ap1); // expected-error{{reinterpret_cast from 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') to 'A_ptr' (aka 'A *') is not allowed}} + (void)reinterpret_cast(ap2); // expected-error{{reinterpret_cast from 'A_ptr_2' (aka '__attribute__((address_space(2))) A *') to 'A_ptr' (aka 'A *') is not allowed}} (void)reinterpret_cast(bp); - (void)reinterpret_cast(bp1); - (void)reinterpret_cast(bp2); + (void)reinterpret_cast(bp1); // expected-error{{reinterpret_cast from 'B_ptr_1' (aka '__attribute__((address_space(1))) B *') to 'A_ptr' (aka 'A *') is not allowed}} + (void)reinterpret_cast(bp2); // expected-error{{reinterpret_cast from 'B_ptr_2' (aka '__attribute__((address_space(2))) B *') to 'A_ptr' (aka 'A *') is not allowed}} (void)reinterpret_cast(vp); - (void)reinterpret_cast(vp1); - (void)reinterpret_cast(vp2); - (void)reinterpret_cast(ap); - (void)reinterpret_cast(ap2); - (void)reinterpret_cast(bp); + (void)reinterpret_cast(vp1); // expected-error{{reinterpret_cast from 'void_ptr_1' (aka '__attribute__((address_space(1))) void *') to 'A_ptr' (aka 'A *') is not allowed}} + (void)reinterpret_cast(vp2); // expected-error{{reinterpret_cast from 'void_ptr_2' (aka '__attribute__((address_space(2))) void *') to 'A_ptr' (aka 'A *') is not allowed}} + (void)reinterpret_cast(ap); // expected-error{{reinterpret_cast from 'A_ptr' (aka 'A *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (void)reinterpret_cast(ap2); // expected-error{{reinterpret_cast from 'A_ptr_2' (aka '__attribute__((address_space(2))) A *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (void)reinterpret_cast(bp); // expected-error{{reinterpret_cast from 'B_ptr' (aka 'B *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} (void)reinterpret_cast(bp1); - (void)reinterpret_cast(bp2); - (void)reinterpret_cast(vp); + (void)reinterpret_cast(bp2); // expected-error{{reinterpret_cast from 'B_ptr_2' (aka '__attribute__((address_space(2))) B *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} + (void)reinterpret_cast(vp); // expected-error{{reinterpret_cast from 'void_ptr' (aka 'void *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} (void)reinterpret_cast(vp1); - (void)reinterpret_cast(vp2); + (void)reinterpret_cast(vp2); // expected-error{{reinterpret_cast from 'void_ptr_2' (aka '__attribute__((address_space(2))) void *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}} // ... but don't try to cast away constness! (void)reinterpret_cast(cvp1); // expected-error{{casts away qualifiers}} Index: cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl =================================================================== --- cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl +++ cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl @@ -129,27 +129,47 @@ AS int *var_cast1 = (AS int *)arg_glob; #ifdef CONSTANT -// expected-error@-2{{casting '__global int *' to type '__constant int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error@-3{{casting '__global int *' to type '__constant int *' changes address space of pointer}} +#else +// expected-error@-5{{C-style cast from '__global int *' to '__constant int *' converts between mismatching address spaces}} +#endif #endif AS int *var_cast2 = (AS int *)arg_loc; #ifndef GENERIC -// expected-error-re@-2{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error-re@-3{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#else +// expected-error-re@-5{{C-style cast from '__local int *' to '__{{global|constant}} int *' converts between mismatching address spaces}} +#endif #endif AS int *var_cast3 = (AS int *)arg_const; #ifndef CONSTANT -// expected-error-re@-2{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error-re@-3{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}} +#else +// expected-error-re@-5{{C-style cast from '__constant int *' to '__{{global|generic}} int *' converts between mismatching address spaces}} +#endif #endif AS int *var_cast4 = (AS int *)arg_priv; #ifndef GENERIC -// expected-error-re@-2{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error-re@-3{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#else +// expected-error-re@-5{{C-style cast from 'int *' to '__{{global|constant}} int *' converts between mismatching address spaces}} +#endif #endif AS int *var_cast5 = (AS int *)arg_gen; #ifdef CONSTANT -// expected-error@-2{{casting '__generic int *' to type '__constant int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error@-3{{casting '__generic int *' to type '__constant int *' changes address space of pointer}} +#else +// expected-error@-5{{C-style cast from '__generic int *' to '__constant int *' converts between mismatching address spaces}} +#endif #endif AS int *var_impl; @@ -200,27 +220,47 @@ var_cast1 = (AS int *)arg_glob; #ifdef CONSTANT -// expected-error@-2{{casting '__global int *' to type '__constant int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error@-3{{casting '__global int *' to type '__constant int *' changes address space of pointer}} +#else +// expected-error@-5{{C-style cast from '__global int *' to '__constant int *' converts between mismatching address spaces}} +#endif #endif var_cast2 = (AS int *)arg_loc; #ifndef GENERIC -// expected-error-re@-2{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error-re@-3{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#else +// expected-error-re@-5{{C-style cast from '__local int *' to '__{{global|constant}} int *' converts between mismatching address spaces}} +#endif #endif var_cast3 = (AS int *)arg_const; #ifndef CONSTANT -// expected-error-re@-2{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error-re@-3{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}} +#else +// expected-error-re@-5{{C-style cast from '__constant int *' to '__{{global|generic}} int *' converts between mismatching address spaces}} +#endif #endif var_cast4 = (AS int *)arg_priv; #ifndef GENERIC -// expected-error-re@-2{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error-re@-3{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}} +#else +// expected-error-re@-5{{C-style cast from 'int *' to '__{{global|constant}} int *' converts between mismatching address spaces}} +#endif #endif var_cast5 = (AS int *)arg_gen; #ifdef CONSTANT -// expected-error@-2{{casting '__generic int *' to type '__constant int *' changes address space of pointer}} +#if !__OPENCL_CPP_VERSION__ +// expected-error@-3{{casting '__generic int *' to type '__constant int *' changes address space of pointer}} +#else +// expected-error@-5{{C-style cast from '__generic int *' to '__constant int *' converts between mismatching address spaces}} +#endif #endif AS int *var_cmp; Index: cfe/trunk/test/SemaOpenCL/address-spaces.cl =================================================================== --- cfe/trunk/test/SemaOpenCL/address-spaces.cl +++ cfe/trunk/test/SemaOpenCL/address-spaces.cl @@ -26,24 +26,96 @@ } void explicit_cast(__global int *g, __local int *l, __constant int *c, __private int *p, const __constant int *cc) { - g = (__global int *)l; // expected-error {{casting '__local int *' to type '__global int *' changes address space of pointer}} - g = (__global int *)c; // expected-error {{casting '__constant int *' to type '__global int *' changes address space of pointer}} - g = (__global int *)cc; // expected-error {{casting 'const __constant int *' to type '__global int *' changes address space of pointer}} - g = (__global int *)p; // expected-error {{casting 'int *' to type '__global int *' changes address space of pointer}} - - l = (__local int *)g; // expected-error {{casting '__global int *' to type '__local int *' changes address space of pointer}} - l = (__local int *)c; // expected-error {{casting '__constant int *' to type '__local int *' changes address space of pointer}} - l = (__local int *)cc; // expected-error {{casting 'const __constant int *' to type '__local int *' changes address space of pointer}} - l = (__local int *)p; // expected-error {{casting 'int *' to type '__local int *' changes address space of pointer}} - - c = (__constant int *)g; // expected-error {{casting '__global int *' to type '__constant int *' changes address space of pointer}} - c = (__constant int *)l; // expected-error {{casting '__local int *' to type '__constant int *' changes address space of pointer}} - c = (__constant int *)p; // expected-error {{casting 'int *' to type '__constant int *' changes address space of pointer}} - - p = (__private int *)g; // expected-error {{casting '__global int *' to type 'int *' changes address space of pointer}} - p = (__private int *)l; // expected-error {{casting '__local int *' to type 'int *' changes address space of pointer}} - p = (__private int *)c; // expected-error {{casting '__constant int *' to type 'int *' changes address space of pointer}} - p = (__private int *)cc; // expected-error {{casting 'const __constant int *' to type 'int *' changes address space of pointer}} + g = (__global int *)l; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__local int *' to type '__global int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__local int *' to '__global int *' converts between mismatching address spaces}} +#endif + g = (__global int *)c; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__constant int *' to type '__global int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__constant int *' to '__global int *' converts between mismatching address spaces}} +#endif + g = (__global int *)cc; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting 'const __constant int *' to type '__global int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from 'const __constant int *' to '__global int *' converts between mismatching address spaces}} +#endif + g = (__global int *)p; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting 'int *' to type '__global int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from 'int *' to '__global int *' converts between mismatching address spaces}} +#endif + l = (__local int *)g; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__global int *' to type '__local int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__global int *' to '__local int *' converts between mismatching address spaces}} +#endif + l = (__local int *)c; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__constant int *' to type '__local int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__constant int *' to '__local int *' converts between mismatching address spaces}} +#endif + l = (__local int *)cc; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting 'const __constant int *' to type '__local int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from 'const __constant int *' to '__local int *' converts between mismatching address spaces}} +#endif + l = (__local int *)p; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting 'int *' to type '__local int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from 'int *' to '__local int *' converts between mismatching address spaces}} +#endif + c = (__constant int *)g; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__global int *' to type '__constant int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__global int *' to '__constant int *' converts between mismatching address spaces}} +#endif + c = (__constant int *)l; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__local int *' to type '__constant int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__local int *' to '__constant int *' converts between mismatching address spaces}} +#endif + c = (__constant int *)p; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting 'int *' to type '__constant int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from 'int *' to '__constant int *' converts between mismatching address spaces}} +#endif + p = (__private int *)g; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__global int *' to type 'int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__global int *' to 'int *' converts between mismatching address spaces}} +#endif + p = (__private int *)l; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__local int *' to type 'int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__local int *' to 'int *' converts between mismatching address spaces}} +#endif + p = (__private int *)c; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting '__constant int *' to type 'int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from '__constant int *' to 'int *' converts between mismatching address spaces}} +#endif + p = (__private int *)cc; +#if !__OPENCL_CPP_VERSION__ +// expected-error@-2 {{casting 'const __constant int *' to type 'int *' changes address space of pointer}} +#else +// expected-error@-4 {{C-style cast from 'const __constant int *' to 'int *' converts between mismatching address spaces}} +#endif } void ok_explicit_casts(__global int *g, __global int *g2, __local int *l, __local int *l2, __private int *p, __private int *p2) {