Hi!

On Sat, Sep 21, 2013 at 07:45:03AM -0400, Jason Merrill wrote:

So, for things that worked fine for me, I'm attaching two patches
(W050b and W051a), do they look ok to you?  The rest causes issues, all
of them on gcc/testsuite/g++.dg/gomp/udr-3.C testcase, see below.

> On 09/20/2013 12:25 PM, Jakub Jelinek wrote:
> >In templates the UDRs are always FUNCTION_DECLs in classes or
> >at function block scope, the above one liner was I believe for the latter,
> >where without it duplicate_decls was returning incorrectly 0; the UDRs
> >from mismatching templates would actually never be seen by duplicate_decls,
> >but t1 was different from t2.  That was before the changes to
> >add the mangled names to the UDR DECL_NAMEs though, I can try to remove it
> >and see if the whole testsuite still passes.
> 
> Please.
> 
> >>>+    && ! (DECL_OMP_DECLARE_REDUCTION_P (newdecl)
> >>>+          && DECL_CONTEXT (newdecl) == NULL_TREE
> >>>+          && DECL_CONTEXT (olddecl) == current_function_decl))
> >>
> >>And this looks like you need to set DECL_CONTEXT sooner on reductions.
> >
> >I know it is ugly, but setting FUNCTION_DECL DECL_CONTEXT too early resulted
> >in all kinds of problems, when the C++ frontend doesn't support nested
> >functions.  So the patch doesn't set DECL_CONTEXT until it is pushdecled
> >into the block scope.
> 
> What is calling decls_match before pushdecl?

Ok, sorry for the delay, been busy with libgomp.
I've tried to remove the two decl.c changes, unfortunately it failed
miserably on the gcc/testsuite/g++.dg/gomp/udr-3.C testcase.
The problem isn't on valid OpenMP code where there shouldn't be any
duplicates anywhere, but during error diagnostics.  Without those two decl.c
hunks (either of them), pushdecl will sometimes return a different decl from
the original or error_mark_node, and the original fndecl passed to it has
ggc_free called on it, thus any further use of it ICEs or may ICE.
With the attached X1 patch I avoid the ICEs - if pushdecl doesn't return
the original fndecl, I treat it as an error that has been reported already,
unfortunately that still means many errors expected to be diagnosed aren't,
e.g. first one on line 71.  Perhaps if pushdecl returns error_mark_node,
then I'd should expect that the error has been reported already and if
it returns some other FUNCTION_DECL, then I should report it myself,
but a problem with that is that there are multiple locations that call
pushdecl (two in parser.c, one in pt.c) and more importantly, that for
the diagnostics the new fndecl is ggc_freed and thus I can't use it
for the diagnostics anymore.
Trying to set DECL_CONTEXT to non-NULL for block_scope UDRs leads to
immediate ICEs as I said earlier, again on udr-3.C testcase:
@@ -30179,7 +30179,10 @@ cp_parser_omp_declare_reduction (cp_pars
        {
          block_scope = true;
          if (!processing_template_decl)
-           pushdecl (fndecl);
+           {
+             DECL_CONTEXT (fndecl) = current_function_decl;
+             pushdecl (fndecl);
+           }
        }
       else if (current_class_type)
        {
#0  internal_error (gmsgid=0x15243c8 "tree check: %s, have %s in %s, at %s:%d") 
at ../../gcc/diagnostic.c:1127
#1  0x0000000000f6cc8e in tree_check_failed (node=0x7ffff1a2f600, 
file=0x144771e "../../gcc/cp/name-lookup.c", line=3392, 
    function=0x1448a70 <namespace_binding_1(tree_node*, 
tree_node*)::__FUNCTION__> "namespace_binding_1") at ../../gcc/tree.c:9321
#2  0x000000000055e725 in tree_check (__t=<function_decl 0x7ffff1a2f600 f1>, 
__f=0x144771e "../../gcc/cp/name-lookup.c", __l=3392, 
    __g=0x1448a70 <namespace_binding_1(tree_node*, tree_node*)::__FUNCTION__> 
"namespace_binding_1", __c=NAMESPACE_DECL) at ../../gcc/tree.h:2672
#3  0x00000000007ae8bc in namespace_binding_1 (name=<identifier_node 
0x7ffff1a269f8 omp declare reduction operator+~1T>, 
    scope=<function_decl 0x7ffff1a2f600 f1>) at ../../gcc/cp/name-lookup.c:3392
#4  0x00000000007ae9e8 in namespace_binding (name=<identifier_node 
0x7ffff1a269f8 omp declare reduction operator+~1T>, 
    scope=<function_decl 0x7ffff1a2f600 f1>) at ../../gcc/cp/name-lookup.c:3404
#5  0x00000000007a38db in pushdecl_maybe_friend_1 (x=<function_decl 
0x7ffff1a2fa00 omp declare reduction operator+~1T>, is_friend=false)
    at ../../gcc/cp/name-lookup.c:701
