On 9/16/20 2:31 PM, Jakub Jelinek wrote:
On Wed, Sep 16, 2020 at 02:11:32PM -0400, Nathan Sidwell wrote:
Jakub,
are you ok with the bool return from cp_check_omp_declare_reduction? That
seemed like the least invasive change.
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.
The attached patch doesn't match the ChangeLog...
here's the right one, problem with ordering by time or name :(
nathan
--
Nathan Sidwell
diff --git i/gcc/cp/cp-tree.h w/gcc/cp/cp-tree.h
index 6e4de7d0c4b..5b727348e51 100644
--- i/gcc/cp/cp-tree.h
+++ w/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 i/gcc/cp/pt.c w/gcc/cp/pt.c
index 289452ab740..cfe5ff4a94f 100644
--- i/gcc/cp/pt.c
+++ w/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 ();
diff --git i/gcc/cp/semantics.c w/gcc/cp/semantics.c
index 4ca2a2f0030..11996c99ac7 100644
--- i/gcc/cp/semantics.c
+++ w/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, "%<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
diff --git i/gcc/testsuite/g++.dg/gomp/udr-2.C w/gcc/testsuite/g++.dg/gomp/udr-2.C
index 48451c4fc0a..6ccf95f822d 100644
--- i/gcc/testsuite/g++.dg/gomp/udr-2.C
+++ w/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 i/libgomp/testsuite/libgomp.c++/udr-3.C w/libgomp/testsuite/libgomp.c++/udr-3.C
index 74a01389c7b..0c45cb8f808 100644
--- i/libgomp/testsuite/libgomp.c++/udr-3.C
+++ w/libgomp/testsuite/libgomp.c++/udr-3.C
@@ -86,6 +86,7 @@ struct W
{
int v;
W () : v (6) {}
+ W (int i) : v (i) {}
~W () {}
};