From c46f1a1791b3ec3a58780a4b882ecf19f047869a Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 12 Apr 2019 15:29:03 +0000 Subject: [PATCH] PR c++/87603 - constexpr functions are no longer noexcept. * constexpr.c (is_sub_constant_expr): Remove unused function. * cp-tree.h (is_sub_constant_expr): Remove declaration. * except.c (check_noexcept_r): Don't consider a call to a constexpr function noexcept. * g++.dg/cpp0x/constexpr-noexcept.C: Adjust the expected result. * g++.dg/cpp0x/constexpr-noexcept3.C: Likewise. * g++.dg/cpp0x/constexpr-noexcept4.C: Likewise. * g++.dg/cpp0x/constexpr-noexcept8.C: New test. * g++.dg/cpp0x/inh-ctor32.C: Remove dg-message. * g++.dg/cpp1y/constexpr-noexcept1.C: New test. From-SVN: r270320 --- gcc/cp/ChangeLog | 6 ++++++ gcc/cp/constexpr.c | 21 --------------------- gcc/cp/cp-tree.h | 1 - gcc/cp/except.c | 13 ++++++++----- gcc/testsuite/ChangeLog | 10 ++++++++++ gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C | 5 ++++- gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C | 4 +++- gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C | 9 +++++---- gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept8.C | 10 ++++++++++ gcc/testsuite/g++.dg/cpp0x/inh-ctor32.C | 6 +++--- gcc/testsuite/g++.dg/cpp1y/constexpr-noexcept1.C | 12 ++++++++++++ 11 files changed, 61 insertions(+), 36 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept8.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-noexcept1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a12622..8e63fda 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -3,6 +3,12 @@ * except.c (build_noexcept_spec): Use build_converted_constant_bool_expr instead of perform_implicit_conversion_flags. + PR c++/87603 - constexpr functions are no longer noexcept. + * constexpr.c (is_sub_constant_expr): Remove unused function. + * cp-tree.h (is_sub_constant_expr): Remove declaration. + * except.c (check_noexcept_r): Don't consider a call to a constexpr + function noexcept. + 2019-04-11 Jakub Jelinek PR translation/90035 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 0ce5618..9c13f0d 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5423,27 +5423,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, return r; } -/* Returns true if T is a valid subexpression of a constant expression, - even if it isn't itself a constant expression. */ - -bool -is_sub_constant_expr (tree t) -{ - bool non_constant_p = false; - bool overflow_p = false; - hash_map map; - HOST_WIDE_INT constexpr_ops_count = 0; - - constexpr_ctx ctx - = { NULL, &map, NULL, NULL, NULL, NULL, &constexpr_ops_count, - true, true, false }; - - instantiate_constexpr_fns (t); - cxx_eval_constant_expression (&ctx, t, false, &non_constant_p, - &overflow_p); - return !non_constant_p && !overflow_p; -} - /* If T represents a constant expression returns its reduced value. Otherwise return error_mark_node. If T is dependent, then return NULL. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b87b968..ff4ce06 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7720,7 +7720,6 @@ extern tree fold_non_dependent_init (tree, tsubst_flags_t = tf_warning_or_error, bool = false); extern tree fold_simple (tree); -extern bool is_sub_constant_expr (tree); extern bool reduced_constant_expression_p (tree); extern bool is_instantiation_of_constexpr (tree); extern bool var_in_constexpr_fn (tree); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 25ab869..afc2610 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1128,11 +1128,14 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void * /*data*/) && (DECL_ARTIFICIAL (fn) || nothrow_libfn_p (fn))) return TREE_NOTHROW (fn) ? NULL_TREE : fn; - /* A call to a constexpr function is noexcept if the call - is a constant expression. */ - if (DECL_DECLARED_CONSTEXPR_P (fn) - && is_sub_constant_expr (t)) - return NULL_TREE; + /* We used to treat a call to a constexpr function as noexcept if + the call was a constant expression (CWG 1129). This has changed + in P0003 whereby noexcept has no special rule for constant + expressions anymore. Since the current behavior is important for + certain library functionality, we treat this as a DR, therefore + adjusting the behavior for C++11 and C++14. Previously, we had + to evaluate the noexcept-specifier's operand here, but that could + cause instantiations that would fail. */ } if (!TYPE_NOTHROW_P (type)) return fn; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f20f45d..fe8373e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,15 @@ 2019-04-12 Marek Polacek + PR c++/87603 - constexpr functions are no longer noexcept. + * g++.dg/cpp0x/constexpr-noexcept.C: Adjust the expected result. + * g++.dg/cpp0x/constexpr-noexcept3.C: Likewise. + * g++.dg/cpp0x/constexpr-noexcept4.C: Likewise. + * g++.dg/cpp0x/constexpr-noexcept8.C: New test. + * g++.dg/cpp0x/inh-ctor32.C: Remove dg-message. + * g++.dg/cpp1y/constexpr-noexcept1.C: New test. + +2019-04-12 Marek Polacek + * g++.dg/cpp0x/noexcept30.C: Tweak dg-error. * g++.dg/cpp0x/pr86397-1.C: Likewise. * g++.dg/cpp0x/pr86397-2.C: Likewise. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C index dbadaa8..035afd1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C @@ -10,4 +10,7 @@ constexpr T value(T t) noexcept(is_funny::value) { return t; } // Line 7 constexpr bool ok = noexcept(value(42)); -static_assert(ok, "Assertion failure"); +// We used to treat a call to a constexpr function as noexcept if +// the call was a constant expression. We no longer do since +// c++/87603. +static_assert(!ok, "Assertion failure"); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C index 9541bc0..5a43899 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C @@ -2,6 +2,8 @@ constexpr int f(int i) { return i; } #define SA(X) static_assert (X, #X) -SA(noexcept(f(42))); +/* We used to assert that the following *is* noexcept, but this has changed + in c++/87603. */ +SA(!noexcept(f(42))); int j; SA(!noexcept(f(j))); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C index eb71900..0446069 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C @@ -1,6 +1,7 @@ // { dg-do compile { target c++11 } } -// A call is noexcept if it is a valid subexpression of a constant -// expression, even if it is not itself a constant expression. +// We used to treat a call to a constexpr function as noexcept if +// the call was a constant expression. We no longer do since +// c++/87603. #define SA(X) static_assert(X,#X) @@ -9,6 +10,6 @@ constexpr const int* f(const int *p) { return p; } int main() { constexpr int i = 42; - SA(noexcept(*f(&i))); - SA(noexcept(f(&i))); + SA(!noexcept(*f(&i))); + SA(!noexcept(f(&i))); } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept8.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept8.C new file mode 100644 index 0000000..7dca56a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept8.C @@ -0,0 +1,10 @@ +// PR c++/87603 +// { dg-do compile { target c++11 } } + +struct Y { }; + + bool operator<(Y a, Y b) { return false; } +constexpr bool operator>(Y a, Y b) { return false; } + +static_assert(!noexcept(Y{} > Y{}), ""); +static_assert(!noexcept(Y{} < Y{}), ""); diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor32.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor32.C index c40412f..5ea2642 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor32.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor32.C @@ -168,7 +168,7 @@ namespace derived_ctor { }; struct bar : boo { template - constexpr bar(T ... args) : boo(args...) {} // { dg-message "sorry, unimplemented: passing arguments to ellipsis" } + constexpr bar(T ... args) : boo(args...) {} }; void f() noexcept(noexcept(bar{0,1})); } @@ -200,12 +200,12 @@ namespace derived_ctor { }; struct bor : boo { template - constexpr bor(T ... args) : boo(args...) {} // { dg-message "sorry, unimplemented: passing arguments to ellipsis" } + constexpr bor(T ... args) : boo(args...) {} }; struct bar : bor { using bor::bor; }; - void f() noexcept(noexcept(bar{0,1})); // { dg-message "'constexpr' expansion" } + void f() noexcept(noexcept(bar{0,1})); } namespace no_constexpr_noninherited_ctor { diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-noexcept1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-noexcept1.C new file mode 100644 index 0000000..a74f24a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-noexcept1.C @@ -0,0 +1,12 @@ +// PR c++/87603 +// { dg-do compile { target c++14 } } + +template +struct basic_string_view +{ + constexpr basic_string_view(T p) noexcept { (void) p.i; } +}; + +struct X { } x; + +bool b = noexcept(basic_string_view{x}); -- 2.7.4