Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit d8ac2ca

Browse files
author
Anastasia Stulova
committed
[Sema] Change addr space diagnostics in casts to follow C++ style.
This change adds a new diagnostic for mismatching address spaces to be used for C++ casts (only enabled in C style cast for now, the rest will follow!). The change extends C-style cast rules to account for address spaces. It also adds a separate function for address space cast checking that can be used to map from a separate address space cast operator addrspace_cast (to be added as a follow up patch). Note, that after this change clang will no longer allows arbitrary address space conversions in reinterpret_casts because they can lead to accidental errors. The implicit safe conversions would still be allowed. Differential Revision: https://reviews.llvm.org/D58346 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@355609 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent f384fbb commit d8ac2ca

File tree

6 files changed

+232
-58
lines changed

6 files changed

+232
-58
lines changed

include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6271,6 +6271,10 @@ def err_bad_cxx_cast_bitfield : Error<
62716271
def err_bad_cxx_cast_qualifiers_away : Error<
62726272
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
62736273
"functional-style cast}0 from %1 to %2 casts away qualifiers">;
6274+
def err_bad_cxx_cast_addr_space_mismatch : Error<
6275+
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
6276+
"functional-style cast}0 from %1 to %2 converts between mismatching address"
6277+
" spaces">;
62746278
def ext_bad_cxx_cast_qualifiers_away_incoherent : ExtWarn<
62756279
"ISO C++ does not allow "
62766280
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"

lib/Sema/SemaCast.cpp

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2212,7 +2212,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
22122212
/*CheckObjCLifetime=*/CStyle))
22132213
SuccessResult = getCastAwayConstnessCastKind(CACK, msg);
22142214

2215-
if (IsLValueCast) {
2215+
if (IsAddressSpaceConversion(SrcType, DestType)) {
2216+
Kind = CK_AddressSpaceConversion;
2217+
assert(SrcType->isPointerType() && DestType->isPointerType());
2218+
if (!CStyle &&
2219+
!DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf(
2220+
SrcType->getPointeeType().getQualifiers())) {
2221+
SuccessResult = TC_Failed;
2222+
}
2223+
} else if (IsLValueCast) {
22162224
Kind = CK_LValueBitCast;
22172225
} else if (DestType->isObjCObjectPointerType()) {
22182226
Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr);
@@ -2222,8 +2230,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
22222230
} else {
22232231
Kind = CK_BitCast;
22242232
}
2225-
} else if (IsAddressSpaceConversion(SrcType, DestType)) {
2226-
Kind = CK_AddressSpaceConversion;
22272233
} else {
22282234
Kind = CK_BitCast;
22292235
}
@@ -2278,6 +2284,41 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
22782284
return SuccessResult;
22792285
}
22802286

2287+
static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
2288+
QualType DestType, bool CStyle,
2289+
unsigned &msg) {
2290+
if (!Self.getLangOpts().OpenCL)
2291+
// FIXME: As compiler doesn't have any information about overlapping addr
2292+
// spaces at the moment we have to be permissive here.
2293+
return TC_NotApplicable;
2294+
// Even though the logic below is general enough and can be applied to
2295+
// non-OpenCL mode too, we fast-path above because no other languages
2296+
// define overlapping address spaces currently.
2297+
auto SrcType = SrcExpr.get()->getType();
2298+
auto SrcPtrType = SrcType->getAs<PointerType>();
2299+
if (!SrcPtrType)
2300+
return TC_NotApplicable;
2301+
auto DestPtrType = DestType->getAs<PointerType>();
2302+
if (!DestPtrType)
2303+
return TC_NotApplicable;
2304+
auto SrcPointeeType = SrcPtrType->getPointeeType();
2305+
auto DestPointeeType = DestPtrType->getPointeeType();
2306+
if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace())
2307+
return TC_NotApplicable;
2308+
if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) {
2309+
msg = diag::err_bad_cxx_cast_addr_space_mismatch;
2310+
return TC_Failed;
2311+
}
2312+
auto SrcPointeeTypeWithoutAS =
2313+
Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType());
2314+
auto DestPointeeTypeWithoutAS =
2315+
Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType());
2316+
return Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
2317+
DestPointeeTypeWithoutAS)
2318+
? TC_Success
2319+
: TC_NotApplicable;
2320+
}
2321+
22812322
void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
22822323
// In OpenCL only conversions between pointers to objects in overlapping
22832324
// addr spaces are allowed. v2.0 s6.5.5 - Generic addr space overlaps
@@ -2372,30 +2413,35 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
23722413
// listed above, the interpretation that appears first in the list is used,
23732414
// even if a cast resulting from that interpretation is ill-formed.
23742415
// In plain language, this means trying a const_cast ...
2416+
// Note that for address space we check compatibility after const_cast.
23752417
unsigned msg = diag::err_bad_cxx_cast_generic;
23762418
TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType,
2377-
/*CStyle*/true, msg);
2419+
/*CStyle*/ true, msg);
23782420
if (SrcExpr.isInvalid())
23792421
return;
23802422
if (isValidCast(tcr))
23812423
Kind = CK_NoOp;
23822424

