[C++ Patch/RFC] PR 53025

Paolo Carlini paolo.carlini@oracle.com
Thu Oct 2 12:12:00 GMT 2014


Hi,

On 10/02/2014 05:22 AM, Jason Merrill wrote:
> 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.
Ok. Personally, I find the analysis in the audit trail rather 
convincing. In practice, clang++ definitely agrees, likewise 
SolarisStudio. Current EDG seems inconsistent, the templated and 
non-templated cases are handled differently.
>
>> 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?
Agreed.
> If you're going to mess with this flag you need to save/restore it in 
> push/pop_to_top_level as well.
I see. But then if we have to do take care of that I find much more 
clean to just add a global?!? In any case, if I understand correctly the 
logic at the end of push_to_top_level, it would be tricky to reset the 
flag to a sensible value (by default would be 1, but the user may have 
passed -fno-elide-constructors on the command line).

The below passes testing.

Thanks!
Paolo.

////////////////////////
-------------- next part --------------
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 215797)
+++ cp/call.c	(working copy)
@@ -7251,7 +7251,11 @@ build_over_call (struct z_candidate *cand, int fla
     /* Do things the hard way.  */;
   else if (cand->num_convs == 1 
            && (DECL_COPY_CONSTRUCTOR_P (fn) 
-               || DECL_MOVE_CONSTRUCTOR_P (fn)))
+               || DECL_MOVE_CONSTRUCTOR_P (fn))
+	   /* It's unsafe to elide the constructor when handling
+	      a noexcept-expression, it may evaluate to the wrong
+	      value (c++/53025).  */
+	   && cp_noexcept_operand == 0)
     {
       tree targ;
       tree arg = argarray[num_artificial_parms_for (fn)];
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 215797)
+++ cp/cp-tree.h	(working copy)
@@ -1058,6 +1058,7 @@ struct GTY(()) saved_scope {
 
   int unevaluated_operand;
   int inhibit_evaluation_warnings;
+  int noexcept_operand;
   /* If non-zero, implicit "omp declare target" attribute is added into the
      attribute lists.  */
   int omp_declare_target_attribute;
@@ -4399,6 +4400,10 @@ extern int comparing_specializations;
 
 extern int cp_unevaluated_operand;
 
+/* Nonzero if we are parsing the operand of a noexcept operator.  */
+
+extern int cp_noexcept_operand;
+
 /* in pt.c  */
 
 /* These values are used for the `STRICT' parameter to type_unification and
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c	(revision 215797)
+++ cp/name-lookup.c	(working copy)
@@ -6139,6 +6139,7 @@ push_to_top_level (void)
   s->function_decl = current_function_decl;
   s->unevaluated_operand = cp_unevaluated_operand;
   s->inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
+  s->noexcept_operand = cp_noexcept_operand;
   s->x_stmt_tree.stmts_are_full_exprs_p = true;
 
   scope_chain = s;
@@ -6149,6 +6150,7 @@ push_to_top_level (void)
   push_class_stack ();
   cp_unevaluated_operand = 0;
   c_inhibit_evaluation_warnings = 0;
+  cp_noexcept_operand = 0;
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
 }
 
@@ -6182,6 +6184,7 @@ pop_from_top_level_1 (void)
   current_function_decl = s->function_decl;
   cp_unevaluated_operand = s->unevaluated_operand;
   c_inhibit_evaluation_warnings = s->inhibit_evaluation_warnings;
+  cp_noexcept_operand = s->noexcept_operand;
 }
 
 /* Wrapper for pop_from_top_level_1.  */
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 215797)
+++ cp/parser.c	(working copy)
@@ -259,6 +259,9 @@ static FILE *cp_lexer_debug_stream;
    sizeof, typeof, or alignof.  */
 int cp_unevaluated_operand;
 
+/* Nonzero if we are parsing the operand of a noexcept operator.  */
+int cp_noexcept_operand;
+
 /* Dump up to NUM tokens in BUFFER to FILE starting with token
    START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
    first token in BUFFER.  If NUM is 0, dump all the tokens.  If
@@ -7156,7 +7159,9 @@ cp_parser_unary_expression (cp_parser *parser, boo
 
 	    ++cp_unevaluated_operand;
 	    ++c_inhibit_evaluation_warnings;
+	    ++cp_noexcept_operand;
 	    expr = cp_parser_expression (parser);
+	    --cp_noexcept_operand;
 	    --c_inhibit_evaluation_warnings;
 	    --cp_unevaluated_operand;
 
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 215797)
+++ cp/pt.c	(working copy)
@@ -14769,11 +14769,13 @@ tsubst_copy_and_build (tree t,
       op1 = TREE_OPERAND (t, 0);
       ++cp_unevaluated_operand;
       ++c_inhibit_evaluation_warnings;
+      ++cp_noexcept_operand;
       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;
+      --cp_noexcept_operand;
       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>();
+}


More information about the Gcc-patches mailing list