Hi! I've backported 11 patches of mine to 4.6 branch, bootstrapped/regtested on x86_64-linux and i686-linux, committed.
Jakub
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-03-01 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/52445 * tree-ssa-phiopt.c (struct name_to_bb): Remove ssa_name field, add ssa_name_ver, offset and size fields and change store field to bool. (name_to_bb_hash, name_to_bb_eq): Adjust for the above changes. (add_or_mark_expr): Likewise. Only consider previous stores with the same size and offset. (nt_init_block): Only look at gimple_assign_single_p stmts, doesn't look at rhs2. * gcc.dg/pr52445.c: New test. --- gcc/tree-ssa-phiopt.c (revision 184742) +++ gcc/tree-ssa-phiopt.c (revision 184743) @@ -1122,9 +1122,10 @@ abs_replacement (basic_block cond_bb, ba same accesses. */ struct name_to_bb { - tree ssa_name; + unsigned int ssa_name_ver; + bool store; + HOST_WIDE_INT offset, size; basic_block bb; - unsigned store : 1; }; /* The hash table for remembering what we've seen. */ @@ -1133,23 +1134,26 @@ static htab_t seen_ssa_names; /* The set of MEM_REFs which can't trap. */ static struct pointer_set_t *nontrap_set; -/* The hash function, based on the pointer to the pointer SSA_NAME. */ +/* The hash function. */ static hashval_t name_to_bb_hash (const void *p) { - const_tree n = ((const struct name_to_bb *)p)->ssa_name; - return htab_hash_pointer (n) ^ ((const struct name_to_bb *)p)->store; + const struct name_to_bb *n = (const struct name_to_bb *) p; + return n->ssa_name_ver ^ (((hashval_t) n->store) << 31) + ^ (n->offset << 6) ^ (n->size << 3); } -/* The equality function of *P1 and *P2. SSA_NAMEs are shared, so - it's enough to simply compare them for equality. */ +/* The equality function of *P1 and *P2. */ static int name_to_bb_eq (const void *p1, const void *p2) { const struct name_to_bb *n1 = (const struct name_to_bb *)p1; const struct name_to_bb *n2 = (const struct name_to_bb *)p2; - return n1->ssa_name == n2->ssa_name && n1->store == n2->store; + return n1->ssa_name_ver == n2->ssa_name_ver + && n1->store == n2->store + && n1->offset == n2->offset + && n1->size == n2->size; } /* We see the expression EXP in basic block BB. If it's an interesting @@ -1161,8 +1165,12 @@ static void add_or_mark_expr (basic_block bb, tree exp, struct pointer_set_t *nontrap, bool store) { + HOST_WIDE_INT size; + if (TREE_CODE (exp) == MEM_REF - && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME) + && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME + && host_integerp (TREE_OPERAND (exp, 1), 0) + && (size = int_size_in_bytes (TREE_TYPE (exp))) > 0) { tree name = TREE_OPERAND (exp, 0); struct name_to_bb map; @@ -1172,9 +1180,12 @@ add_or_mark_expr (basic_block bb, tree e /* Try to find the last seen MEM_REF through the same SSA_NAME, which can trap. */ - map.ssa_name = name; + map.ssa_name_ver = SSA_NAME_VERSION (name); map.bb = 0; map.store = store; + map.offset = tree_low_cst (TREE_OPERAND (exp, 1), 0); + map.size = size; + slot = htab_find_slot (seen_ssa_names, &map, INSERT); n2bb = (struct name_to_bb *) *slot; if (n2bb) @@ -1197,9 +1208,11 @@ add_or_mark_expr (basic_block bb, tree e else { n2bb = XNEW (struct name_to_bb); - n2bb->ssa_name = name; + n2bb->ssa_name_ver = SSA_NAME_VERSION (name); n2bb->bb = bb; n2bb->store = store; + n2bb->offset = map.offset; + n2bb->size = size; *slot = n2bb; } } @@ -1219,13 +1232,10 @@ nt_init_block (struct dom_walk_data *dat { gimple stmt = gsi_stmt (gsi); - if (is_gimple_assign (stmt)) + if (gimple_assign_single_p (stmt)) { add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true); add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false); - if (get_gimple_rhs_num_ops (gimple_assign_rhs_code (stmt)) > 1) - add_or_mark_expr (bb, gimple_assign_rhs2 (stmt), nontrap_set, - false); } } } --- gcc/testsuite/gcc.dg/pr52445.c (revision 0) +++ gcc/testsuite/gcc.dg/pr52445.c (revision 184743) @@ -0,0 +1,15 @@ +/* PR tree-optimization/52445 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-cselim -fdump-tree-cselim" } */ + +void +foo (char *buf, unsigned long len) +{ + buf[0] = '\n'; + if (len > 1) + buf[1] = '\0'; /* We can't cselim "optimize" this, while + buf[0] doesn't trap, buf[1] could. */ +} + +/* { dg-final { scan-tree-dump-not "cstore\." "cselim" } } */ +/* { dg-final { cleanup-tree-dump "cselim" } } */
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-03-22 Jakub Jelinek <ja...@redhat.com> PR middle-end/52547 * tree-nested.c (convert_tramp_reference_stmt): Call declare_vars on any new_local_var_chain vars declared during recursing on GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK body. * testsuite/libgomp.c/pr52547.c: New test. --- gcc/tree-nested.c (revision 185706) +++ gcc/tree-nested.c (revision 185707) @@ -1954,6 +1954,7 @@ static tree convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, struct walk_stmt_info *wi) { + struct nesting_info *info = (struct nesting_info *) wi->info; gimple stmt = gsi_stmt (*gsi); switch (gimple_code (stmt)) @@ -1966,16 +1967,33 @@ convert_tramp_reference_stmt (gimple_stm for (i = 0; i < nargs; i++) walk_tree (gimple_call_arg_ptr (stmt, i), convert_tramp_reference_op, wi, NULL); + break; + } - *handled_ops_p = true; - return NULL_TREE; + case GIMPLE_OMP_PARALLEL: + case GIMPLE_OMP_TASK: + { + tree save_local_var_chain; + walk_gimple_op (stmt, convert_tramp_reference_op, wi); + save_local_var_chain = info->new_local_var_chain; + info->new_local_var_chain = NULL; + walk_body (convert_tramp_reference_stmt, convert_tramp_reference_op, + info, gimple_omp_body (stmt)); + if (info->new_local_var_chain) + declare_vars (info->new_local_var_chain, + gimple_seq_first_stmt (gimple_omp_body (stmt)), + false); + info->new_local_var_chain = save_local_var_chain; } + break; default: + *handled_ops_p = false; + return NULL_TREE; break; } - *handled_ops_p = false; + *handled_ops_p = true; return NULL_TREE; } --- libgomp/testsuite/libgomp.c/pr52547.c (revision 0) +++ libgomp/testsuite/libgomp.c/pr52547.c (revision 185707) @@ -0,0 +1,36 @@ +/* PR middle-end/52547 */ +/* { dg-do run } */ + +extern void abort (void); + +__attribute__((noinline, noclone)) int +baz (int *x, int (*fn) (int *)) +{ + return fn (x); +} + +__attribute__((noinline, noclone)) int +foo (int x, int *y) +{ + int i, e = 0; +#pragma omp parallel for reduction(|:e) + for (i = 0; i < x; ++i) + { + __label__ lab; + int bar (int *z) { return z - y; } + if (baz (&y[i], bar) != i) + e |= 1; + } + return e; +} + +int +main () +{ + int a[100], i; + for (i = 0; i < 100; i++) + a[i] = i; + if (foo (100, a)) + abort (); + return 0; +}
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-05-03 Jakub Jelinek <ja...@redhat.com> PR debug/53174 * tree-predcom.c (remove_stmt): Call reset_debug_uses on stmts being removed. * gcc.dg/pr53174.c: New test. --- gcc/tree-predcom.c (revision 187086) +++ gcc/tree-predcom.c (revision 187087) @@ -1707,6 +1707,7 @@ remove_stmt (gimple stmt) { name = PHI_RESULT (stmt); next = single_nonlooparound_use (name); + reset_debug_uses (stmt); psi = gsi_for_stmt (stmt); remove_phi_node (&psi, true); @@ -1728,6 +1729,7 @@ remove_stmt (gimple stmt) gcc_assert (TREE_CODE (name) == SSA_NAME); next = single_nonlooparound_use (name); + reset_debug_uses (stmt); mark_virtual_ops_for_renaming (stmt); gsi_remove (&bsi, true); --- gcc/testsuite/gcc.dg/pr53174.c (revision 0) +++ gcc/testsuite/gcc.dg/pr53174.c (revision 187087) @@ -0,0 +1,67 @@ +/* PR debug/53174 */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -g" } */ + +int w, h; + +void +bar (float (*x)[4], int y, int z) +{ + int a, b, c, d, e, f, g; + + a = 2; + b = 2; + c = 274; + d = 274; + if (!z) + a = 12; + if (!y) + b = 12; + if (z + 266 >= h - 2) + c = 8 + h - z; + if (y + 266 >= w - 2) + d = 8 + w - y; + for (e = a; e < c; e++) + for (f = b, g = e * 276 + f; f < d; f++, g++) + { + float (*h)[4] = x + (g - 277); + float k = (*h)[0]; + float l = (*h)[1]; + float m = (*h)[2]; + h++; + k += (*h)[0]; + l += (*h)[1]; + m += (*h)[2]; + h++; + k += (*h)[0]; + l += (*h)[1]; + m += (*h)[2]; + h += 274; + k += (*h)[0]; + l += (*h)[1]; + m += (*h)[2]; + h += 2; + k += (*h)[0]; + l += (*h)[1]; + m += (*h)[2]; + h += 274; + k += (*h)[0]; + l += (*h)[1]; + m += (*h)[2]; + h++; + k += (*h)[0]; + l += (*h)[1]; + m += (*h)[2]; + h++; + k += (*h)[0]; + l += (*h)[1]; + m += (*h)[2]; + k *= 0.125f; + l *= 0.125f; + m *= 0.125f; + k = k + (x[g][1] - l); + m = m + (x[g][1] - l); + x[g][0] = k; + x[g][2] = m; + } +}
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-08-24 Jakub Jelinek <ja...@redhat.com> PR c/54363 * gimplify.c (optimize_compound_literals_in_ctor): Only recurse if init is a CONSTRUCTOR. * gcc.dg/pr54363.c: New test. --- gcc/gimplify.c (revision 190656) +++ gcc/gimplify.c (revision 190657) @@ -3857,7 +3857,8 @@ optimize_compound_literals_in_ctor (tree if (!TREE_ADDRESSABLE (value) && !TREE_ADDRESSABLE (decl) - && init) + && init + && TREE_CODE (init) == CONSTRUCTOR) newval = optimize_compound_literals_in_ctor (init); } if (newval == value) --- gcc/testsuite/gcc.dg/pr54363.c (revision 0) +++ gcc/testsuite/gcc.dg/pr54363.c (revision 190657) @@ -0,0 +1,12 @@ +/* PR c/54363 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99" } */ + +struct S { char **a; }; + +void +test (void) +{ + struct S b = { .a = (char **) { "a", "b" } }; /* { dg-warning "(initialization|excess elements)" } */ + struct S c = { .a = (char *[]) { "a", "b" } }; +}
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-09-05 Jakub Jelinek <ja...@redhat.com> PR middle-end/54486 * builtins.c (fold_builtin_strspn, fold_builtin_strcspn): Use build_int_cst with size_type_node instead of size_int. * c-c++-common/pr54486.c: New test. --- gcc/builtins.c (revision 190985) +++ gcc/builtins.c (revision 190986) @@ -11890,7 +11890,7 @@ fold_builtin_strspn (location_t loc, tre if (p1 && p2) { const size_t r = strspn (p1, p2); - return size_int (r); + return build_int_cst (size_type_node, r); } /* If either argument is "", return NULL_TREE. */ @@ -11935,7 +11935,7 @@ fold_builtin_strcspn (location_t loc, tr if (p1 && p2) { const size_t r = strcspn (p1, p2); - return size_int (r); + return build_int_cst (size_type_node, r); } /* If the first argument is "", return NULL_TREE. */ --- gcc/testsuite/c-c++-common/pr54486.c (revision 0) +++ gcc/testsuite/c-c++-common/pr54486.c (revision 190986) @@ -0,0 +1,32 @@ +/* PR middle-end/54486 */ +/* { dg-do compile } */ +/* { dg-options "-Wformat" } */ + +#ifdef __cplusplus +extern "C" { +#endif +typedef __SIZE_TYPE__ size_t; +extern int printf (const char *, ...); +extern size_t strspn (const char *, const char *); +extern size_t strcspn (const char *, const char *); +extern size_t strlen (const char *); +#ifdef __cplusplus +} +#endif + +void +foo (void) +{ + printf ("%zu\n", strspn ("abc", "abcdefg")); + printf ("%zu\n", (size_t) strspn ("abc", "abcdefg")); + printf ("%zu\n", __builtin_strspn ("abc", "abcdefg")); + printf ("%zu\n", (size_t) __builtin_strspn ("abc", "abcdefg")); + printf ("%zu\n", strcspn ("abc", "abcdefg")); + printf ("%zu\n", (size_t) strcspn ("abc", "abcdefg")); + printf ("%zu\n", __builtin_strcspn ("abc", "abcdefg")); + printf ("%zu\n", (size_t) __builtin_strcspn ("abc", "abcdefg")); + printf ("%zu\n", strlen ("abc")); + printf ("%zu\n", (size_t) strlen ("abc")); + printf ("%zu\n", __builtin_strlen ("abc")); + printf ("%zu\n", (size_t) __builtin_strlen ("abc")); +}
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2012-10-08 Jakub Jelinek <ja...@redhat.com> PR c++/54858 * tree.c (cp_tree_equal): Handle FIELD_DECL. * g++.dg/template/pr54858.C: New test. --- gcc/cp/tree.c (revision 192219) +++ gcc/cp/tree.c (revision 192220) @@ -2559,6 +2559,7 @@ cp_tree_equal (tree t1, tree t2) case VAR_DECL: case CONST_DECL: + case FIELD_DECL: case FUNCTION_DECL: case TEMPLATE_DECL: case IDENTIFIER_NODE: --- gcc/testsuite/g++.dg/template/pr54858.C (revision 0) +++ gcc/testsuite/g++.dg/template/pr54858.C (revision 192220) @@ -0,0 +1,21 @@ +// PR c++/54858 +// { dg-do compile } + +template <int> struct A {}; +template <typename T, T *> struct B {}; +template <typename D> struct C +{ + A<0> c0; B<A<0>, &C::c0> d0; // { dg-error "could not convert template argument" } + A<0> c1; B<A<0>, &C::c1> d1; // { dg-error "could not convert template argument" } + A<0> c2; B<A<0>, &C::c2> d2; // { dg-error "could not convert template argument" } + A<0> c3; B<A<0>, &C::c3> d3; // { dg-error "could not convert template argument" } + A<0> c4; B<A<0>, &C::c4> d4; // { dg-error "could not convert template argument" } + A<0> c5; B<A<0>, &C::c5> d5; // { dg-error "could not convert template argument" } + A<0> c6; B<A<0>, &C::c6> d6; // { dg-error "could not convert template argument" } + A<0> c7; B<A<0>, &C::c7> d7; // { dg-error "could not convert template argument" } + A<0> c8; B<A<0>, &C::c8> d8; // { dg-error "could not convert template argument" } + A<0> c9; B<A<0>, &C::c9> d9; // { dg-error "could not convert template argument" } + A<0> ca; B<A<0>, &C::ca> da; // { dg-error "could not convert template argument" } + A<0> cb; B<A<0>, &C::cb> db; // { dg-error "could not convert template argument" } +}; +C<int> e;
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-10 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/55921 * tree-complex.c (expand_complex_asm): New function. (expand_complex_operations_1): Call it for GIMPLE_ASM. --- gcc/tree-complex.c (revision 195079) +++ gcc/tree-complex.c (revision 195080) @@ -1391,6 +1391,36 @@ expand_complex_comparison (gimple_stmt_i update_stmt (stmt); } +/* Expand inline asm that sets some complex SSA_NAMEs. */ + +static void +expand_complex_asm (gimple_stmt_iterator *gsi) +{ + gimple stmt = gsi_stmt (*gsi); + unsigned int i; + + for (i = 0; i < gimple_asm_noutputs (stmt); ++i) + { + tree link = gimple_asm_output_op (stmt, i); + tree op = TREE_VALUE (link); + if (TREE_CODE (op) == SSA_NAME + && TREE_CODE (TREE_TYPE (op)) == COMPLEX_TYPE) + { + tree type = TREE_TYPE (op); + tree inner_type = TREE_TYPE (type); + tree r = build1 (REALPART_EXPR, inner_type, op); + tree i = build1 (IMAGPART_EXPR, inner_type, op); + gimple_seq list = set_component_ssa_name (op, false, r); + + if (list) + gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); + + list = set_component_ssa_name (op, true, i); + if (list) + gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); + } + } +} /* Process one statement. If we identify a complex operation, expand it. */ @@ -1403,6 +1433,12 @@ expand_complex_operations_1 (gimple_stmt complex_lattice_t al, bl; enum tree_code code; + if (gimple_code (stmt) == GIMPLE_ASM) + { + expand_complex_asm (gsi); + return; + } + lhs = gimple_get_lhs (stmt); if (!lhs && gimple_code (stmt) != GIMPLE_COND) return;
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-18 Jakub Jelinek <ja...@redhat.com> PR middle-end/56015 * expr.c (expand_expr_real_2) <case COMPLEX_EXPR>: Handle the case where writing real complex part of target modifies op1. * gfortran.dg/pr56015.f90: New test. --- gcc/expr.c (revision 195300) +++ gcc/expr.c (revision 195301) @@ -8860,6 +8860,54 @@ expand_expr_real_2 (sepops ops, rtx targ if (!target) target = gen_reg_rtx (TYPE_MODE (type)); + else + /* If target overlaps with op1, then either we need to force + op1 into a pseudo (if target also overlaps with op0), + or write the complex parts in reverse order. */ + switch (GET_CODE (target)) + { + case CONCAT: + if (reg_overlap_mentioned_p (XEXP (target, 0), op1)) + { + if (reg_overlap_mentioned_p (XEXP (target, 1), op0)) + { + complex_expr_force_op1: + temp = gen_reg_rtx (GET_MODE_INNER (GET_MODE (target))); + emit_move_insn (temp, op1); + op1 = temp; + break; + } + complex_expr_swap_order: + /* Move the imaginary (op1) and real (op0) parts to their + location. */ + write_complex_part (target, op1, true); + write_complex_part (target, op0, false); + + return target; + } + break; + case MEM: + temp = adjust_address_nv (target, + GET_MODE_INNER (GET_MODE (target)), 0); + if (reg_overlap_mentioned_p (temp, op1)) + { + enum machine_mode imode = GET_MODE_INNER (GET_MODE (target)); + temp = adjust_address_nv (target, imode, + GET_MODE_SIZE (imode)); + if (reg_overlap_mentioned_p (temp, op0)) + goto complex_expr_force_op1; + goto complex_expr_swap_order; + } + break; + default: + if (reg_overlap_mentioned_p (target, op1)) + { + if (reg_overlap_mentioned_p (target, op0)) + goto complex_expr_force_op1; + goto complex_expr_swap_order; + } + break; + } /* Move the real (op0) and imaginary (op1) parts to their location. */ write_complex_part (target, op0, false); --- gcc/testsuite/gfortran.dg/pr56015.f90 (revision 0) +++ gcc/testsuite/gfortran.dg/pr56015.f90 (revision 195301) @@ -0,0 +1,16 @@ +! PR middle-end/56015 +! { dg-do run } +! { dg-options "-O3 -ffast-math -fno-inline" } + +program pr56015 + implicit none + complex*16 p(10) + p(:) = (0.1d0, 0.2d0) + p(:) = (0.0d0, 1.0d0) * p(:) + call foo (p) +contains + subroutine foo (p) + complex*16 p(10) + if (any (p .ne. (-0.2d0, 0.1d0))) call abort + end subroutine +end program pr56015
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-01-25 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/56098 * tree-ssa-phiopt.c (nt_init_block): Don't call add_or_mark_expr for stmts with volatile ops. (cond_store_replacement): Don't optimize if assign has volatile ops. (cond_if_else_store_replacement_1): Don't optimize if either then_assign or else_assign have volatile ops. * gcc.dg/pr56098-1.c: New test. --- gcc/tree-ssa-phiopt.c (revision 195474) +++ gcc/tree-ssa-phiopt.c (revision 195475) @@ -1160,7 +1160,7 @@ nt_init_block (struct dom_walk_data *dat { gimple stmt = gsi_stmt (gsi); - if (gimple_assign_single_p (stmt)) + if (gimple_assign_single_p (stmt) && !gimple_has_volatile_ops (stmt)) { add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true); add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false); @@ -1237,7 +1237,8 @@ cond_store_replacement (basic_block midd /* Check if middle_bb contains of only one store. */ if (!assign - || !gimple_assign_single_p (assign)) + || !gimple_assign_single_p (assign) + || gimple_has_volatile_ops (assign)) return false; locus = gimple_location (assign); @@ -1333,8 +1334,10 @@ cond_if_else_store_replacement (basic_bl /* Check if then_bb and else_bb contain only one store each. */ if (then_assign == NULL || !gimple_assign_single_p (then_assign) + || gimple_has_volatile_ops (then_assign) || else_assign == NULL - || !gimple_assign_single_p (else_assign)) + || !gimple_assign_single_p (else_assign) + || gimple_has_volatile_ops (else_assign)) return false; lhs = gimple_assign_lhs (then_assign); --- gcc/testsuite/gcc.dg/pr56098-1.c (revision 0) +++ gcc/testsuite/gcc.dg/pr56098-1.c (revision 195475) @@ -0,0 +1,16 @@ +/* PR tree-optimization/56098 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +volatile int *p; + +void +foo (int x) +{ + *p = 1; + if (x) + *p = 2; +} + +/* { dg-final { scan-tree-dump-not "=\[^\n\r]*\\*p" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-02-07 Jakub Jelinek <ja...@redhat.com> PR c++/56239 * parser.c (cp_parser_token_starts_cast_expression): Renamed to... (cp_parser_tokens_start_cast_expression): ... this. Change parameter to cp_parser *, call cp_lexer_peek_token first. For CPP_OPEN_PAREN, return true only if 2nd token isn't CPP_CLOSE_PAREN. (cp_parser_cast_expression): Adjust caller. * g++.dg/parse/pr56239.C: New test. --- gcc/cp/parser.c (revision 195858) +++ gcc/cp/parser.c (revision 195859) @@ -7091,8 +7091,9 @@ cp_parser_delete_expression (cp_parser* otherwise. */ static bool -cp_parser_token_starts_cast_expression (cp_token *token) +cp_parser_tokens_start_cast_expression (cp_parser *parser) { + cp_token *token = cp_lexer_peek_token (parser->lexer); switch (token->type) { case CPP_COMMA: @@ -7133,6 +7134,12 @@ cp_parser_token_starts_cast_expression ( case CPP_EOF: return false; + case CPP_OPEN_PAREN: + /* In ((type ()) () the last () isn't a valid cast-expression, + so the whole must be parsed as postfix-expression. */ + return cp_lexer_peek_nth_token (parser->lexer, 2)->type + != CPP_CLOSE_PAREN; + /* '[' may start a primary-expression in obj-c++. */ case CPP_OPEN_SQUARE: return c_dialect_objc (); @@ -7225,8 +7232,7 @@ cp_parser_cast_expression (cp_parser *pa parenthesized ctor such as `(T ())' that looks like a cast to function returning T. */ if (!cp_parser_error_occurred (parser) - && cp_parser_token_starts_cast_expression (cp_lexer_peek_token - (parser->lexer))) + && cp_parser_tokens_start_cast_expression (parser)) { cp_parser_parse_definitely (parser); expr = cp_parser_cast_expression (parser, --- gcc/testsuite/g++.dg/parse/pr56239.C (revision 0) +++ gcc/testsuite/g++.dg/parse/pr56239.C (revision 195859) @@ -0,0 +1,13 @@ +// PR c++/56239 +// { dg-do compile } + +struct S +{ + int operator () () { return 0; } +}; + +int +main () +{ + return (S ()) (); +}
2013-04-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2013-03-06 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/56539 * tree-tailcall.c (adjust_return_value_with_ops): Use GSI_SAME_STMT instead of GSI_CONTINUE_LINKING as last argument to force_gimple_operand_gsi. Adjust function comment. * gcc.c-torture/compile/pr56539.c: New test. --- gcc/tree-tailcall.c (revision 196510) +++ gcc/tree-tailcall.c (revision 196511) @@ -599,8 +599,8 @@ add_successor_phi_arg (edge e, tree var, } /* Creates a GIMPLE statement which computes the operation specified by - CODE, OP0 and OP1 to a new variable with name LABEL and inserts the - statement in the position specified by GSI and UPDATE. Returns the + CODE, ACC and OP1 to a new variable with name LABEL and inserts the + statement in the position specified by GSI. Returns the tree node of the statement's result. */ static tree @@ -622,7 +622,7 @@ adjust_return_value_with_ops (enum tree_ fold_convert (TREE_TYPE (op1), acc), op1)); rhs = force_gimple_operand_gsi (&gsi, rhs, - false, NULL, true, GSI_CONTINUE_LINKING); + false, NULL, true, GSI_SAME_STMT); stmt = gimple_build_assign (NULL_TREE, rhs); } --- gcc/testsuite/gcc.c-torture/compile/pr56539.c (revision 0) +++ gcc/testsuite/gcc.c-torture/compile/pr56539.c (revision 196511) @@ -0,0 +1,7 @@ +/* PR tree-optimization/56539 */ + +short +foo (const char *x, unsigned y) +{ + return y > 1 ? (x[y - 1] - '0') + 10 * foo (x, y - 1) : (*x - '0'); +}