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:
parent
d1339b519a
commit
8155316c6f
@ -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);
|
||||
|
55
gcc/cp/pt.c
55
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<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 ();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -86,6 +86,7 @@ struct W
|
||||
{
|
||||
int v;
|
||||
W () : v (6) {}
|
||||
W (int i) : v (i) {}
|
||||
~W () {}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user