c++: local-scope OMP UDR reductions have no template head
authorNathan Sidwell <nathan@acm.org>
Wed, 16 Sep 2020 18:04:19 +0000 (11:04 -0700)
committerNathan Sidwell <nathan@acm.org>
Wed, 16 Sep 2020 19:16:11 +0000 (12:16 -0700)
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
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/gomp/udr-2.C
libgomp/testsuite/libgomp.c++/udr-3.C

index 6e4de7d0c4b2addbb3a812880a8d32b6b3f1f0ab..5b727348e51b5e8a6fc0ed8c35554058a87a0f0c 100644 (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);
index 289452ab740c88650e6172671ff58b2c19ead71d..cfe5ff4a94f471ecdb134a0f46442c23e9f4d10b 100644 (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 ();
index 4ca2a2f0030c88adf4f629ffbda2d5ef618d1391..11996c99ac798e4db89ab1f40cc2a9e9537416d7 100644 (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
index 48451c4fc0ab9bf595b0a52b3c41692c77ff80e8..6ccf95f822d503fc96c6cd28e0a276383cc8b8ea 100644 (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;
   }
index 74a01389c7b196e66719194b222f20d2f5105cf5..0c45cb8f808136df0bc0663bedd55a2eb498c919 100644 (file)
@@ -86,6 +86,7 @@ struct W
 {
   int v;
   W () : v (6) {}
+  W (int i) : v (i) {}
   ~W () {}
 };