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
This commit is contained in:
Marek Polacek 2019-04-12 15:29:03 +00:00 committed by Marek Polacek
parent cc3bae3dc2
commit c46f1a1791
11 changed files with 61 additions and 36 deletions

View File

@ -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 <jakub@redhat.com>
PR translation/90035

View File

@ -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 <tree, tree> 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. */

View File

@ -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);

View File

@ -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;

View File

@ -1,3 +1,13 @@
2019-04-12 Marek Polacek <polacek@redhat.com>
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 <polacek@redhat.com>
* g++.dg/cpp0x/noexcept30.C: Tweak dg-error.

View File

@ -10,4 +10,7 @@ constexpr T value(T t) noexcept(is_funny<T>::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");

View File

@ -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)));

View File

@ -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)));
}

View File

@ -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{}), "");

View File

@ -168,7 +168,7 @@ namespace derived_ctor {
};
struct bar : boo {
template <typename ...T>
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 <typename ...T>
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 {

View File

@ -0,0 +1,12 @@
// PR c++/87603
// { dg-do compile { target c++14 } }
template<typename T>
struct basic_string_view
{
constexpr basic_string_view(T p) noexcept { (void) p.i; }
};
struct X { } x;
bool b = noexcept(basic_string_view<X>{x});