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.
This commit is contained in:
Nathan Sidwell 2020-09-16 11:04:19 -07:00
parent d1339b519a
commit 8155316c6f
5 changed files with 43 additions and 33 deletions

View File

@ -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);

View File

@ -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<tree> 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 ();

View File

@ -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, "%<const%>, %<volatile%> 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

View File

@ -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;
}

View File

@ -86,6 +86,7 @@ struct W
{
int v;
W () : v (6) {}
W (int i) : v (i) {}
~W () {}
};