diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9234,10 +9234,23 @@ // reference if an implementation supports them in kernel parameters. if (S.getLangOpts().OpenCLCPlusPlus && !S.getOpenCLOptions().isAvailableOption( - "__cl_clang_non_portable_kernel_param_types", S.getLangOpts()) && - !PointeeType->isAtomicType() && !PointeeType->isVoidType() && - !PointeeType->isStandardLayoutType()) + "__cl_clang_non_portable_kernel_param_types", S.getLangOpts())) { + auto CXXRec = PointeeType.getCanonicalType()->getAsCXXRecordDecl(); + bool IsStandardLayoutType = true; + if (CXXRec) { + // If template type is not ODR-used its definition is only available + // in the template definition not its instantiation. + // FIXME: This logic doesn't work for types that depend on template + // parameter (PR58590). + if (!CXXRec->hasDefinition()) + CXXRec = CXXRec->getTemplateInstantiationPattern(); + if (!CXXRec || !CXXRec->hasDefinition() || !CXXRec->isStandardLayout()) + IsStandardLayoutType = false; + } + if (!PointeeType->isAtomicType() && !PointeeType->isVoidType() && + !IsStandardLayoutType) return InvalidKernelParam; + } return PtrKernelParam; } diff --git a/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp b/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp --- a/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp +++ b/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp @@ -93,3 +93,24 @@ #ifndef UNSAFEKERNELPARAMETER //expected-error@-2{{'__global Trivial &__private' cannot be used as the type of a kernel parameter}} #endif + +// Nested types and templates +struct Outer { + struct Inner{ + int i; + }; +}; +template +struct OuterTempl { + struct Inner{ + int i; + }; +}; +// FIXME: (PR58590) Use of template parameter dependent types doesn't +// work yet due to lazy instantiation of reference types. +//template +//struct Templ { +//T i; +//}; + +extern kernel void nested(constant Outer::Inner& r1, constant OuterTempl::Inner& r2/*, constant Templ& r3*/);