Skip to content

Commit b33830a

Browse files
Anastasia Stulovazmodem
authored andcommitted
[OpenCL] Restrict addr space conversions in nested pointers
Address space conversion changes pointer representation. This commit disallows such conversions when they are not legal i.e. for the nested pointers even with compatible address spaces. Because the address space conversion in the nested levels can't be generated to modify the pointers correctly. The behavior implemented is as follows: - Any implicit conversions of nested pointers with different address spaces is rejected. - Any conversion of address spaces in nested pointers in safe casts (e.g. const_cast or static_cast) is rejected. - Conversion in low level C-style or reinterpret_cast is accepted but with a warning (this aligns with OpenCL C behavior). Fixes PR39674 Differential Revision: https://reviews.llvm.org/D73360 (cherry picked from commit 6064f42)
1 parent d8a6dea commit b33830a

File tree

8 files changed

+86
-17
lines changed

8 files changed

+86
-17
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6748,6 +6748,10 @@ def err_bad_cxx_cast_scalar_to_vector_different_size : Error<
67486748
def err_bad_cxx_cast_vector_to_vector_different_size : Error<
67496749
"%select{||reinterpret_cast||C-style cast|}0 from vector %1 "
67506750
"to vector %2 of different size">;
6751+
def warn_bad_cxx_cast_nested_pointer_addr_space : Warning<
6752+
"%select{reinterpret_cast|C-style cast}0 from %1 to %2 "
6753+
"changes address space of nested pointers">,
6754+
InGroup<IncompatiblePointerTypesDiscardsQualifiers>;
67516755
def err_bad_lvalue_to_rvalue_cast : Error<
67526756
"cannot cast from lvalue of type %1 to rvalue reference type %2; types are "
67536757
"not compatible">;

clang/lib/Sema/SemaCast.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,24 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
23112311
return SuccessResult;
23122312
}
23132313

2314+
// Diagnose address space conversion in nested pointers.
2315+
QualType DestPtee = DestType->getPointeeType().isNull()
2316+
? DestType->getPointeeType()
2317+
: DestType->getPointeeType()->getPointeeType();
2318+
QualType SrcPtee = SrcType->getPointeeType().isNull()
2319+
? SrcType->getPointeeType()
2320+
: SrcType->getPointeeType()->getPointeeType();
2321+
while (!DestPtee.isNull() && !SrcPtee.isNull()) {
2322+
if (DestPtee.getAddressSpace() != SrcPtee.getAddressSpace()) {
2323+
Self.Diag(OpRange.getBegin(),
2324+
diag::warn_bad_cxx_cast_nested_pointer_addr_space)
2325+
<< CStyle << SrcType << DestType << SrcExpr.get()->getSourceRange();
2326+
break;
2327+
}
2328+
DestPtee = DestPtee->getPointeeType();
2329+
SrcPtee = SrcPtee->getPointeeType();
2330+
}
2331+
23142332
// C++ 5.2.10p7: A pointer to an object can be explicitly converted to
23152333
// a pointer to an object of different type.
23162334
// Void pointers are not specified, but supported by every compiler out there.

clang/lib/Sema/SemaOverload.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3176,7 +3176,7 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
31763176
/// FromType and \p ToType is permissible, given knowledge about whether every
31773177
/// outer layer is const-qualified.
31783178
static bool isQualificationConversionStep(QualType FromType, QualType ToType,
3179-
bool CStyle,
3179+
bool CStyle, bool IsTopLevel,
31803180
bool &PreviousToQualsIncludeConst,
31813181
bool &ObjCLifetimeConversion) {
31823182
Qualifiers FromQuals = FromType.getQualifiers();
@@ -3213,11 +3213,15 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType,
32133213
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
32143214
return false;
32153215

3216-
// For a C-style cast, just require the address spaces to overlap.
3217-
// FIXME: Does "superset" also imply the representation of a pointer is the
3218-
// same? We're assuming that it does here and in compatiblyIncludes.
3219-
if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
3220-
!FromQuals.isAddressSpaceSupersetOf(ToQuals))
3216+
// If address spaces mismatch:
3217+
// - in top level it is only valid to convert to addr space that is a
3218+
// superset in all cases apart from C-style casts where we allow
3219+
// conversions between overlapping address spaces.
3220+
// - in non-top levels it is not a valid conversion.
3221+
if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() &&
3222+
(!IsTopLevel ||
3223+
!(ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
3224+
(CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))))
32213225
return false;
32223226

