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 () {}
 };
 

Reply via email to