It sounds plausible that this assert int f(); static_assert(noexcept(sizeof(f())));
should pass: sizeof produces a std::size_t and its operand is not evaluated, so it can't throw. noexcept should only evaluate to false for potentially evaluated operands. Therefore I think that check_noexcept_r shouldn't walk into operands of sizeof/decltype/ alignof/typeof. Only checking cp_unevaluated_operand therein does not work, because expr_noexcept_p can be called in an unevaluated context, so I resorted to the following cp_evaluated hack. Does that seem acceptable? Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? PR c++/101087 gcc/cp/ChangeLog: * except.c (check_noexcept_r): Don't walk into unevaluated operands. (expr_noexcept_p): Use cp_evaluated. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept70.C: New test. --- gcc/cp/except.c | 14 +++++++++++--- gcc/testsuite/g++.dg/cpp0x/noexcept70.C | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept70.C diff --git a/gcc/cp/except.c b/gcc/cp/except.c index a8cea53cf91..6f97ac40b4b 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1033,12 +1033,15 @@ check_handlers (tree handlers) expression whose type is a polymorphic class type (10.3). */ static tree -check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void * /*data*/) +check_noexcept_r (tree *tp, int *walk_subtrees, void *) { tree t = *tp; enum tree_code code = TREE_CODE (t); - if ((code == CALL_EXPR && CALL_EXPR_FN (t)) - || code == AGGR_INIT_EXPR) + + if (cp_unevaluated_operand) + *walk_subtrees = false; + else if ((code == CALL_EXPR && CALL_EXPR_FN (t)) + || code == AGGR_INIT_EXPR) { /* We can only use the exception specification of the called function for determining the value of a noexcept expression; we can't use @@ -1155,6 +1158,11 @@ expr_noexcept_p (tree expr, tsubst_flags_t complain) if (expr == error_mark_node) return false; + /* Even though the operand of noexcept is an _unevaluated_ operand, + temporarily clearing cp_unevaluated_operand allows us to check it + in check_noexcept_r, to handle noexcept(sizeof(f())). It could be + set when we are called in the context of synthesized_method_walk. */ + cp_evaluated ev; fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0); if (fn) { diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept70.C b/gcc/testsuite/g++.dg/cpp0x/noexcept70.C new file mode 100644 index 00000000000..45a6137dd6f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept70.C @@ -0,0 +1,5 @@ +// PR c++/101087 +// { dg-do compile { target c++11 } } + +int f(); +static_assert(noexcept(sizeof(f())), ""); base-commit: a110855667782dac7b674d3e328b253b3b3c919b -- 2.31.1