32233227
// -- if the cv 1,j and cv 2,j are different, then const is in
@@ -3258,9 +3262,9 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
32583262
bool PreviousToQualsIncludeConst = true;
32593263
bool UnwrappedAnyPointer = false;
32603264
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
3261-
if (!isQualificationConversionStep(FromType, ToType, CStyle,
3262-
PreviousToQualsIncludeConst,
3263-
ObjCLifetimeConversion))
3265+
if (!isQualificationConversionStep(
3266+
FromType, ToType, CStyle, !UnwrappedAnyPointer,
3267+
PreviousToQualsIncludeConst, ObjCLifetimeConversion))
32643268
return false;
32653269
UnwrappedAnyPointer = true;
32663270
}
@@ -4499,7 +4503,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
44994503
// If we find a qualifier mismatch, the types are not reference-compatible,
45004504
// but are still be reference-related if they're similar.
45014505
bool ObjCLifetimeConversion = false;
4502-
if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
4506+
if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel,
45034507
PreviousToQualsIncludeConst,
45044508
ObjCLifetimeConversion))
45054509
return (ConvertedReferent || Context.hasSimilarType(T1, T2))

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -513,17 +513,37 @@ void test_pointer_chains() {
513513
#endif
514514

515515
// Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces.
516-
// FIXME: Should this really be allowed in C++ mode?
517516
var_as_as_int = var_asc_asc_int;
518-
#if !__OPENCL_CPP_VERSION__
519517
#ifdef GENERIC
518+
#if !__OPENCL_CPP_VERSION__
520519
// expected-error@-3 {{assigning '__local int *__local *__private' to '__generic int *__generic *__private' changes address space of nested pointer}}
520+
#else
521+
// expected-error@-5 {{assigning to '__generic int *__generic *' from incompatible type '__local int *__local *__private'}}
521522
#endif
522523
#endif
523-
var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int;
524+
525+
var_as_as_int = (AS int *AS *)var_asc_asc_int;
526+
#ifdef GENERIC
524527
#if !__OPENCL_CPP_VERSION__
528+
// expected-warning@-3 {{casting '__local int *__local *' to type '__generic int *__generic *' discards qualifiers in nested pointer types}}
529+
#else
530+
// expected-warning@-5 {{C-style cast from '__local int *__local *' to '__generic int *__generic *' changes address space of nested pointers}}
531+
#endif
532+
#endif
533+
534+
var_as_as_int = (AS int *AS *)var_asc_asn_int;
535+
#if !__OPENCL_CPP_VERSION__
536+
// expected-warning-re@-2 {{casting '__{{global|local|constant}} int *__{{local|constant|global}} *' to type '__{{global|constant|generic}} int *__{{global|constant|generic}} *' discards qualifiers in nested pointer types}}
537+
#else
538+
// expected-warning-re@-4 {{C-style cast from '__{{global|local|constant}} int *__{{local|constant|global}} *' to '__{{global|constant|generic}} int *__{{global|constant|generic}} *' changes address space of nested pointers}}
539+
#endif
540+
541+
var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int;
525542
#ifdef GENERIC
543+
#if !__OPENCL_CPP_VERSION__
526544
// expected-warning@-3{{pointer type mismatch ('__generic int *__generic *' and '__local int *__local *')}}
545+
#else
546+
// expected-error@-5 {{incompatible operand types ('__generic int *__generic *' and '__local int *__local *')}}
527547
#endif
528548
#endif
529549
}

clang/test/SemaOpenCL/address-spaces.cl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,7 @@ void nested(__global int *g, __global int * __private *gg, __local int *l, __loc
198198
ll = gg; // expected-error {{assigning to '__local int *__private *' from incompatible type '__global int *__private *__private'}}
199199
ll = l; // expected-error {{assigning to '__local int *__private *' from incompatible type '__local int *__private'; take the address with &}}
200200
ll = gg_f; // expected-error {{assigning to '__local int *__private *' from incompatible type '__global float *__private *__private'}}
201-
// FIXME: The below becomes a reinterpret_cast, and therefore does not emit an error
202-
// even though the address space mismatches in the nested pointers.
203-
ll = (__local int * __private *)gg;
201+
ll = (__local int *__private *)gg; //expected-warning{{C-style cast from '__global int *__private *' to '__local int *__private *' changes address space of nested pointers}}
204202

205203
gg_f = g; // expected-error {{assigning to '__global float *__private *' from incompatible type '__global int *__private'}}
206204
gg_f = gg; // expected-error {{assigning to '__global float *__private *' from incompatible type '__global int *__private *__private'}}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//RUN: %clang_cc1 %s -cl-std=clc++ -pedantic -ast-dump -verify | FileCheck %s
2+
3+
void nester_ptr() {
4+
local int * * locgen;
5+
constant int * * congen;
6+
int * * gengen;
7+
8+
gengen = const_cast<int**>(locgen); //expected-error{{const_cast from '__local int *__generic *' to '__generic int *__generic *' is not allowed}}
9+
gengen = static_cast<int**>(locgen); //expected-error{{static_cast from '__local int *__generic *' to '__generic int *__generic *' is not allowed}}
10+
// CHECK-NOT: AddressSpaceConversion
11+
gengen = reinterpret_cast<int**>(locgen); //expected-warning{{reinterpret_cast from '__local int *__generic *' to '__generic int *__generic *' changes address space of nested pointers}}
12+
}

clang/test/SemaOpenCLCXX/address-space-deduction.cl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void t5(float (*(*fYZ))[2]);
105105
106106
__kernel void k() {
107107
__local float x[2];
108-
__local float(*p)[2];
108+
float(*p)[2];
109109
t1(x);
110110
t2(&x);
111111
t3(&x);

clang/test/SemaOpenCLCXX/address-space-references.cl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,16 @@ int bar(const unsigned int &i);
1313
void foo() {
1414
bar(1) // expected-error{{binding reference of type 'const __global unsigned int' to value of type 'int' changes address space}}
1515
}
16+
17+
// Test addr space conversion with nested pointers
18+
19+
extern void nestptr(int *&); // expected-note {{candidate function not viable: no known conversion from '__global int *__private' to '__generic int *__generic &__private' for 1st argument}}
20+
extern void nestptr_const(int * const &); // expected-note {{candidate function not viable: cannot pass pointer to address space '__constant' as a pointer to address space '__generic' in 1st argument}}
21+
int test_nestptr(__global int *glob, __constant int *cons, int* gen) {
22+
nestptr(glob); // expected-error{{no matching function for call to 'nestptr'}}
23+
// Addr space conversion first occurs on a temporary.
24+
nestptr_const(glob);
25+
// No legal conversion between disjoint addr spaces.
26+
nestptr_const(cons); // expected-error{{no matching function for call to 'nestptr_const'}}
27+
return *(*cons ? glob : gen);
28+
}

0 commit comments

Comments
 (0)