#6  0x00000000007a7521 in pushdecl_maybe_friend (x=<function_decl 
0x7ffff1a2fa00 omp declare reduction operator+~1T>, is_friend=false)
    at ../../gcc/cp/name-lookup.c:1264
#7  0x00000000007a7558 in pushdecl (x=<function_decl 0x7ffff1a2fa00 omp declare 
reduction operator+~1T>) at ../../gcc/cp/name-lookup.c:1274

pushdecl_maybe_friend_1 clearly doesn't expect anything to be in function scope,
and from what I remember from writing the UDR patch, it certainly wasn't the
only spot.

> >>>+      if (TREE_CODE (argtype) == REFERENCE_TYPE)
> >>>+        error_at (DECL_SOURCE_LOCATION (t),
> >>>+                  "function, array or reference type in "
> >>>+                  "%<#pragma omp declare reduction%>");
> >>
> >>Let's just say "reference type", since we know that's what it is.
> >
> >That is true, but I wanted to match the same error message elsewhere,
> >otherwise the error will be different (more specific) for instantiation
> >vs. in non-template code.
> 
> It's more important to be specific during instantiation because we
> can't always tell what the types involved actually are.  So let's
> also add the type in question to the diagnostic.

Ok, see attached W050b patch.

Other changes that worked fine (moving of finish_omp_clauses
OMP_CLAUSE_REDUCTION handling to a separate function, comment addition,
DECL_FUNCTION_SCOPE_P use, formatting) are in attached W051a patch.

> >I believe I need to discuss that on omp-lang, what exactly is the intended
> >behavior (and get the standard clarified).  Returning the first base class
> >is an option (and, depth-first vs. breadth-first?), or erroring out if more
> >than one base class has an UDR is another.
> 
> Normal C++ lookup behavior is to check for ambiguity, so I think
> that's the best bet for what the eventual defined semantics will be.

No response from omp-lang yet, so I'm not changing this yet.

> >>>+              if (DECL_TEMPLATE_INFO (id))
> >>>+                id = instantiate_decl (id, /*defer_ok*/0, true);
> >>
> >>Let's use mark_used instead.
> >
> >Will that always instantiate it?
> 
> In contexts where that makes sense, which I would expect to be all
> contexts where you can see a reduction.

Unfortunately it didn't work, again on the udr-3.C testcase.
mark_used was already called during instantiation of the decl, DECL_ODR_USED
got set on it, but it was actually deferred, then when mark_used is called
again on it, it is ignored.  I'd need to clear DECL_ODR_USED explicitly
and call mark_used, perhaps that would work.

As for not using INIT_EXPR and just use DECL_EXPR gimplification, the problem
is that we do not actually gimplify it with the OMP_PRIV decl which has that
DECL_INITIAL from the parsing, but a different one - the original var referenced
by the clause, and that can have completely different DECL_INITIAL, or none at
all.

        Jakub
2013-10-07  Jakub Jelinek  <ja...@redhat.com>

        * parser.c (cp_parser_omp_declare_reduction): Use different wording
        of error message between function/method/array type and reference type.
        Include %qT in the type related error messages.
        * semantics.c (cp_check_omp_declare_reduction): Likewise.
        * pt.c (tsubst_decl): Use reference type specific wording of error
        message.  Include %qT in the type related error messages.

--- gcc/cp/parser.c.jj  2013-10-07 10:56:11.000000000 +0200
+++ gcc/cp/parser.c     2013-10-07 12:32:22.506909617 +0200
@@ -30099,17 +30112,19 @@ cp_parser_omp_declare_reduction (cp_pars
                                   "min") == 0
                           || strcmp (IDENTIFIER_POINTER (orig_reduc_id),
                                      "max") == 0))))
-       error_at (loc, "predeclared arithmetic type in "
-                      "%<#pragma omp declare reduction%>");
+       error_at (loc, "predeclared arithmetic type in %qT"
+                      "%<#pragma omp declare reduction%>", type);
       else if (TREE_CODE (type) == FUNCTION_TYPE
               || TREE_CODE (type) == METHOD_TYPE
-              || TREE_CODE (type) == ARRAY_TYPE
-              || TREE_CODE (type) == REFERENCE_TYPE)
-       error_at (loc, "function, array or reference type in "
-                      "%<#pragma omp declare reduction%>");
+              || TREE_CODE (type) == ARRAY_TYPE)
+       error_at (loc, "function or array type %qT in "
+                      "%<#pragma omp declare reduction%>", type);
+      else if (TREE_CODE (type) == REFERENCE_TYPE)
+       error_at (loc, "reference type in %qT"
+                      "%<#pragma omp declare reduction%>", type);
       else if (TYPE_QUALS_NO_ADDR_SPACE (type))
