omp reductions are modeled as nested functions, which is a thing C++
doesn't have.  Leading to much confusion until I figured out what was
happening.  Not helped by some duplicate code and inconsistencies in
the dependent and non-dependent paths.  This patch removes the parser
duplication and fixes up some bookkeeping.  Added some asserts and
comments too.

        gcc/cp/
        * parser.c (cp_parser_omp_declare_reduction): Refactor to avoid
        code duplication.  Update DECL_TI_TEMPLATE's context.
        * pt.c (tsubst_expr): For OMP reduction function, set context to
        global_namespace before pushing.
        (tsubst_omp_udr): Assert current_function_decl, add comment about
        decl context.

pushing to trunk

nathan
--
Nathan Sidwell
diff --git c/gcc/cp/parser.c w/gcc/cp/parser.c
index 9849e59d5aa..0da383937c2 100644
--- c/gcc/cp/parser.c
+++ w/gcc/cp/parser.c
@@ -42616,16 +42616,9 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
 	  cp_parser_push_lexer_for_tokens (parser, cp);
 	  parser->lexer->in_pragma = true;
 	}
-      if (!cp_parser_omp_declare_reduction_exprs (fndecl, parser))
-	{
-	  if (!block_scope)
-	    finish_function (/*inline_p=*/false);
-	  else
-	    DECL_CONTEXT (fndecl) = current_function_decl;
-	  if (cp)
-	    cp_parser_pop_lexer (parser);
-	  goto fail;
-	}
+
+      bool ok = cp_parser_omp_declare_reduction_exprs (fndecl, parser);
+
       if (cp)
 	cp_parser_pop_lexer (parser);
       if (!block_scope)
@@ -42633,6 +42626,14 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
       else
 	{
 	  DECL_CONTEXT (fndecl) = current_function_decl;
+	  if (DECL_TEMPLATE_INFO (fndecl))
+	    DECL_CONTEXT (DECL_TI_TEMPLATE (fndecl)) = current_function_decl;
+	}
+      if (!ok)
+	goto fail;
+
+      if (block_scope)
+	{
 	  block = finish_omp_structured_block (block);
 	  if (TREE_CODE (block) == BIND_EXPR)
 	    DECL_SAVED_TREE (fndecl) = BIND_EXPR_BODY (block);
@@ -42641,6 +42642,7 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
 	  if (processing_template_decl)
 	    add_decl_expr (fndecl);
 	}
+
       cp_check_omp_declare_reduction (fndecl);
       if (cp == NULL && types.length () > 1)
 	cp = cp_token_cache_new (first_token,
diff --git c/gcc/cp/pt.c w/gcc/cp/pt.c
index a7b7a12b59f..4e212620eaf 100644
--- c/gcc/cp/pt.c
+++ w/gcc/cp/pt.c
@@ -18077,7 +18077,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 			 && DECL_OMP_DECLARE_REDUCTION_P (decl)
 			 && DECL_FUNCTION_SCOPE_P (pattern_decl))
 		  {
-		    DECL_CONTEXT (decl) = NULL_TREE;
+		    /* We pretend this is regular local extern decl of
+		       a namespace-scope fn.  Then we make it really
+		       local, it is a nested function.  */
+		    DECL_CONTEXT (decl) = global_namespace;
 		    pushdecl (decl);
 		    DECL_CONTEXT (decl) = current_function_decl;
 		    cp_check_omp_declare_reduction (decl);
@@ -18899,7 +18902,7 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   if (t == NULL_TREE || t == error_mark_node)
     return;
 
-  gcc_assert (TREE_CODE (t) == STATEMENT_LIST);
+  gcc_assert (TREE_CODE (t) == STATEMENT_LIST && current_function_decl);
 
   tree_stmt_iterator tsi;
   int i;
@@ -18919,6 +18922,8 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 			     args, complain, in_decl);
       tree omp_in = tsubst (DECL_EXPR_DECL (stmts[1]),
 			    args, complain, in_decl);
+      /* tsubsting a local var_decl leaves DECL_CONTEXT null, as we
+	 expect to be pushing it.  */
       DECL_CONTEXT (omp_out) = current_function_decl;
       DECL_CONTEXT (omp_in) = current_function_decl;
       keep_next_level (true);

Reply via email to