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 {