-       error_at (loc, "const, volatile or __restrict qualified type in "
-                      "%<#pragma omp declare reduction%>");
+       error_at (loc, "const, volatile or __restrict qualified type %qT in "
+                      "%<#pragma omp declare reduction%>", type);
       else
        types.safe_push (type);
 
--- gcc/cp/pt.c.jj      2013-10-07 10:56:11.000000000 +0200
+++ gcc/cp/pt.c 2013-10-07 12:32:53.718746235 +0200
@@ -10413,8 +10413,8 @@ tsubst_decl (tree t, tree args, tsubst_f
            argtype = tsubst (argtype, args, complain, in_decl);
            if (TREE_CODE (argtype) == REFERENCE_TYPE)
              error_at (DECL_SOURCE_LOCATION (t),
-                       "function, array or reference type in "
-                       "%<#pragma omp declare reduction%>");
+                       "reference type %qT in "
+                       "%<#pragma omp declare reduction%>", argtype);
            if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)
              DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),
                                                argtype);
--- gcc/cp/semantics.c.jj       2013-09-25 09:51:45.000000000 +0200
+++ gcc/cp/semantics.c  2013-10-07 12:33:46.743467670 +0200
@@ -4775,24 +4775,29 @@ cp_check_omp_declare_reduction (tree udr
        }
       if (i < 8)
        {
-         error_at (loc, "predeclared arithmetic type in "
-                        "%<#pragma omp declare reduction%>");
+         error_at (loc, "predeclared arithmetic type %qT in "
+                        "%<#pragma omp declare reduction%>", type);
          return;
        }
     }
   else if (TREE_CODE (type) == FUNCTION_TYPE
           || TREE_CODE (type) == METHOD_TYPE
-          || TREE_CODE (type) == ARRAY_TYPE
-          || TREE_CODE (type) == REFERENCE_TYPE)
+          || TREE_CODE (type) == ARRAY_TYPE)
     {
-      error_at (loc, "function, array or reference type in "
-                    "%<#pragma omp declare reduction%>");
+      error_at (loc, "function or array type %qT in "
+                    "%<#pragma omp declare reduction%>", type);
+      return;
+    }
+  else if (TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      error_at (loc, "reference type %qT in %<#pragma omp declare reduction%>",
+               type);
       return;
     }
   else if (TYPE_QUALS_NO_ADDR_SPACE (type))
     {
-      error_at (loc, "const, volatile or __restrict qualified type in "
-                    "%<#pragma omp declare reduction%>");
+      error_at (loc, "const, volatile or __restrict qualified type %qT in "
+                    "%<#pragma omp declare reduction%>", type);
       return;
     }
 
--- gcc/testsuite/g++.dg/gomp/udr-1.C.jj        2013-09-18 12:43:23.000000000 
+0200
+++ gcc/testsuite/g++.dg/gomp/udr-1.C   2013-10-07 11:04:54.806701394 +0200
@@ -36,11 +36,11 @@ namespace N2
 namespace N3
 {
   void bar ();
-  #pragma omp declare reduction (| : __typeof (bar) : omp_out |= omp_in)// { 
dg-error "function, array or reference" }
-  #pragma omp declare reduction (+ : char () : omp_out += omp_in)      // { 
dg-error "function, array or reference" }
+  #pragma omp declare reduction (| : __typeof (bar) : omp_out |= omp_in)// { 
dg-error "function or array type" }
+  #pragma omp declare reduction (+ : char () : omp_out += omp_in)      // { 
dg-error "function or array type" }
   typedef short T;
-  #pragma omp declare reduction (min : T[2] : omp_out += omp_in)       // { 
dg-error "function, array or reference" }
-  #pragma omp declare reduction (baz : char & : omp_out *= omp_in)     // { 
dg-error "function, array or reference" }
+  #pragma omp declare reduction (min : T[2] : omp_out += omp_in)       // { 
dg-error "function or array type" }
+  #pragma omp declare reduction (baz : char & : omp_out *= omp_in)     // { 
dg-error "reference type" }
 }
 namespace N4
 {
@@ -48,21 +48,21 @@ namespace N4
   template <typename T1, typename T2, typename T3, typename T4>
   struct S
   {
-    #pragma omp declare reduction (| : T1 : omp_out |= omp_in)         // { 
dg-error "function, array or reference" }
-    #pragma omp declare reduction (+ : T2 : omp_out += omp_in)         // { 
dg-error "function, array or reference" }
+    #pragma omp declare reduction (| : T1 : omp_out |= omp_in)         // { 
dg-error "function or array type" }
+    #pragma omp declare reduction (+ : T2 : omp_out += omp_in)         // { 
dg-error "function or array type" }
     typedef T3 T;
