This fixes the regression part of c++/65642. Some history behind this: up until r214941 we were able to fold "&A[i] + j" into "&A[i + j]", but in this revision richi removed this transformation. Since we need this transformation when dealing with constexprs, I added it back into cxx_fold_indirect_ref function (r221544). But that was a wrong place; we need to be able to handle such a transformation even when we're not dealing with INDIRECT_REFs, so I moved the folding into cxx_eval_constant_expression and introduced cxx_eval_pointer_plus_expression (r221777). That was the right thing to do, but I should've also added an evaluation of the first op of a POINTER_PLUS_EXPR, otherwise cxx_eval_pointer_plus_expression won't be able to do its job properly in some cases: e.g. when it gets "s + 1" where "s" is a PARM_DECL: the function expects the "&s[0] + 1" form.
The fix for the second part of this PR should follow soon. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2015-04-02 Marek Polacek <pola...@redhat.com> PR c++/65642 * constexpr.c (cxx_eval_pointer_plus_expression): Call cxx_eval_constant_expression on the first operand. * g++.dg/cpp0x/constexpr-fold1.C: New test. * g++.dg/cpp0x/constexpr-fold2.C: New test. diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index 2100f94..f5be8df 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -2933,6 +2933,9 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t, tree op01 = TREE_OPERAND (t, 1); location_t loc = EXPR_LOCATION (t); + op00 = cxx_eval_constant_expression (ctx, op00, lval, + non_constant_p, overflow_p); + STRIP_NOPS (op00); if (TREE_CODE (op00) != ADDR_EXPR) return NULL_TREE; diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-fold1.C gcc/testsuite/g++.dg/cpp0x/constexpr-fold1.C index e69de29..414a0da 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-fold1.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-fold1.C @@ -0,0 +1,65 @@ +// PR c++/65642 +// { dg-do compile { target c++11 } } + +// Check we're able to evaluate these. + +#define SA(X) static_assert((X),#X) + +constexpr char s[] = "abc"; +constexpr int t[] = { 'a', 'b', 'c', '\0' }; + +constexpr char +fn1 (const char *p) +{ + return *(p + 1); +} + +constexpr char +fn2 (const char *p) +{ + return p[1]; +} + +constexpr int +fn3 (const int *p) +{ + return *(p + 1); +} + +constexpr int +fn4 (const int *p) +{ + return p[1]; +} + +constexpr auto c1 = fn1 (&s[0]); +constexpr auto c2 = fn1 (&s[1]); +constexpr auto c3 = fn1 (&s[2]); + +SA (c1 == 'b'); +SA (c2 == 'c'); +SA (c3 == '\0'); + +constexpr auto d1 = fn2 (&s[0]); +constexpr auto d2 = fn2 (&s[1]); +constexpr auto d3 = fn2 (&s[2]); + +SA (d1 == 'b'); +SA (d2 == 'c'); +SA (d3 == '\0'); + +constexpr auto e1 = fn3 (&t[0]); +constexpr auto e2 = fn3 (&t[1]); +constexpr auto e3 = fn3 (&t[2]); + +SA (e1 == 'b'); +SA (e2 == 'c'); +SA (e3 == '\0'); + +constexpr auto f1 = fn4 (&t[0]); +constexpr auto f2 = fn4 (&t[1]); +constexpr auto f3 = fn4 (&t[2]); + +SA (f1 == 'b'); +SA (f2 == 'c'); +SA (f3 == '\0'); diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-fold2.C gcc/testsuite/g++.dg/cpp0x/constexpr-fold2.C index e69de29..98aca2a 100644 --- gcc/testsuite/g++.dg/cpp0x/constexpr-fold2.C +++ gcc/testsuite/g++.dg/cpp0x/constexpr-fold2.C @@ -0,0 +1,30 @@ +// PR c++/65642 +// { dg-do compile { target c++11 } } + +#define SA(X) static_assert((X),#X) + +constexpr char s[] = "abc"; + +constexpr bool +cmp (char const *a, char const *b) +{ + return a == b; +} + +constexpr bool +fn1 (const char *s) +{ + return cmp (s, s + 1); +} + +constexpr bool +fn2 (const char *s) +{ + return cmp (s + 1, s + 1); +} + +constexpr auto c1 = fn1 (&s[0]); +constexpr auto c2 = fn2 (&s[0]); + +SA (!c1); +SA (c2); Marek