[clang] [OpenCL] Diagnose invalid pipe packet types when formed (PR #234347)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 21 12:57:19 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Akimasa Watanuki (Men-cotton)
<details>
<summary>Changes</summary>
Validation is limited to function parameters and misses invalid pipe typedefs such as `typedef pipe void P;`. Move this validation into `BuildReadPipeType` and `BuildWritePipeType` so declarations and template instantiations follow the same packet-type restrictions.
Reject pointer, reference, block pointer, non-object, and non-dependent incomplete packet types. Defer checks that require a concrete type until template substitution, but diagnose dependent function types immediately. Report errors at the `pipe` keyword.
Assisted-by: Codex / GPT-5.6 Sol + GPT-6 Astra
---
Full diff: https://github.com/llvm/llvm-project/pull/234347.diff
6 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3-2)
- (modified) clang/lib/Parse/ParseDecl.cpp (+3-3)
- (modified) clang/lib/Sema/DeclSpec.cpp (+1)
- (modified) clang/lib/Sema/SemaDecl.cpp (-11)
- (modified) clang/lib/Sema/SemaType.cpp (+27-2)
- (modified) clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl (+38-8)
``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a23667f1fb1c2c..bd8ceb1031d659 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11920,8 +11920,9 @@ def err_opencl_global_invalid_addr_space : Error<
"%select{program scope|static local|extern}0 variable must reside in %1 address space">;
def err_missing_actual_pipe_type : Error<
"missing actual type specifier for pipe">;
-def err_reference_pipe_type : Error <
- "pipes packet types cannot be of reference type">;
+def err_invalid_pipe_packet_type : Error<
+ "%select{pointer|reference|block pointer|non-object|incomplete}0 type %1 "
+ "cannot be used as a pipe packet type">;
def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
def err_opencl_kernel_attr :
Error<"attribute %0 can only be applied to an OpenCL kernel function">;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index ada54c85695c34..e452c312702491 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -6654,9 +6654,9 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
DeclSpec DS(AttrFactory);
ParseTypeQualifierListOpt(DS);
- D.AddTypeInfo(
- DeclaratorChunk::getPipe(DS.getTypeQualifiers(), DS.getPipeLoc()),
- std::move(DS.getAttributes()), SourceLocation());
+ D.AddTypeInfo(DeclaratorChunk::getPipe(DS.getTypeQualifiers(),
+ D.getDeclSpec().getPipeLoc()),
+ std::move(DS.getAttributes()), SourceLocation());
}
// Not a pointer, C++ reference, or block.
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index e83ba3db9f1fd6..dfa7a79d1f92b2 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -905,6 +905,7 @@ bool DeclSpec::SetTypePipe(bool isPipe, SourceLocation Loc,
if (isPipe) {
TypeSpecPipe = static_cast<unsigned>(TypeSpecifiersPipe::Pipe);
+ TQ_pipeLoc = Loc;
}
return false;
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 21e279ec2000c3..854ed123bb558c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -11433,17 +11433,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
for (const ParmVarDecl *Param : NewFD->parameters()) {
QualType PT = Param->getType();
- // OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value
- // types.
- if (getLangOpts().getOpenCLCompatibleVersion() >= 200) {
- if(const PipeType *PipeTy = PT->getAs<PipeType>()) {
- QualType ElemTy = PipeTy->getElementType();
- if (ElemTy->isPointerOrReferenceType()) {
- Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type);
- D.setInvalidType();
- }
- }
- }
// WebAssembly tables can't be used as function parameters.
if (Context.getTargetInfo().getTriple().isWasm()) {
if (PT->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) {
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index af0403e73480c0..578c73f2a00d15 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1970,11 +1970,35 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return Context.getRValueReferenceType(T);
}
+static bool checkOpenCLPipePacketType(Sema &S, QualType T, SourceLocation Loc) {
+ if (T->isPointerType())
+ return S.Diag(Loc, diag::err_invalid_pipe_packet_type)
+ << /*pointer*/ 0 << T;
+ if (T->isReferenceType())
+ return S.Diag(Loc, diag::err_invalid_pipe_packet_type)
+ << /*reference*/ 1 << T;
+ if (T->isBlockPointerType())
+ return S.Diag(Loc, diag::err_invalid_pipe_packet_type)
+ << /*block pointer*/ 2 << T;
+ if (!T->isObjectType())
+ return S.Diag(Loc, diag::err_invalid_pipe_packet_type)
+ << /*non-object*/ 3 << T;
+ if (!T->isDependentType() && !S.isCompleteType(Loc, T))
+ return S.Diag(Loc, diag::err_invalid_pipe_packet_type)
+ << /*incomplete*/ 4 << T;
+
+ return false;
+}
+
QualType Sema::BuildReadPipeType(QualType T, SourceLocation Loc) {
+ if (checkOpenCLPipePacketType(*this, T, Loc))
+ return QualType();
return Context.getReadPipeType(T);
}
QualType Sema::BuildWritePipeType(QualType T, SourceLocation Loc) {
+ if (checkOpenCLPipePacketType(*this, T, Loc))
+ return QualType();
return Context.getWritePipeType(T);
}
@@ -5498,8 +5522,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Pipe: {
T = S.BuildReadPipeType(T, DeclType.Loc);
- processTypeAttrs(state, T, TAL_DeclSpec,
- D.getMutableDeclSpec().getAttributes());
+ if (!T.isNull())
+ processTypeAttrs(state, T, TAL_DeclSpec,
+ D.getMutableDeclSpec().getAttributes());
break;
}
}
diff --git a/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl b/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl
index 089b2f16765fd0..a570bd3ff75ca4 100644
--- a/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl
+++ b/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -Wno-strict-prototypes -cl-std=CL2.0
+// RUN: %clang_cc1 %s -verify=expected,blocks -pedantic -fsyntax-only -Wno-strict-prototypes -cl-std=CL2.0 -fblocks -DTEST_BLOCK_POINTER_PACKET
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -Wno-strict-prototypes -cl-std=CL3.0 -cl-ext=+__opencl_c_pipes,+__opencl_c_generic_address_space,+__opencl_c_program_scope_global_variables
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -Wno-strict-prototypes -cl-std=CL3.0 -cl-ext=+__opencl_c_pipes,+__opencl_c_generic_address_space,-__opencl_c_program_scope_global_variables,-__opencl_c_device_enqueue
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=clc++1.0
@@ -8,21 +9,50 @@
global pipe int gp; // expected-error {{type '__global read_only pipe int' can only be used as a function parameter in OpenCL}}
global reserve_id_t rid; // expected-error {{the '__global reserve_id_t' type cannot be used to declare a program scope variable}}
-extern pipe write_only int get_pipe(void); // expected-error {{'write_only' attribute only applies to parameters and typedefs}}
-#if (__OPENCL_CPP_VERSION__ == 100) || (__OPENCL_C_VERSION__ == 200) || ((__OPENCL_CPP_VERSION__ == 202100 || __OPENCL_C_VERSION__ == 300) && defined(__opencl_c_program_scope_global_variables))
-// expected-error-re at -2{{type '__global write_only pipe int ({{(void)?}})' can only be used as a function parameter in OpenCL}}
-#else
-// FIXME: '__private' here makes no sense since program scope variables feature is not supported, should diagnose as '__global' probably
-// expected-error-re at -5{{type '__private write_only pipe int ({{(void)?}})' can only be used as a function parameter in OpenCL}}
-#endif
+extern pipe write_only int get_pipe(void); // expected-error {{'write_only' attribute only applies to parameters and typedefs}} expected-error-re {{non-object type 'int ({{(void)?}})' cannot be used as a pipe packet type}}
global pipe notype1, notype2; // expected-error {{missing actual type specifier for pipe}}
kernel void test_invalid_reserved_id(reserve_id_t ID) { // expected-error {{'__private reserve_id_t' cannot be used as the type of a kernel parameter}}
}
-void test1(pipe int *p) {// expected-error {{pipes packet types cannot be of reference type}}
+void test1(pipe int *p) {// expected-error {{pointer type '__generic int *' cannot be used as a pipe packet type}}
}
+
+#ifdef __OPENCL_CPP_VERSION__
+void reference_packet_type(pipe int &p) {} // expected-error {{reference type '__generic int &' cannot be used as a pipe packet type}}
+#endif
+
+#ifdef TEST_BLOCK_POINTER_PACKET
+typedef void (^block_t)(void);
+void block_pointer_packet_type(pipe block_t p) {} // blocks-error-re {{block pointer type 'block_t'{{.*}} cannot be used as a pipe packet type}}
+#endif
+
+typedef pipe void invalid_pipe_typedef; // expected-error {{non-object type 'void' cannot be used as a pipe packet type}}
+
+typedef void function_type(void);
+void non_object_packet_types(
+ pipe void p1, // expected-error {{non-object type 'void' cannot be used as a pipe packet type}}
+ pipe function_type p2) {} // expected-error-re {{non-object type 'function_type' (aka 'void ({{(void)?}})') cannot be used as a pipe packet type}}
+
+struct incomplete;
+typedef pipe struct incomplete invalid_incomplete_pipe; // expected-error {{incomplete type 'struct incomplete' cannot be used as a pipe packet type}}
+
+#ifdef __OPENCL_CPP_VERSION__
+template <typename T>
+void non_object_packet_in_template(pipe void p) {} // expected-error {{non-object type 'void' cannot be used as a pipe packet type}}
+
+template <typename T>
+void dependent_packet_type(pipe T p) {}
+
+template <typename T> using dependent_function_type = T();
+template <typename T>
+void dependent_function_packet_type(pipe dependent_function_type<T> p) {} // expected-error {{non-object type 'dependent_function_type<T>' (aka 'T ()') cannot be used as a pipe packet type}}
+
+template <typename T> struct packet_type { T value; };
+void class_template_packet_type(pipe packet_type<int> p) {}
+#endif
+
void test2(pipe p) {// expected-error {{missing actual type specifier for pipe}}
}
void test3(int pipe p) {// expected-error {{cannot combine with previous 'int' declaration specifier}}
``````````
</details>
https://github.com/llvm/llvm-project/pull/234347
More information about the cfe-commits
mailing list