2383-
Sema::CheckedConversionKind CCK
2384-
= FunctionalStyle? Sema::CCK_FunctionalCast
2385-
: Sema::CCK_CStyleCast;
2425+
Sema::CheckedConversionKind CCK =
2426+
FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast;
23862427
if (tcr == TC_NotApplicable) {
2387-
// ... or if that is not possible, a static_cast, ignoring const, ...
2388-
tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange,
2389-
msg, Kind, BasePath, ListInitialization);
2428+
tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg);
23902429
if (SrcExpr.isInvalid())
23912430
return;
2392-
23932431
if (tcr == TC_NotApplicable) {
2394-
// ... and finally a reinterpret_cast, ignoring const.
2395-
tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true,
2396-
OpRange, msg, Kind);
2432+
// ... or if that is not possible, a static_cast, ignoring const, ...
2433+
tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind,
2434+
BasePath, ListInitialization);
23972435
if (SrcExpr.isInvalid())
23982436
return;
2437+
2438+
if (tcr == TC_NotApplicable) {
2439+
// ... and finally a reinterpret_cast, ignoring const.
2440+
tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true,
2441+
OpRange, msg, Kind);
2442+
if (SrcExpr.isInvalid())
2443+
return;
2444+
}
23992445
}
24002446
}
24012447

@@ -2426,8 +2472,6 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
24262472
}
24272473
}
24282474

