Hi! As discussed in the PR, these 4 places call maybe_constant_value even when processing_template_decl, just to try harder to see if the value isn't constant, and that may crash if fold_non_dependent_expr hasn't been called first. This is just optimization to get better warnings, so we don't want that call to emit any errors, worst case we just won't emit the warnings, so I'm using fold_non_dependent_expr_sfinae with tf_none.
Bootstrapped/regtested on x86_64-linux and i686-linux, acked by Jason in the PR, committed to trunk and 4.8 branch. 2013-04-10 Jakub Jelinek <ja...@redhat.com> PR c++/56895 * typeck.c (cp_build_binary_op): Call fold_non_dependent_expr_sfinae first before calling maybe_constant_value for warn_for_div_by_zero or invalid shift count warning purposes. * g++.dg/template/arrow3.C: New test. --- gcc/cp/typeck.c.jj 2013-04-04 15:03:28.000000000 +0200 +++ gcc/cp/typeck.c 2013-04-09 20:40:20.753714512 +0200 @@ -4047,8 +4047,9 @@ cp_build_binary_op (location_t location, || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)) { enum tree_code tcode0 = code0, tcode1 = code1; + tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none); - warn_for_div_by_zero (location, maybe_constant_value (op1)); + warn_for_div_by_zero (location, maybe_constant_value (cop1)); if (tcode0 == COMPLEX_TYPE || tcode0 == VECTOR_TYPE) tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0))); @@ -4084,7 +4085,11 @@ cp_build_binary_op (location_t location, case TRUNC_MOD_EXPR: case FLOOR_MOD_EXPR: - warn_for_div_by_zero (location, maybe_constant_value (op1)); + { + tree cop1 = fold_non_dependent_expr_sfinae (op1, tf_none); + + warn_for_div_by_zero (location, maybe_constant_value (cop1)); + } if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE @@ -4132,7 +4137,8 @@ cp_build_binary_op (location_t location, } else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) { - tree const_op1 = maybe_constant_value (op1); + tree const_op1 = fold_non_dependent_expr_sfinae (op1, tf_none); + const_op1 = maybe_constant_value (const_op1); if (TREE_CODE (const_op1) != INTEGER_CST) const_op1 = op1; result_type = type0; @@ -4178,7 +4184,8 @@ cp_build_binary_op (location_t location, } else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) { - tree const_op1 = maybe_constant_value (op1); + tree const_op1 = fold_non_dependent_expr_sfinae (op1, tf_none); + const_op1 = maybe_constant_value (const_op1); if (TREE_CODE (const_op1) != INTEGER_CST) const_op1 = op1; result_type = type0; --- gcc/testsuite/g++.dg/template/arrow3.C.jj 2013-04-09 20:27:31.800321563 +0200 +++ gcc/testsuite/g++.dg/template/arrow3.C 2013-04-09 20:42:34.000000000 +0200 @@ -0,0 +1,38 @@ +// PR c++/56895 +// { dg-do compile } + +extern struct A { bool foo (); A bar (); } *a; + +template <int> +int +baz1 () +{ + return 2 << (a->bar().foo() ? 1 : 0); +} + +template <int> +int +baz2 () +{ + return 2 >> (a->bar().foo() ? 1 : 0); +} + +template <int> +int +baz3 () +{ + return 10 / (a->bar().foo() ? 1 : 2); +} + +template <int> +int +baz4 () +{ + return 10 % (a->bar().foo() ? 1 : 0); +} + +int +test () +{ + return baz1<0> () + baz2<0> () + baz3<0> () + baz4<0> (); +} Jakub