https://gcc.gnu.org/g:858f300727833740f74d90378a0f302d4254ef37
commit r16-5727-g858f300727833740f74d90378a0f302d4254ef37 Author: Nathaniel Shead <[email protected]> Date: Sat Nov 15 15:27:13 2025 +1100 c++: Support template block-scope OpenMP user-defined reductions in modules [PR119864] There were two issues preventing OpenMP reductions of UDTs from working in modules. Firstly, we were failing a number of checking asserts in the streaming logic because the declaration is a DECL_LOCAL_DECL_P but was not correctly added to the BLOCK of the function template. This is because cp_parser_omp_declare_reduction only called pushdecl when !processing_template_decl; correcting this fixed this issue. The second issue is that modules saw this as a function definition and so attempted to call allocate_struct_function on it, which crashes. Given that these reduction functions don't really behave like real function definitions in any other way, I think the cleanest solution is to just skip all the function definition post-processing in modules; this seems to work to get the test functioning correctly, from what I can see. PR c++/119864 gcc/cp/ChangeLog: * module.cc (trees_in::read_function_def): Don't call post_process on OpenMP UDT reductions. * parser.cc (cp_parser_omp_declare_reduction): Call push_decl for block_scope, even when processing_template_decl. gcc/testsuite/ChangeLog: * g++.dg/modules/omp-4_a.C: New test. * g++.dg/modules/omp-4_b.C: New test. Signed-off-by: Nathaniel Shead <[email protected]> Reviewed-by: Jakub Jelinek <[email protected]> Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/module.cc | 8 +++++++- gcc/cp/parser.cc | 5 +---- gcc/testsuite/g++.dg/modules/omp-4_a.C | 30 ++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/modules/omp-4_b.C | 11 +++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 92449286a842..ea22cef24a5b 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13015,7 +13015,13 @@ trees_in::read_function_def (tree decl, tree maybe_template) SET_DECL_FRIEND_CONTEXT (decl, context); if (cexpr.decl) register_constexpr_fundef (cexpr); - post_process (pdata); + + if (DECL_LOCAL_DECL_P (decl)) + /* Block-scope OMP UDRs aren't real functions, and don't need a + function structure to be allocated or to be expanded. */ + gcc_checking_assert (DECL_OMP_DECLARE_REDUCTION_P (decl)); + else + post_process (pdata); } else if (maybe_dup) { diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index de11798b8bdc..786212713dbc 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -53737,10 +53737,7 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, fndecl = push_template_decl (fndecl); if (block_scope) - { - if (!processing_template_decl) - pushdecl (fndecl); - } + pushdecl (fndecl); else if (current_class_type) { if (cp == NULL) diff --git a/gcc/testsuite/g++.dg/modules/omp-4_a.C b/gcc/testsuite/g++.dg/modules/omp-4_a.C new file mode 100644 index 000000000000..948966e657f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/omp-4_a.C @@ -0,0 +1,30 @@ +// PR c++/119864 +// { dg-additional-options "-fmodules -fopenmp" } +// { dg-module-cmi p1 } + +export module p1; + +export +template<unsigned> +struct T +{ + double d; + + T &operator +=(T const &x) { d += x.d; return *this; } +}; + +export +template<unsigned d> +T<d> sum(T<d> const *p, unsigned N) +{ +T<d> Sum = {}; + +#pragma omp declare reduction(Op: T<d>: omp_out += omp_in) initializer(omp_priv = {}) +#pragma omp parallel for reduction(Op: Sum) +for (unsigned i = 0u; i < N; ++i) + { + Sum += *p; + ++p; + } +return Sum; +} diff --git a/gcc/testsuite/g++.dg/modules/omp-4_b.C b/gcc/testsuite/g++.dg/modules/omp-4_b.C new file mode 100644 index 000000000000..c1ca279a97e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/omp-4_b.C @@ -0,0 +1,11 @@ +// PR c++/119864 +// { dg-additional-options "-fmodules -fopenmp" } + +import p1; + +int main() +{ + T<1u> v[3u] = {}; + + T s = sum(v, 3u); +}