2429-
checkAddressSpaceCast(SrcExpr.get()->getType(), DestType);
2430-
24312475
if (isValidCast(tcr)) {
24322476
if (Kind == CK_BitCast)
24332477
checkCastAlign();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s
2+
3+
void test_reinterpret_cast(){
4+
__private float x;
5+
__private float& y = x;
6+
// We don't need bitcast to cast pointer type and
7+
// address space at the same time.
8+
//CHECK: addrspacecast float* %x to i32 addrspace(4)*
9+
//CHECK: [[REG:%[0-9]+]] = load float*, float** %y
10+
//CHECK: addrspacecast float* [[REG]] to i32 addrspace(4)*
11+
//CHECK-NOT: bitcast
12+
__generic int& rc1 = reinterpret_cast<__generic int&>(x);
13+
__generic int& rc2 = reinterpret_cast<__generic int&>(y);
14+
}

test/SemaCXX/address-space-conversion.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -131,24 +131,24 @@ void test_dynamic_cast(A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
131131
void test_reinterpret_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
132132
A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
133133
B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2,
134-
const void __attribute__((address_space(1))) *cvp1) {
135-
// reinterpret_cast can be used to cast to a different address space.
136-
(void)reinterpret_cast<A_ptr>(ap1);
137-
(void)reinterpret_cast<A_ptr>(ap2);
134+
const void __attribute__((address_space(1))) * cvp1) {
135+
// reinterpret_cast can't be used to cast to a different address space unless they are matching (i.e. overlapping).
136+
(void)reinterpret_cast<A_ptr>(ap1); // expected-error{{reinterpret_cast from 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') to 'A_ptr' (aka 'A *') is not allowed}}
137+
(void)reinterpret_cast<A_ptr>(ap2); // expected-error{{reinterpret_cast from 'A_ptr_2' (aka '__attribute__((address_space(2))) A *') to 'A_ptr' (aka 'A *') is not allowed}}
138138
(void)reinterpret_cast<A_ptr>(bp);
139-
(void)reinterpret_cast<A_ptr>(bp1);
140-
(void)reinterpret_cast<A_ptr>(bp2);
139+
(void)reinterpret_cast<A_ptr>(bp1); // expected-error{{reinterpret_cast from 'B_ptr_1' (aka '__attribute__((address_space(1))) B *') to 'A_ptr' (aka 'A *') is not allowed}}
140+
(void)reinterpret_cast<A_ptr>(bp2); // expected-error{{reinterpret_cast from 'B_ptr_2' (aka '__attribute__((address_space(2))) B *') to 'A_ptr' (aka 'A *') is not allowed}}
141141
(void)reinterpret_cast<A_ptr>(vp);
142-
(void)reinterpret_cast<A_ptr>(vp1);
143-
(void)reinterpret_cast<A_ptr>(vp2);
144-
(void)reinterpret_cast<A_ptr_1>(ap);
145-
(void)reinterpret_cast<A_ptr_1>(ap2);
146-
(void)reinterpret_cast<A_ptr_1>(bp);
142+
(void)reinterpret_cast<A_ptr>(vp1); // expected-error{{reinterpret_cast from 'void_ptr_1' (aka '__attribute__((address_space(1))) void *') to 'A_ptr' (aka 'A *') is not allowed}}
143+
(void)reinterpret_cast<A_ptr>(vp2); // expected-error{{reinterpret_cast from 'void_ptr_2' (aka '__attribute__((address_space(2))) void *') to 'A_ptr' (aka 'A *') is not allowed}}
144+
(void)reinterpret_cast<A_ptr_1>(ap); // expected-error{{reinterpret_cast from 'A_ptr' (aka 'A *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}}
145+
(void)reinterpret_cast<A_ptr_1>(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}}
146+
(void)reinterpret_cast<A_ptr_1>(bp); // expected-error{{reinterpret_cast from 'B_ptr' (aka 'B *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}}
147147
(void)reinterpret_cast<A_ptr_1>(bp1);
148-
(void)reinterpret_cast<A_ptr_1>(bp2);
149-
(void)reinterpret_cast<A_ptr_1>(vp);
148+
(void)reinterpret_cast<A_ptr_1>(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}}
149+
(void)reinterpret_cast<A_ptr_1>(vp); // expected-error{{reinterpret_cast from 'void_ptr' (aka 'void *') to 'A_ptr_1' (aka '__attribute__((address_space(1))) A *') is not allowed}}
150150
(void)reinterpret_cast<A_ptr_1>(vp1);
151-
(void)reinterpret_cast<A_ptr_1>(vp2);
151+
(void)reinterpret_cast<A_ptr_1>(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}}
152152

153153
// ... but don't try to cast away constness!
154154
(void)reinterpret_cast<A_ptr_2>(cvp1); // expected-error{{casts away qualifiers}}

