Hi,
in this issue Daniel argued that the value of a noexcept expression
should not depend on constructor elision. Then, in the audit trail Marc
tentatively suggested something like the parser.c hunk below, which just
disables our -felide-constructors optimization when parsing the noexcept
expression. Over the last couple of days, I had a look, noticed that in
any case we still have to handle templates, thus the pt.c hunk, and also
that maybe we can avoid completely disabling -felide-constructors in
noexcept expressions when we know for sure that the constructor at issue
doen't throw: for that in call.s I'm further abusing the
flag_elide_constructors global, in terms of using a special value of 2
when flag_elide_constructor is found == 1 when handling the expression.
The below passes testing, anyway.
Thanks!
Paolo.
///////////////////////
Index: cp/call.c
===================================================================
--- cp/call.c (revision 215750)
+++ cp/call.c (working copy)
@@ -7249,9 +7249,14 @@ build_over_call (struct z_candidate *cand, int fla
if (! flag_elide_constructors)
/* Do things the hard way. */;
- else if (cand->num_convs == 1
- && (DECL_COPY_CONSTRUCTOR_P (fn)
- || DECL_MOVE_CONSTRUCTOR_P (fn)))
+ else if ((cand->num_convs == 1
+ && (DECL_COPY_CONSTRUCTOR_P (fn)
+ || DECL_MOVE_CONSTRUCTOR_P (fn)))
+ && (flag_elide_constructors == 1
+ || (flag_elide_constructors == 2
+ && (!DEFERRED_NOEXCEPT_SPEC_P
+ (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+ && type_noexcept_p (TREE_TYPE (fn))))))
{
tree targ;
tree arg = argarray[num_artificial_parms_for (fn)];
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 215750)
+++ cp/parser.c (working copy)
@@ -7136,10 +7136,15 @@ cp_parser_unary_expression (cp_parser *parser, boo
bool saved_integral_constant_expression_p;
bool saved_non_integral_constant_expression_p;
bool saved_greater_than_is_operator_p;
+ int saved_flag_elide_constructors;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
+ saved_flag_elide_constructors = flag_elide_constructors;
+ if (flag_elide_constructors == 1)
+ flag_elide_constructors = 2;
+
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= G_("types may not be defined in %<noexcept%> expressions");
@@ -7170,6 +7175,8 @@ cp_parser_unary_expression (cp_parser *parser, boo
parser->type_definition_forbidden_message = saved_message;
+ flag_elide_constructors = saved_flag_elide_constructors;
+
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
return finish_noexcept_expr (expr, tf_warning_or_error);
}
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 215750)
+++ cp/pt.c (working copy)
@@ -14766,15 +14766,22 @@ tsubst_copy_and_build (tree t,
}
case NOEXCEPT_EXPR:
- op1 = TREE_OPERAND (t, 0);
- ++cp_unevaluated_operand;
- ++c_inhibit_evaluation_warnings;
- op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
- /*function_p=*/false,
- /*integral_constant_expression_p=*/false);
- --cp_unevaluated_operand;
- --c_inhibit_evaluation_warnings;
- RETURN (finish_noexcept_expr (op1, complain));
+ {
+ int saved_flag_elide_constructors;
+ op1 = TREE_OPERAND (t, 0);
+ ++cp_unevaluated_operand;
+ ++c_inhibit_evaluation_warnings;
+ saved_flag_elide_constructors = flag_elide_constructors;
+ if (flag_elide_constructors == 1)
+ flag_elide_constructors = 2;
+ op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
+ /*function_p=*/false,
+ /*integral_constant_expression_p=*/false);
+ flag_elide_constructors = saved_flag_elide_constructors;
+ --cp_unevaluated_operand;
+ --c_inhibit_evaluation_warnings;
+ RETURN (finish_noexcept_expr (op1, complain));
+ }
case MODOP_EXPR:
{
Index: testsuite/g++.dg/cpp0x/noexcept23.C
===================================================================
--- testsuite/g++.dg/cpp0x/noexcept23.C (revision 0)
+++ testsuite/g++.dg/cpp0x/noexcept23.C (working copy)
@@ -0,0 +1,14 @@
+// PR c++/53025
+// { dg-do compile { target c++11 } }
+
+struct A {
+ A() noexcept {}
+ A(const A&) noexcept(false) {}
+};
+
+void a(A) noexcept {}
+
+void f()
+{
+ static_assert(!noexcept(a(A{})), "");
+}
Index: testsuite/g++.dg/cpp0x/noexcept24.C
===================================================================
--- testsuite/g++.dg/cpp0x/noexcept24.C (revision 0)
+++ testsuite/g++.dg/cpp0x/noexcept24.C (working copy)
@@ -0,0 +1,22 @@
+// PR c++/53025
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+struct A {
+ A() noexcept {}
+ A(const A&) noexcept(false) {}
+};
+
+template<typename T>
+void a(A<T>) noexcept {}
+
+template<typename T>
+void f()
+{
+ static_assert(!noexcept(a(A<T>{})), "");
+}
+
+void g()
+{
+ f<int>();
+}