diff mbox

c++/78765

Message ID af30b5d3-07a7-78e2-d0ea-930cc5e00ae6@acm.org
State Superseded
Headers show

Commit Message

Nathan Sidwell Dec. 16, 2016, 12:23 p.m. UTC
Jason,
this patch fixes an ICE that happens after error recovery of a constexpr 
object that has a bad initializer.

your patch introduced this regression:
* tree.c (obvalue_p): Rename from lvalue_p.
	(lvalue_p): Define for c-common.
	* call.c, cp-tree.h, cvt.c, init.c: Adjust.
	* typeck.c: Adjust.
	(cp_build_addr_expr_1): Remove obsolete code.

that cp_build_addr_expr_1 change turns out not quite obsolete.

when cxx_eval_constant_expression finds a nonconstant expression it 
returns a TREE without TREE_CONSTANT set.
   else if (non_constant_p && TREE_CONSTANT (r))
   {
       /* This isn't actually constant, so unset TREE_CONSTANT.  */
       ...
      else // THIS CASE HAPPENS
	r = build_nop (TREE_TYPE (r), r);
       TREE_CONSTANT (r) = false;
    }

In this case r is the VAR_DECL for 'var'. And cp_build_addr_expr_1 is 
called to build the object expression to apply ValueType::operator int ().

This patch simply strips the NOP expr.  I placed that code in the 
lvalue_kind checking block, because of the comment in the switch statement:
     CASE_CONVERT:
     case FLOAT_EXPR:
     case FIX_TRUNC_EXPR:
       /* We should have handled this above in the lvalue_kind check.  */
       gcc_unreachable ();

Alternatively we could check if we've met this case just there. (which 
was the original location of the obsolete code)

ok?

nathan
-- 
Nathan Sidwell

Comments

Jason Merrill Jan. 4, 2017, 5:40 a.m. UTC | #1
On 12/16/2016 07:23 AM, Nathan Sidwell wrote:
> when cxx_eval_constant_expression finds a nonconstant expression it

> returns a TREE without TREE_CONSTANT set.

>   else if (non_constant_p && TREE_CONSTANT (r))

>   {

>       /* This isn't actually constant, so unset TREE_CONSTANT.  */

>       ...

>      else // THIS CASE HAPPENS

>     r = build_nop (TREE_TYPE (r), r);

>       TREE_CONSTANT (r) = false;

>    }


Hmm, we shouldn't get here for an expression we're going to use as an 
lvalue.

Jason
Nathan Sidwell Jan. 4, 2017, 2:33 p.m. UTC | #2
On 01/04/2017 12:40 AM, Jason Merrill wrote:
> On 12/16/2016 07:23 AM, Nathan Sidwell wrote:

>> when cxx_eval_constant_expression finds a nonconstant expression it

>> returns a TREE without TREE_CONSTANT set.

>>   else if (non_constant_p && TREE_CONSTANT (r))

>>   {

>>       /* This isn't actually constant, so unset TREE_CONSTANT.  */


> Hmm, we shouldn't get here for an expression we're going to use as an

> lvalue.


I don't think we know we're going to use it as an lvalue early enough. 
We get here from convert_nontype_argument:
      else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
	expr = maybe_constant_value (expr);
and fail to have 'var' as a constexpr (because it had a bogus 
initializer, for which we emitted a diagnostic).

We then get to:
   if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
     {
       tree t = build_integral_nontype_arg_conv (type, expr, complain);
and that finds the conversion operator, which needs var as the object 
expression.

I suppose at that point, if expr is not constant we've already lost. 
Perhaps build_integral_nontype_arg_conv should bail out earlier?

Or is the problem in the error recovery of:
static constexpr ValueType var = 0;

should we unmark the constexprness of var?

WDYT?

nathan
-- 
Nathan Sidwell
Jason Merrill Jan. 4, 2017, 3:13 p.m. UTC | #3
On Wed, Jan 4, 2017 at 9:33 AM, Nathan Sidwell <nathan@acm.org> wrote:
> On 01/04/2017 12:40 AM, Jason Merrill wrote:

>> On 12/16/2016 07:23 AM, Nathan Sidwell wrote:

>>>

>>> when cxx_eval_constant_expression finds a nonconstant expression it

>>> returns a TREE without TREE_CONSTANT set.

>>>   else if (non_constant_p && TREE_CONSTANT (r))

>>>   {

>>>       /* This isn't actually constant, so unset TREE_CONSTANT.  */

>

>> Hmm, we shouldn't get here for an expression we're going to use as an

>> lvalue.

>

> I don't think we know we're going to use it as an lvalue early enough. We

> get here from convert_nontype_argument:

>      else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))

>         expr = maybe_constant_value (expr);


OK, that looks like the problem; we shouldn't be calling
maybe_constant_value before we perform the conversion.

Jason
diff mbox

Patch

2016-12-15  Nathan Sidwell  <nathan@acm.org>

	PR c++/78765
	* typeck.c (cp_build_addr_expr_1): Cope with failed constexpr eval
	of incoming arg.

	PR c++/78765
	* g++.dg/cpp0x/pr78765.C: New.

Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 243692)
+++ cp/typeck.c	(working copy)
@@ -5645,9 +5645,24 @@  cp_build_addr_expr_1 (tree arg, bool str
 	  else
 	    error ("taking address of xvalue (rvalue reference)");
 	}
+
+      /* If ARG comes from a failed constexpr evaluation, it might be
+	 wrapped in a NOP_EXPR to remove TREE_CONSTANT.  */
+      if (kind == clk_class && TREE_CODE (arg) == NOP_EXPR)
+	{
+	  gcc_assert (!TREE_CONSTANT (arg)
+		      && TREE_CONSTANT (TREE_OPERAND (arg, 0))
+		      && same_type_p (argtype,
+				      TREE_TYPE (TREE_OPERAND (arg, 0))));
+	  arg = TREE_OPERAND (arg, 0);
+	}
     }
 
   if (TREE_CODE (argtype) == REFERENCE_TYPE)
Index: testsuite/g++.dg/cpp0x/pr78765.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr78765.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr78765.C	(working copy)
@@ -0,0 +1,15 @@ 
+// PR c++/78765
+// { dg-do compile { target c++11 } }
+
+// ICE with failed constexpr object and member fn call
+
+struct ValueType {
+  constexpr operator int() const {return field;}
+  int field;
+};
+
+static constexpr ValueType var = 0; // { dg-error "conversion" }
+
+template <int> class ValueTypeInfo;
+
+ValueTypeInfo<var> x;