test/SemaOpenCL/address-spaces-conversions-cl2.0.cl

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,27 +129,47 @@ void test_conversion(__global int *arg_glob, __local int *arg_loc,
129129

130130
AS int *var_cast1 = (AS int *)arg_glob;
131131
#ifdef CONSTANT
132-
// expected-error@-2{{casting '__global int *' to type '__constant int *' changes address space of pointer}}
132+
#if !__OPENCL_CPP_VERSION__
133+
// expected-error@-3{{casting '__global int *' to type '__constant int *' changes address space of pointer}}
134+
#else
135+
// expected-error@-5{{C-style cast from '__global int *' to '__constant int *' converts between mismatching address spaces}}
136+
#endif
133137
#endif
134138

135139
AS int *var_cast2 = (AS int *)arg_loc;
136140
#ifndef GENERIC
137-
// expected-error-re@-2{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}}
141+
#if !__OPENCL_CPP_VERSION__
142+
// expected-error-re@-3{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}}
143+
#else
144+
// expected-error-re@-5{{C-style cast from '__local int *' to '__{{global|constant}} int *' converts between mismatching address spaces}}
145+
#endif
138146
#endif
139147

140148
AS int *var_cast3 = (AS int *)arg_const;
141149
#ifndef CONSTANT
142-
// expected-error-re@-2{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}}
150+
#if !__OPENCL_CPP_VERSION__
151+
// expected-error-re@-3{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}}
152+
#else
153+
// expected-error-re@-5{{C-style cast from '__constant int *' to '__{{global|generic}} int *' converts between mismatching address spaces}}
154+
#endif
143155
#endif
144156

145157
AS int *var_cast4 = (AS int *)arg_priv;
146158
#ifndef GENERIC
147-
// expected-error-re@-2{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}}
159+
#if !__OPENCL_CPP_VERSION__
160+
// expected-error-re@-3{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}}
161+
#else
162+
// expected-error-re@-5{{C-style cast from 'int *' to '__{{global|constant}} int *' converts between mismatching address spaces}}
163+
#endif
148164
#endif
149165

150166
AS int *var_cast5 = (AS int *)arg_gen;
151167
#ifdef CONSTANT
152-
// expected-error@-2{{casting '__generic int *' to type '__constant int *' changes address space of pointer}}
168+
#if !__OPENCL_CPP_VERSION__
169+
// expected-error@-3{{casting '__generic int *' to type '__constant int *' changes address space of pointer}}
170+
#else
171+
// expected-error@-5{{C-style cast from '__generic int *' to '__constant int *' converts between mismatching address spaces}}
172+
#endif
153173
#endif
154174

155175
AS int *var_impl;
@@ -200,27 +220,47 @@ void test_conversion(__global int *arg_glob, __local int *arg_loc,
200220

201221
var_cast1 = (AS int *)arg_glob;
202222
#ifdef CONSTANT
203-
// expected-error@-2{{casting '__global int *' to type '__constant int *' changes address space of pointer}}
223+
#if !__OPENCL_CPP_VERSION__
224+
// expected-error@-3{{casting '__global int *' to type '__constant int *' changes address space of pointer}}
225+
#else
226+
// expected-error@-5{{C-style cast from '__global int *' to '__constant int *' converts between mismatching address spaces}}
227+
#endif
204228
#endif
205229

206230
var_cast2 = (AS int *)arg_loc;
207231
#ifndef GENERIC
208-
// expected-error-re@-2{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}}
232+
#if !__OPENCL_CPP_VERSION__
233+
// expected-error-re@-3{{casting '__local int *' to type '__{{global|constant}} int *' changes address space of pointer}}
234+
#else
235+
// expected-error-re@-5{{C-style cast from '__local int *' to '__{{global|constant}} int *' converts between mismatching address spaces}}
236+
#endif
209237
#endif
210238

211239
var_cast3 = (AS int *)arg_const;
212240
#ifndef CONSTANT
213-
// expected-error-re@-2{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}}
241+
#if !__OPENCL_CPP_VERSION__
242+
// expected-error-re@-3{{casting '__constant int *' to type '__{{global|generic}} int *' changes address space of pointer}}
243+
#else
244+
// expected-error-re@-5{{C-style cast from '__constant int *' to '__{{global|generic}} int *' converts between mismatching address spaces}}
245+
#endif
214246
#endif
215247

216248
var_cast4 = (AS int *)arg_priv;
217249
#ifndef GENERIC
218-
// expected-error-re@-2{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}}
250+
#if !__OPENCL_CPP_VERSION__
251+
// expected-error-re@-3{{casting 'int *' to type '__{{global|constant}} int *' changes address space of pointer}}
252+
#else
253+
// expected-error-re@-5{{C-style cast from 'int *' to '__{{global|constant}} int *' converts between mismatching address spaces}}
254+
#endif
219255
#endif
220256

221257
var_cast5 = (AS int *)arg_gen;
222258
#ifdef CONSTANT
223-
// expected-error@-2{{casting '__generic int *' to type '__constant int *' changes address space of pointer}}
259+
#if !__OPENCL_CPP_VERSION__
260+
// expected-error@-3{{casting '__generic int *' to type '__constant int *' changes address space of pointer}}
261+
#else
262+
// expected-error@-5{{C-style cast from '__generic int *' to '__constant int *' converts between mismatching address spaces}}
263+
#endif
224264
#endif
225265

226266
AS int *var_cmp;

0 commit comments

Comments
 (0)