From 8155316c6fc23045e8e056e91449a6e9863c357f Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Wed, 16 Sep 2020 11:04:19 -0700 Subject: [PATCH] c++: local-scope OMP UDR reductions have no template head This corrects the earlier problems with removing the template header from local omp reductions. And it uncovered a latent bug. When we tsubst such a decl, we immediately tsubst its body. cp_check_omp_declare_reduction gets a success return value to gate that instantiation. udr-2.C got a further error, as the omp checking machinery doesn't appear to turn the reduction into an error mark when failing. I didn't dig into that further. udr-3.C appears to have been invalid and accidentally worked. gcc/cp/ * cp-tree.h (cp_check_omp_declare_reduction): Return bool. * semantics.c (cp_check_omp_declare_reduction): Return true on for success. * pt.c (push_template_decl_real): OMP reductions do not get a template header. (tsubst_function_decl): Remove special casing for local decl omp reductions. (tsubst_expr): Call instantiate_body for a local omp reduction. (instantiate_body): Add nested_p parm, and deal with such instantiations. (instantiate_decl): Reject FUNCTION_SCOPE entities, adjust instantiate_body call. gcc/testsuite/ * g++.dg/gomp/udr-2.C: Add additional expected error. libgomp/ * testsuite/libgomp.c++/udr-3.C: Add missing ctor. --- gcc/cp/cp-tree.h | 2 +- gcc/cp/pt.c | 55 +++++++++++++++------------ gcc/cp/semantics.c | 17 +++++---- gcc/testsuite/g++.dg/gomp/udr-2.C | 1 + libgomp/testsuite/libgomp.c++/udr-3.C | 1 + 5 files changed, 43 insertions(+), 33 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6e4de7d0c4b..5b727348e51 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7228,7 +7228,7 @@ extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); extern tree omp_reduction_id (enum tree_code, tree, tree); extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *); -extern void cp_check_omp_declare_reduction (tree); +extern bool cp_check_omp_declare_reduction (tree); extern void finish_omp_declare_simd_methods (tree); extern tree finish_omp_clauses (tree, enum c_omp_region_type); extern tree push_omp_privatization_clauses (bool); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 289452ab740..cfe5ff4a94f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -227,6 +227,7 @@ static tree canonicalize_expr_argument (tree, tsubst_flags_t); static tree make_argument_pack (tree); static void register_parameter_specializations (tree, tree); static tree enclosing_instantiation_of (tree tctx); +static void instantiate_body (tree pattern, tree args, tree d, bool nested); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function @@ -6073,10 +6074,7 @@ push_template_decl_real (tree decl, bool is_friend) retrofit_lang_decl (decl); if (DECL_LANG_SPECIFIC (decl) && !(VAR_OR_FUNCTION_DECL_P (decl) - && DECL_LOCAL_DECL_P (decl) - /* OMP reductions still need a template header. */ - && !(TREE_CODE (decl) == FUNCTION_DECL - && DECL_OMP_DECLARE_REDUCTION_P (decl)))) + && DECL_LOCAL_DECL_P (decl))) DECL_TEMPLATE_INFO (decl) = info; } @@ -13714,8 +13712,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE || DECL_LOCAL_DECL_P (t)); - if (DECL_LOCAL_DECL_P (t) - && !DECL_OMP_DECLARE_REDUCTION_P (t)) + if (DECL_LOCAL_DECL_P (t)) { if (tree spec = retrieve_local_specialization (t)) return spec; @@ -13970,8 +13967,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, && !uses_template_parms (argvec)) tsubst_default_arguments (r, complain); } - else if (DECL_LOCAL_DECL_P (r) - && !DECL_OMP_DECLARE_REDUCTION_P (r)) + else if (DECL_LOCAL_DECL_P (r)) { if (!cp_unevaluated_operand) register_local_specialization (r, t); @@ -18083,7 +18079,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, DECL_CONTEXT (decl) = global_namespace; pushdecl (decl); DECL_CONTEXT (decl) = current_function_decl; - cp_check_omp_declare_reduction (decl); + if (cp_check_omp_declare_reduction (decl)) + instantiate_body (pattern_decl, args, decl, true); } else { @@ -25448,15 +25445,24 @@ register_parameter_specializations (tree pattern, tree inst) } /* Instantiate the body of D using PATTERN with ARGS. We have - already determined PATTERN is the correct template to use. */ + already determined PATTERN is the correct template to use. + NESTED_P is true if this is a nested function, in which case + PATTERN will be a FUNCTION_DECL not a TEMPLATE_DECL. */ static void -instantiate_body (tree pattern, tree args, tree d) +instantiate_body (tree pattern, tree args, tree d, bool nested_p) { - gcc_checking_assert (TREE_CODE (pattern) == TEMPLATE_DECL); - - tree td = pattern; - tree code_pattern = DECL_TEMPLATE_RESULT (td); + tree td = NULL_TREE; + tree code_pattern = pattern; + + if (!nested_p) + { + td = pattern; + code_pattern = DECL_TEMPLATE_RESULT (td); + } + else + /* Only OMP reductions are nested. */ + gcc_checking_assert (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)); vec omp_privatization_save; if (current_function_decl) @@ -25489,9 +25495,10 @@ instantiate_body (tree pattern, tree args, tree d) instantiate_decl do not try to instantiate it again. */ DECL_TEMPLATE_INSTANTIATED (d) = 1; - /* Regenerate the declaration in case the template has been modified - by a subsequent redeclaration. */ - regenerate_decl_from_template (d, td, args); + if (td) + /* Regenerate the declaration in case the template has been modified + by a subsequent redeclaration. */ + regenerate_decl_from_template (d, td, args); /* We already set the file and line above. Reset them now in case they changed as a result of calling regenerate_decl_from_template. */ @@ -25540,8 +25547,7 @@ instantiate_body (tree pattern, tree args, tree d) tree block = NULL_TREE; /* Set up context. */ - if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern) - && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL) + if (nested_p) block = push_stmt_list (); else start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); @@ -25554,7 +25560,7 @@ instantiate_body (tree pattern, tree args, tree d) /* Substitute into the body of the function. */ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) tsubst_omp_udr (DECL_SAVED_TREE (code_pattern), args, - tf_warning_or_error, DECL_TI_TEMPLATE (d)); + tf_warning_or_error, d); else { tsubst_expr (DECL_SAVED_TREE (code_pattern), args, @@ -25572,8 +25578,7 @@ instantiate_body (tree pattern, tree args, tree d) } /* Finish the function. */ - if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern) - && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL) + if (nested_p) DECL_SAVED_TREE (d) = pop_stmt_list (block); else { @@ -25628,6 +25633,8 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) /* A concept is never instantiated. */ gcc_assert (!DECL_DECLARED_CONCEPT_P (d)); + gcc_checking_assert (!DECL_FUNCTION_SCOPE_P (d)); + /* Variables are never deferred; if instantiation is required, they are instantiated right away. That allows for better code in the case that an expression refers to the value of the variable -- @@ -25844,7 +25851,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) { if (variable_template_p (gen_tmpl)) note_variable_template_instantiation (d); - instantiate_body (td, args, d); + instantiate_body (td, args, d, false); } pop_deferring_access_checks (); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4ca2a2f0030..11996c99ac7 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5679,7 +5679,7 @@ cp_check_omp_declare_reduction_r (tree *tp, int *, void *data) /* Diagnose violation of OpenMP #pragma omp declare reduction restrictions. */ -void +bool cp_check_omp_declare_reduction (tree udr) { tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (udr))); @@ -5689,7 +5689,7 @@ cp_check_omp_declare_reduction (tree udr) location_t loc = DECL_SOURCE_LOCATION (udr); if (type == error_mark_node) - return; + return false; if (ARITHMETIC_TYPE_P (type)) { static enum tree_code predef_codes[] @@ -5723,7 +5723,7 @@ cp_check_omp_declare_reduction (tree udr) { error_at (loc, "predeclared arithmetic type %qT in " "%<#pragma omp declare reduction%>", type); - return; + return false; } } else if (FUNC_OR_METHOD_TYPE_P (type) @@ -5731,24 +5731,24 @@ cp_check_omp_declare_reduction (tree udr) { error_at (loc, "function or array type %qT in " "%<#pragma omp declare reduction%>", type); - return; + return false; } else if (TYPE_REF_P (type)) { error_at (loc, "reference type %qT in %<#pragma omp declare reduction%>", type); - return; + return false; } else if (TYPE_QUALS_NO_ADDR_SPACE (type)) { error_at (loc, "%, % or %<__restrict%>-qualified " "type %qT in %<#pragma omp declare reduction%>", type); - return; + return false; } tree body = DECL_SAVED_TREE (udr); if (body == NULL_TREE || TREE_CODE (body) != STATEMENT_LIST) - return; + return true; tree_stmt_iterator tsi; struct cp_check_omp_declare_reduction_data data; @@ -5764,7 +5764,7 @@ cp_check_omp_declare_reduction (tree udr) gcc_assert (TREE_CODE (data.stmts[0]) == DECL_EXPR && TREE_CODE (data.stmts[1]) == DECL_EXPR); if (TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0]))) - return; + return true; data.combiner_p = true; if (cp_walk_tree (&data.stmts[2], cp_check_omp_declare_reduction_r, &data, NULL)) @@ -5783,6 +5783,7 @@ cp_check_omp_declare_reduction (tree udr) if (i == 7) gcc_assert (TREE_CODE (data.stmts[6]) == DECL_EXPR); } + return true; } /* Helper function of finish_omp_clauses. Clone STMT as if we were making diff --git a/gcc/testsuite/g++.dg/gomp/udr-2.C b/gcc/testsuite/g++.dg/gomp/udr-2.C index 48451c4fc0a..6ccf95f822d 100644 --- a/gcc/testsuite/g++.dg/gomp/udr-2.C +++ b/gcc/testsuite/g++.dg/gomp/udr-2.C @@ -34,6 +34,7 @@ namespace N2 typedef T3 T; #pragma omp declare reduction (foo : T : omp_out += N1::v) // { dg-error "combiner refers to variable" } #pragma omp declare reduction (foo : T4 : v *= omp_in) // { dg-error "combiner refers to variable" } + // { dg-error "in assignment" "" { target *-*-* } .-1 } #pragma omp declare reduction (foo : T5 : omp_out.w *= omp_in.w + v) // { dg-error "combiner refers to variable" } return 0; } diff --git a/libgomp/testsuite/libgomp.c++/udr-3.C b/libgomp/testsuite/libgomp.c++/udr-3.C index 74a01389c7b..0c45cb8f808 100644 --- a/libgomp/testsuite/libgomp.c++/udr-3.C +++ b/libgomp/testsuite/libgomp.c++/udr-3.C @@ -86,6 +86,7 @@ struct W { int v; W () : v (6) {} + W (int i) : v (i) {} ~W () {} }; -- 2.30.2