-    #pragma omp declare reduction (min : T : omp_out += omp_in)                
// { dg-error "function, array or reference" }
-    #pragma omp declare reduction (baz : T4 : omp_out *= omp_in)       // { 
dg-error "function, array or reference" }
+    #pragma omp declare reduction (min : T : omp_out += omp_in)                
// { dg-error "function or array type" }
+    #pragma omp declare reduction (baz : T4 : omp_out *= omp_in)       // { 
dg-error "function or array type" }
   };
   S<__typeof (bar), char (), short [3], char []> s;
   template <typename T1, typename T2, typename T3, typename T4>
   int foo ()
   {
-    #pragma omp declare reduction (| : T1 : omp_out |= omp_in)         // { 
dg-error "function, array or reference" }
-    #pragma omp declare reduction (+ : T2 : omp_out += omp_in)         // { 
dg-error "function, array or reference" }
+    #pragma omp declare reduction (| : T1 : omp_out |= omp_in)         // { 
dg-error "function or array type" }
+    #pragma omp declare reduction (+ : T2 : omp_out += omp_in)         // { 
dg-error "function or array type" }
     typedef T3 T;
-    #pragma omp declare reduction (min : T : omp_out += omp_in)                
// { dg-error "function, array or reference" }
-    #pragma omp declare reduction (baz : T4 : omp_out *= omp_in)       // { 
dg-error "function, array or reference" }
+    #pragma omp declare reduction (min : T : omp_out += omp_in)                
// { dg-error "function or array type" }
+    #pragma omp declare reduction (baz : T4 : omp_out *= omp_in)       // { 
dg-error "function or array type" }
     return 0;
   }
   int x = foo <__typeof (bar), char (), short[], char [2]> ();
@@ -72,13 +72,13 @@ namespace N5
   template <typename T>
   struct S
   {
-    #pragma omp declare reduction (baz : T : omp_out *= omp_in)                
// { dg-error "function, array or reference" }
+    #pragma omp declare reduction (baz : T : omp_out *= omp_in)                
// { dg-error "reference type" }
   };
   S<char &> s;
   template <typename T>
   int foo ()
   {
-    #pragma omp declare reduction (baz : T : omp_out *= omp_in)                
// { dg-error "function, array or reference" }
+    #pragma omp declare reduction (baz : T : omp_out *= omp_in)                
// { dg-error "reference type" }
     return 0;
   }
   int x = foo <char &> ();
2013-10-07  Jakub Jelinek  <ja...@redhat.com>

        * parser.c (cp_parser_omp_declare_reduction_exprs): Document the
        statements in the artificial function body of UDRs.
        * pt.c (tsubst_expr): Use DECL_FUNCTION_SCOPE_P macro for UDRs.
        (tsubst_omp_udr): Refer to cp_parser_omp_declare_reduction_exprs
        in function comment.
        (finish_omp_reduction_clause): New function.
        (finish_omp_clauses): Use it.
        * cp-gimplify.c (cxx_omp_privatize_by_reference): Fix up formatting.

--- gcc/cp/parser.c.jj  2013-10-07 11:01:03.000000000 +0200
+++ gcc/cp/parser.c     2013-10-07 11:23:26.967735597 +0200
@@ -29865,7 +29865,20 @@ cp_parser_omp_end_declare_target (cp_par
 
 /* Helper function of cp_parser_omp_declare_reduction.  Parse the combiner
    expression and optional initializer clause of
-   #pragma omp declare reduction.  */
+   #pragma omp declare reduction.  We store the expression(s) as
+   either 3, 6 or 7 special statements inside of the artificial function's
+   body.  The first two statements are DECL_EXPRs for the artificial
+   OMP_OUT resp. OMP_IN variables, followed by a statement with the combiner
+   expression that uses those variables.
+   If there was any INITIALIZER clause, this is followed by further statements,
+   the fourth and fifth statements are DECL_EXPRs for the artificial
+   OMP_PRIV resp. OMP_ORIG variables.  If the INITIALIZER clause wasn't the
+   constructor variant (first token after open paren is not omp_priv),
+   then the sixth statement is a statement with the function call expression
+   that uses the OMP_PRIV and optionally OMP_ORIG variable.
+   Otherwise, the sixth statement is whatever statement cp_finish_decl emits
+   to initialize the OMP_PRIV artificial variable and there is seventh
+   statement, a DECL_EXPR of the OMP_PRIV statement again.  */
 
 static bool
 cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser)
