summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Sotkin <alexey.sotkin@intel.com>2018-07-31 19:47:19 +0000
committerAlexey Sotkin <alexey.sotkin@intel.com>2018-07-31 19:47:19 +0000
commite9901bde15692e135ee2b98005f5fb8cdc23fcd5 (patch)
tree31464a45dac318ebcacc3c2eed449bedf0164f03
parent0065b256efa39476c9d32097b06c80a50356e27c (diff)
[OpenCL] Check for invalid kernel arguments in array types
Summary: OpenCL specification forbids use of several types as kernel arguments. This patch improves existing diagnostic to look through arrays. Patch by: Andrew Savonichev Reviewers: Anastasia, yaxunl Subscribers: yaxunl, Anastasia, cfe-commits Differential Revision: https://reviews.llvm.org/D49723 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338427 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaDecl.cpp32
-rw-r--r--test/SemaOpenCL/invalid-kernel-parameters.cl13
2 files changed, 40 insertions, 5 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2e871d6029..941ffefeed 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -8079,6 +8079,15 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PT->isRecordType())
return RecordKernelParam;
+ // Look into an array argument to check if it has a forbidden type.
+ if (PT->isArrayType()) {
+ const Type *UnderlyingTy = PT->getPointeeOrArrayElementType();
+ // Call ourself to check an underlying type of an array. Since the
+ // getPointeeOrArrayElementType returns an innermost type which is not an
+ // array, this recusive call only happens once.
+ return getOpenCLKernelParameterType(S, QualType(UnderlyingTy, 0));
+ }
+
return ValidKernelParam;
}
@@ -8146,9 +8155,14 @@ static void checkIsValidOpenCLKernelParameter(
SmallVector<const FieldDecl *, 4> HistoryStack;
HistoryStack.push_back(nullptr);
- const RecordDecl *PD = PT->castAs<RecordType>()->getDecl();
- VisitStack.push_back(PD);
+ // At this point we already handled everything except of a RecordType or
+ // an ArrayType of a RecordType.
+ assert((PT->isArrayType() || PT->isRecordType()) && "Unexpected type.");
+ const RecordType *RecTy =
+ PT->getPointeeOrArrayElementType()->getAs<RecordType>();
+ const RecordDecl *OrigRecDecl = RecTy->getDecl();
+ VisitStack.push_back(RecTy->getDecl());
assert(VisitStack.back() && "First decl null?");
do {
@@ -8167,7 +8181,15 @@ static void checkIsValidOpenCLKernelParameter(
const RecordDecl *RD;
if (const FieldDecl *Field = dyn_cast<FieldDecl>(Next)) {
HistoryStack.push_back(Field);
- RD = Field->getType()->castAs<RecordType>()->getDecl();
+
+ QualType FieldTy = Field->getType();
+ // Other field types (known to be valid or invalid) are handled while we
+ // walk around RecordDecl::fields().
+ assert((FieldTy->isArrayType() || FieldTy->isRecordType()) &&
+ "Unexpected type.");
+ const Type *FieldRecTy = FieldTy->getPointeeOrArrayElementType();
+
+ RD = FieldRecTy->castAs<RecordType>()->getDecl();
} else {
RD = cast<RecordDecl>(Next);
}
@@ -8204,8 +8226,8 @@ static void checkIsValidOpenCLKernelParameter(
S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
}
- S.Diag(PD->getLocation(), diag::note_within_field_of_type)
- << PD->getDeclName();
+ S.Diag(OrigRecDecl->getLocation(), diag::note_within_field_of_type)
+ << OrigRecDecl->getDeclName();
// We have an error, now let's go back up through history and show where
// the offending field came from
diff --git a/test/SemaOpenCL/invalid-kernel-parameters.cl b/test/SemaOpenCL/invalid-kernel-parameters.cl
index 2433c17fe0..ef0b56435d 100644
--- a/test/SemaOpenCL/invalid-kernel-parameters.cl
+++ b/test/SemaOpenCL/invalid-kernel-parameters.cl
@@ -136,3 +136,16 @@ struct AlsoUser // expected-note{{within field of type 'AlsoUser' declared here}
};
kernel void pointer_in_nested_struct_arg_2(struct Valid valid, struct NestedPointer arg, struct AlsoUser also) { } // expected-error 2 {{struct kernel parameters may not contain pointers}}
+
+struct ArrayOfPtr // expected-note{{within field of type 'ArrayOfPtr' declared here}}
+{
+ float *arr[3]; // expected-note{{field of illegal type 'float *[3]' declared here}}
+ // expected-note@-1{{field of illegal type 'float *[3]' declared here}}
+};
+kernel void array_of_ptr(struct ArrayOfPtr arr) {} // expected-error{{struct kernel parameters may not contain pointers}}
+
+struct ArrayOfStruct // expected-note{{within field of type 'ArrayOfStruct' declared here}}
+{
+ struct ArrayOfPtr arr[3]; // expected-note{{within field of type 'struct ArrayOfPtr [3]' declared here}}
+};
+kernel void array_of_struct(struct ArrayOfStruct arr) {} // expected-error{{struct kernel parameters may not contain pointers}}