From 109d2197c31b766daf9c7b138bc7eeaab12985df Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 20 Jul 2016 16:00:02 +0200 Subject: [PATCH] re PR middle-end/50060 (intrinsics not folded by the middle-end) PR c++/50060 * constexpr.c (cxx_eval_builtin_function_call): Pass false as lval when evaluating call arguments. Use fold_builtin_call_array instead of fold_build_call_array_loc, return t if it returns NULL. Otherwise check the result with potential_constant_expression and call cxx_eval_constant_expression on it. * g++.dg/cpp0x/constexpr-50060.C: New test. * g++.dg/cpp1y/constexpr-50060.C: New test. From-SVN: r238520 --- gcc/cp/ChangeLog | 9 ++ gcc/cp/constexpr.c | 32 ++++-- gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C | 21 ++++ gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C | 100 +++++++++++++++++++ 5 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 417cb82b3ee..7b9032022e0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2016-07-20 Jakub Jelinek + + PR c++/50060 + * constexpr.c (cxx_eval_builtin_function_call): Pass false as lval + when evaluating call arguments. Use fold_builtin_call_array instead + of fold_build_call_array_loc, return t if it returns NULL. Otherwise + check the result with potential_constant_expression and call + cxx_eval_constant_expression on it. + 2016-07-19 Jason Merrill PR c++/67164 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 91d14a55b4f..346fdfad908 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1105,7 +1105,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, for (i = 0; i < nargs; ++i) { args[i] = cxx_eval_constant_expression (&new_ctx, CALL_EXPR_ARG (t, i), - lval, &dummy1, &dummy2); + false, &dummy1, &dummy2); if (bi_const_p) /* For __built_in_constant_p, fold all expressions with constant values even if they aren't C++ constant-expressions. */ @@ -1114,13 +1114,31 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, bool save_ffbcp = force_folding_builtin_constant_p; force_folding_builtin_constant_p = true; - new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t), - CALL_EXPR_FN (t), nargs, args); - /* Fold away the NOP_EXPR from fold_builtin_n. */ - new_call = fold (new_call); + new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), + CALL_EXPR_FN (t), nargs, args); force_folding_builtin_constant_p = save_ffbcp; - VERIFY_CONSTANT (new_call); - return new_call; + if (new_call == NULL) + { + if (!*non_constant_p && !ctx->quiet) + { + new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t), + CALL_EXPR_FN (t), nargs, args); + error ("%q+E is not a constant expression", new_call); + } + *non_constant_p = true; + return t; + } + + if (!potential_constant_expression (new_call)) + { + if (!*non_constant_p && !ctx->quiet) + error ("%q+E is not a constant expression", new_call); + *non_constant_p = true; + return t; + } + + return cxx_eval_constant_expression (&new_ctx, new_call, lval, + non_constant_p, overflow_p); } /* TEMP is the constant value of a temporary object of type TYPE. Adjust diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 41b09e268db..41042eb2aa8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-07-20 Jakub Jelinek + + PR c++/50060 + * g++.dg/cpp0x/constexpr-50060.C: New test. + * g++.dg/cpp1y/constexpr-50060.C: New test. + 2016-07-20 Martin Liska * gfortran.dg/graphite/pr71898.f90: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C new file mode 100644 index 00000000000..ee1c221b6a6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C @@ -0,0 +1,21 @@ +// PR c++/50060 +// { dg-do compile { target c++11 } } + +extern "C" double frexp (double, int *); + +struct S +{ + constexpr S (double a) : y {}, x (frexp (a, &y)) {} // { dg-error "is not a constant expression" "S" { target { ! c++14 } } } + double x; + int y; +}; + +struct T +{ + constexpr T (double a) : y {}, x ((y = 1, 0.8125)) {} // { dg-error "is not a constant-expression" "T" { target { ! c++14 } } } + double x; + int y; +}; + +static_assert (S (6.5).x == 0.8125, ""); // { dg-error "non-constant condition for static assertion|in constexpr expansion" "" { target { ! c++14 } } } +static_assert (T (6.5).x == 0.8125, ""); // { dg-error "non-constant condition for static assertion|called in a constant expression" "" { target { ! c++14 } } } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C new file mode 100644 index 00000000000..4ac27a349a0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C @@ -0,0 +1,100 @@ +// PR c++/50060 +// { dg-do compile { target c++14 } } + +// sincos and lgamma_r aren't available in -std=c++14, +// only in -std=gnu++14. Use __builtin_* in that case. +extern "C" void sincos (double, double *, double *); +extern "C" double frexp (double, int *); +extern "C" double modf (double, double *); +extern "C" double remquo (double, double, int *); +extern "C" double lgamma_r (double, int *); + +constexpr double +f0 (double x) +{ + double y {}; + double z {}; + __builtin_sincos (x, &y, &z); + return y; +} + +constexpr double +f1 (double x) +{ + double y {}; + double z {}; + __builtin_sincos (x, &y, &z); + return z; +} + +constexpr double +f2 (double x) +{ + int y {}; + return frexp (x, &y); +} + +constexpr int +f3 (double x) +{ + int y {}; + frexp (x, &y); + return y; +} + +constexpr double +f4 (double x) +{ + double y {}; + return modf (x, &y); +} + +constexpr double +f5 (double x) +{ + double y {}; + modf (x, &y); + return y; +} + +constexpr double +f6 (double x, double y) +{ + int z {}; + return remquo (x, y, &z); +} + +constexpr int +f7 (double x, double y) +{ + int z {}; + remquo (x, y, &z); + return z; +} + +constexpr double +f8 (double x) +{ + int y {}; + return __builtin_lgamma_r (x, &y); +} + +constexpr int +f9 (double x) +{ + int y {}; + __builtin_lgamma_r (x, &y); + return y; +} + +static_assert (f0 (0.0) == 0.0, ""); +static_assert (f1 (0.0) == 1.0, ""); +static_assert (f2 (6.5) == 0.8125, ""); +static_assert (f3 (6.5) == 3, ""); +static_assert (f4 (-7.25) == -0.25, ""); +static_assert (f5 (-7.25) == -7.0, ""); +static_assert (f6 (3.0, 2.0) == -1.0, ""); +static_assert (f7 (3.0, 2.0) == 2, ""); +static_assert (f8 (0.75) >= 0.20 && f8 (0.75) <= 0.21, ""); +static_assert (f8 (0.75) >= 0.20 && f8 (0.75) <= 0.21, ""); +static_assert (f9 (0.75) == 1, ""); -- 2.30.2