--- gcc/cp/pt.c.jj      2013-10-07 11:01:26.000000000 +0200
+++ gcc/cp/pt.c 2013-10-07 11:16:14.312053430 +0200
@@ -13256,9 +13256,7 @@ tsubst_expr (tree t, tree args, tsubst_f
                  /* We already did a pushtag.  */;
                else if (TREE_CODE (decl) == FUNCTION_DECL
                         && DECL_OMP_DECLARE_REDUCTION_P (decl)
-                        && DECL_CONTEXT (pattern_decl)
-                        && TREE_CODE (DECL_CONTEXT (pattern_decl))
-                           == FUNCTION_DECL)
+                        && DECL_FUNCTION_SCOPE_P (pattern_decl))
                  {
                    DECL_CONTEXT (decl) = NULL_TREE;
                    pushdecl (decl);
@@ -13771,7 +13769,8 @@ tsubst_expr (tree t, tree args, tsubst_f
 }
 
 /* Instantiate the special body of the artificial DECL_OMP_DECLARE_REDUCTION
-   function.  */
+   function.  For description of the body see comment above
+   cp_parser_omp_declare_reduction_exprs.  */
 
 static void
 tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
--- gcc/cp/semantics.c.jj       2013-10-07 11:05:18.000000000 +0200
+++ gcc/cp/semantics.c  2013-10-07 12:03:55.676926652 +0200
@@ -4881,6 +4881,200 @@ find_omp_placeholder_r (tree *tp, int *,
   return NULL_TREE;
 }
 
+/* Helper function of finish_omp_clauses.  Handle OMP_CLAUSE_REDUCTION C.
+   Return true if there is some error and the clause should be removed.  */
+
+static bool
+finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
+{
+  tree t = OMP_CLAUSE_DECL (c);
+  bool predefined = false;
+  tree type = TREE_TYPE (t);
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
+  if (ARITHMETIC_TYPE_P (type))
+    switch (OMP_CLAUSE_REDUCTION_CODE (c))
+      {
+      case PLUS_EXPR:
+      case MULT_EXPR:
+      case MINUS_EXPR:
+       predefined = true;
+       break;
+      case MIN_EXPR:
+      case MAX_EXPR:
+       if (TREE_CODE (type) == COMPLEX_TYPE)
+         break;
+       predefined = true;
+       break;
+      case BIT_AND_EXPR:
+      case BIT_IOR_EXPR:
+      case BIT_XOR_EXPR:
+      case TRUTH_ANDIF_EXPR:
+      case TRUTH_ORIF_EXPR:
+       if (FLOAT_TYPE_P (type))
+         break;
+       predefined = true;
+       break;
+      default:
+       break;
+      }
+  else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type))
+    {
+      error ("%qE has invalid type for %<reduction%>", t);
+      return true;
+    }
+  else if (!processing_template_decl)
+    {
+      t = require_complete_type (t);
+      if (t == error_mark_node)
+       return true;
+      OMP_CLAUSE_DECL (c) = t;
+    }
+
+  if (predefined)
+    {
+      OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
+      return false;
+    }
+  else if (processing_template_decl)
+    return false;
+
+  tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+
+  type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
+  OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
+  if (id == NULL_TREE)
+    id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c),
+                          NULL_TREE, NULL_TREE);
+  id = omp_reduction_lookup (OMP_CLAUSE_LOCATION (c), id, type);
+  if (id)
+    {
+      id = OVL_CURRENT (id);
+      if (DECL_TEMPLATE_INFO (id))
+       id = instantiate_decl (id, /*defer_ok*/0, true);
+      tree body = DECL_SAVED_TREE (id);
+      if (TREE_CODE (body) == STATEMENT_LIST)
+       {
+         tree_stmt_iterator tsi;
+         tree placeholder = NULL_TREE;
+         int i;
+         tree stmts[7];
+         tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id)));
+         atype = TREE_TYPE (atype);
+         bool need_static_cast = !same_type_p (type, atype);
+         memset (stmts, 0, sizeof stmts);
+         for (i = 0, tsi = tsi_start (body);
+              i < 7 && !tsi_end_p (tsi);
+              i++, tsi_next (&tsi))
+           stmts[i] = tsi_stmt (tsi);
+         gcc_assert (tsi_end_p (tsi));
+
+         if (i >= 3)
+           {
+             gcc_assert (TREE_CODE (stmts[0]) == DECL_EXPR
+                         && TREE_CODE (stmts[1]) == DECL_EXPR);
+             placeholder = build_lang_decl (VAR_DECL, NULL_TREE, type);
+             DECL_ARTIFICIAL (placeholder) = 1;
+             DECL_IGNORED_P (placeholder) = 1;
+             OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
+             if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0])))
+               cxx_mark_addressable (placeholder);
+             if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1]))
+                 && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
+                    != REFERENCE_TYPE)
+               cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+             tree omp_out = placeholder;
+             tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c));
+             if (need_static_cast)
+               {
+                 tree ptype = build_pointer_type (atype);
+                 omp_out = build_fold_addr_expr (omp_out);
+                 omp_out = build_static_cast (ptype, omp_out,
+                                              tf_warning_or_error);
+                 omp_in = build_fold_addr_expr (omp_in);
+                 omp_in = build_static_cast (ptype, omp_in,
+                                             tf_warning_or_error);
+                 if (omp_out == error_mark_node || omp_in == error_mark_node)
+                   return true;
+                 omp_out = build1 (INDIRECT_REF, atype, omp_out);
+                 omp_in = build1 (INDIRECT_REF, atype, omp_in);
+               }
+             OMP_CLAUSE_REDUCTION_MERGE (c)
+               = clone_omp_udr (stmts[2], DECL_EXPR_DECL (stmts[0]),
+                                DECL_EXPR_DECL (stmts[1]), omp_in, omp_out);
+           }
+         if (i >= 6)
+           {
+             gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR
+                         && TREE_CODE (stmts[4]) == DECL_EXPR);
+             if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3])))
+               cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+             if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4])))
+               cxx_mark_addressable (placeholder);
+             tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c));
+             tree omp_orig = placeholder;
+             if (need_static_cast)
+               {
+                 if (i == 7)
+                   {
+                     error_at (OMP_CLAUSE_LOCATION (c),
+                               "user defined reduction with constructor "
+                               "initializer for base class %qT", atype);
+                     return true;
+                   }
+                 tree ptype = build_pointer_type (atype);
+                 omp_priv = build_fold_addr_expr (omp_priv);
+                 omp_priv = build_static_cast (ptype, omp_priv,
+                                               tf_warning_or_error);
+                 omp_orig = build_fold_addr_expr (omp_orig);
+                 omp_orig = build_static_cast (ptype, omp_orig,
+                                               tf_warning_or_error);
+                 if (omp_priv == error_mark_node
+                     || omp_orig == error_mark_node)
+                   return true;
+                 omp_priv = build1 (INDIRECT_REF, atype, omp_priv);
+                 omp_orig = build1 (INDIRECT_REF, atype, omp_orig);
+               }
+             if (i == 6)
+               *need_default_ctor = true;
+             OMP_CLAUSE_REDUCTION_INIT (c)
+               = clone_omp_udr (stmts[5], DECL_EXPR_DECL (stmts[4]),
+                                DECL_EXPR_DECL (stmts[3]),
+                                omp_priv, omp_orig);
+             if (cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
+                               find_omp_placeholder_r, placeholder, NULL))
+               OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1;
+           }
+         else if (i >= 3)
+           {
+             if (CLASS_TYPE_P (type) && !pod_type_p (type))
+               *need_default_ctor = true;
+             else
+               {
+                 tree init;
+                 tree v = convert_from_reference (t);
+                 if (AGGREGATE_TYPE_P (TREE_TYPE (v)))
+                   init = build_constructor (TREE_TYPE (v), NULL);
+                 else
+                   init = fold_convert (TREE_TYPE (v), integer_zero_node);
+                 OMP_CLAUSE_REDUCTION_INIT (c)
+                   = build2 (INIT_EXPR, TREE_TYPE (v), v, init);
+               }
+           }
+       }
+    }
+  if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+    *need_dtor = true;
+  else
+    {
+      error ("user defined reduction not found for %qD", t);
+      return true;
+    }
+  return false;
+}
+
 /* For all elements of CLAUSES, validate them vs OpenMP constraints.
    Remove any elements from the list that are invalid.  */
 
