diff mbox

[C++,Patch/RFC] PR 53025

Message ID 542C2C69.9000905@oracle.com
State New
Headers show

Commit Message

Paolo Carlini Oct. 1, 2014, 4:31 p.m. UTC
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.

///////////////////////

Comments

Jason Merrill Oct. 2, 2014, 3:22 a.m. UTC | #1
On 10/01/2014 12:31 PM, Paolo Carlini wrote:
> in this issue Daniel argued that the value of a noexcept expression
> should not depend on constructor elision.

I'm open to that, but I don't think it's at all clear in the standard.

> 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.

Why do we want to avoid completely disabling -felide-constructors, since 
it's an unevaluated context anyway?

If you're going to mess with this flag you need to save/restore it in 
push/pop_to_top_level as well.

Jason
diff mbox

Patch

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>();
+}