@@ -5481,221 +5675,12 @@ finish_omp_clauses (tree clauses)
          break;
 
        case OMP_CLAUSE_REDUCTION:
-         {
-           bool predefined = false;
-           tree type = TREE_TYPE (t);
-           if (TREE_CODE (type) == REFERENCE_TYPE)
-             type = TREE_TYPE (type);
-           if (ARITHMETIC_TYPE_P (type))
-             switch (OMP_CLAUSE_REDUCTION_CODE (c))
-               {
-               case PLUS_EXPR:
-               case MULT_EXPR:
-               case MINUS_EXPR:
-                 predefined = true;
-                 break;
-               case MIN_EXPR:
-               case MAX_EXPR:
-                 if (TREE_CODE (type) == COMPLEX_TYPE)
-                   break;
-                 predefined = true;
-                 break;
-               case BIT_AND_EXPR:
-               case BIT_IOR_EXPR:
-               case BIT_XOR_EXPR:
-               case TRUTH_ANDIF_EXPR:
-               case TRUTH_ORIF_EXPR:
-                 if (FLOAT_TYPE_P (type))
-                   break;
-                 predefined = true;
-                 break;
-               default:
-                 break;
-               }
-           else if (TREE_CODE (type) == ARRAY_TYPE
-                    || TYPE_READONLY (type))
-             {
-               error ("%qE has invalid type for %<reduction%>", t);
-               remove = true;
-               break;
-             }
-           else if (!processing_template_decl)
-             {
-               t = require_complete_type (t);
-               if (t == error_mark_node)
-                 {
-                   remove = true;
-                   break;
-                 }
-             }
-           if (predefined)
-             {
-               OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
-             }
-           else if (!processing_template_decl)
-             {
-               tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
-
-               type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
-               if (TREE_CODE (type) == REFERENCE_TYPE)
-                 type = TREE_TYPE (type);
-               OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
-               if (id == NULL_TREE)
-                 id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c),
-                                        NULL_TREE, NULL_TREE);
-               id = omp_reduction_lookup (OMP_CLAUSE_LOCATION (c), id, type);
-               if (id)
-                 {
-                   id = OVL_CURRENT (id);
-                   if (DECL_TEMPLATE_INFO (id))
-                     id = instantiate_decl (id, /*defer_ok*/0, true);
-                   tree body = DECL_SAVED_TREE (id);
-                   if (TREE_CODE (body) == STATEMENT_LIST)
-                     {
-                       tree_stmt_iterator tsi;
-                       tree placeholder = NULL_TREE;
-                       int i;
-                       tree stmts[7];
-                       tree atype
-                         = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id)));
-                       atype = TREE_TYPE (atype);
-                       bool need_static_cast = !same_type_p (type, atype);
-                       memset (stmts, 0, sizeof stmts);
-                       for (i = 0, tsi = tsi_start (body);
-                            i < 7 && !tsi_end_p (tsi);
-                            i++, tsi_next (&tsi))
-                         stmts[i] = tsi_stmt (tsi);
-                       gcc_assert (tsi_end_p (tsi));
-                       if (i >= 3)
-                         {
-                           gcc_assert (TREE_CODE (stmts[0]) == DECL_EXPR
-                                       && TREE_CODE (stmts[1]) == DECL_EXPR);
-                           placeholder
-                             = build_lang_decl (VAR_DECL, NULL_TREE, type);
-                           DECL_ARTIFICIAL (placeholder) = 1;
-                           DECL_IGNORED_P (placeholder) = 1;
-                           OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
-                           if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0])))
-                             cxx_mark_addressable (placeholder);
-                           if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1]))
-                               && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
-                                  != REFERENCE_TYPE)
-                             cxx_mark_addressable (OMP_CLAUSE_DECL (c));
-                           tree omp_out = placeholder;
-                           tree omp_in
-                             = convert_from_reference (OMP_CLAUSE_DECL (c));
-                           if (need_static_cast)
-                             {
-                               tree ptype = build_pointer_type (atype);
-                               omp_out = build_fold_addr_expr (omp_out);
-                               omp_out
-                                 = build_static_cast (ptype, omp_out,
-                                                      tf_warning_or_error);
-                               omp_in = build_fold_addr_expr (omp_in);
-                               omp_in
-                                 = build_static_cast (ptype, omp_in,
-                                                      tf_warning_or_error);
-                               if (omp_out == error_mark_node
-                                   || omp_in == error_mark_node)
-                                 {
-                                   remove = true;
-                                   break;
-                                 }
-                               omp_out
-                                 = build1 (INDIRECT_REF, atype, omp_out);
-                               omp_in
-                                 = build1 (INDIRECT_REF, atype, omp_in);
-                             }
-                           OMP_CLAUSE_REDUCTION_MERGE (c)
-                             = clone_omp_udr (stmts[2],
-                                              DECL_EXPR_DECL (stmts[0]),
-                                              DECL_EXPR_DECL (stmts[1]),
-                                              omp_in, omp_out);
-                         }
-                       if (i >= 6)
-                         {
-                           gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR
-                                       && TREE_CODE (stmts[4]) == DECL_EXPR);
-                           if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3])))
-                             cxx_mark_addressable (OMP_CLAUSE_DECL (c));
-                           if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4])))
-                             cxx_mark_addressable (placeholder);
-                           tree omp_priv
-                             = convert_from_reference (OMP_CLAUSE_DECL (c));
-                           tree omp_orig = placeholder;
-                           if (need_static_cast)
-                             {
-                               if (i == 7)
-                                 {
-                                   error_at (OMP_CLAUSE_LOCATION (c),
-                                             "user defined reduction with "
-                                             "constructor initializer for "
-                                             "base class %qT", atype);
-                                   remove = true;
-                                   break;
-                                 }
-                               tree ptype = build_pointer_type (atype);
-                               omp_priv = build_fold_addr_expr (omp_priv);
-                               omp_priv
-                                 = build_static_cast (ptype, omp_priv,
-                                                      tf_warning_or_error);
-                               omp_orig = build_fold_addr_expr (omp_orig);
-                               omp_orig
-                                 = build_static_cast (ptype, omp_orig,
-                                                      tf_warning_or_error);
-                               if (omp_priv == error_mark_node
-                                   || omp_orig == error_mark_node)
-                                 {
-                                   remove = true;
-                                   break;
-                                 }
-                               omp_priv
-                                 = build1 (INDIRECT_REF, atype, omp_priv);
-                               omp_orig
-                                 = build1 (INDIRECT_REF, atype, omp_orig);
-                             }
-                           if (i == 6)
-                             need_default_ctor = true;
-                           OMP_CLAUSE_REDUCTION_INIT (c)
-                             = clone_omp_udr (stmts[5],
-                                              DECL_EXPR_DECL (stmts[4]),
-                                              DECL_EXPR_DECL (stmts[3]),
-                                              omp_priv, omp_orig);
-                           if (cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
-                                             find_omp_placeholder_r,
-                                             placeholder, NULL))
-                             OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1;
-                         }
-                       else if (i >= 3)
-                         {
-                           if (CLASS_TYPE_P (type) && !pod_type_p (type))
-                             need_default_ctor = true;
-                           else
-                             {
-                               tree init;
-                               tree v = convert_from_reference (t);
-                               if (AGGREGATE_TYPE_P (TREE_TYPE (v)))
-                                 init = build_constructor (TREE_TYPE (v),
-                                                           NULL);
-                               else
-                                 init = fold_convert (TREE_TYPE (v),
-                                                      integer_zero_node);
-                               OMP_CLAUSE_REDUCTION_INIT (c)
-                                 = build2 (INIT_EXPR, TREE_TYPE (v), v, init);
-                             }
-                         }
-                     }
-                 }
-               if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
-                 need_dtor = true;
-               else
-                 {
-                   error ("user defined reduction not found for %qD", t);
-                   remove = true;
-                 }
-             }
-           break;
-         }
+         if (finish_omp_reduction_clause (c, &need_default_ctor,
+                                          &need_dtor))
+           remove = true;
+         else
+           t = OMP_CLAUSE_DECL (c);
+         break;
 
        case OMP_CLAUSE_COPYIN:
          if (!VAR_P (t) || !DECL_THREAD_LOCAL_P (t))
--- gcc/cp/cp-gimplify.c.jj     2013-09-18 12:43:23.000000000 +0200
+++ gcc/cp/cp-gimplify.c        2013-10-07 11:14:57.881462845 +0200
@@ -1415,8 +1415,8 @@ cxx_omp_clause_dtor (tree clause, tree d
 bool
 cxx_omp_privatize_by_reference (const_tree decl)
 {
-  return TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
-        || is_invisiref_parm (decl);
+  return (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+         || is_invisiref_parm (decl));
 }
 
 /* Return true if DECL is const qualified var having no mutable member.  */
--- gcc/cp/decl.c.jj    2013-09-18 12:43:23.000000000 +0200
+++ gcc/cp/decl.c       2013-10-07 10:40:39.711514812 +0200
@@ -978,15 +978,12 @@ decls_match (tree newdecl, tree olddecl)
       tree t2 = (DECL_USE_TEMPLATE (olddecl)
                 ? DECL_TI_TEMPLATE (olddecl)
                 : NULL_TREE);
-      if (t1 != t2 && !DECL_OMP_DECLARE_REDUCTION_P (newdecl))
+      if (t1 != t2)
        return 0;
 
       if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)
          && ! (DECL_EXTERN_C_P (newdecl)
-               && DECL_EXTERN_C_P (olddecl))
-         && ! (DECL_OMP_DECLARE_REDUCTION_P (newdecl)
-               && DECL_CONTEXT (newdecl) == NULL_TREE
-               && DECL_CONTEXT (olddecl) == current_function_decl))
+               && DECL_EXTERN_C_P (olddecl)))
        return 0;
 
       /* A new declaration doesn't match a built-in one unless it
--- gcc/cp/parser.c.jj  2013-09-25 09:51:45.000000000 +0200
+++ gcc/cp/parser.c     2013-10-07 10:51:23.723053886 +0200
@@ -30164,7 +30164,8 @@ cp_parser_omp_declare_reduction (cp_pars
        {
          block_scope = true;
          if (!processing_template_decl)
-           pushdecl (fndecl);
+           if (pushdecl (fndecl) != fndecl)
+             goto fail;
        }
       else if (current_class_type)
        {
@@ -30189,7 +30190,8 @@ cp_parser_omp_declare_reduction (cp_pars
       else
        {
          DECL_CONTEXT (fndecl) = current_namespace;
-         pushdecl (fndecl);
+         if (pushdecl (fndecl) != fndecl)
+           goto fail;
        }
       if (!block_scope)
        start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED);
--- gcc/cp/pt.c.jj      2013-09-25 09:51:45.000000000 +0200
+++ gcc/cp/pt.c 2013-10-07 10:53:02.661520627 +0200
@@ -13262,9 +13262,11 @@ tsubst_expr (tree t, tree args, tsubst_f
                            == FUNCTION_DECL)
                  {
                    DECL_CONTEXT (decl) = NULL_TREE;
-                   pushdecl (decl);
-                   DECL_CONTEXT (decl) = current_function_decl;
-                   cp_check_omp_declare_reduction (decl);
+                   if (pushdecl (decl) == decl)
+                     {
+                       DECL_CONTEXT (decl) = current_function_decl;
+                       cp_check_omp_declare_reduction (decl);
+                     }
                  }
                else
                  {

Reply via email to