In this test we have a user-defined conversion converting const int & to
T, and we're binding a const int to const int & -- the parameter of the
converting ctor.  We call Func with "VIEW_CONVERT_EXPR<const int>(Val)"
as an argument.  I like to use a diagram for the conversion like this:

ck_rvalue   <-   ck_user   <-   ck_identity
T                T              const int
                                V_C_E<const int>(Val)                           
  

when processing the ck_user part we call __ct_comp, whose ICS for its
argument is

ck_ref_bind   <-   ck_identity
const int &   <-   const int
                   V_C_E<const int>(Val)

this ICS comes from reference_binding, and at that time we still had "Val"
so need_temporary_p is 0.  But when processing the ck_user conversion
before calling build_over_call for the __ct_comp, we call
 7009         expr = mark_rvalue_use (expr);
for the argument which turns the V_C_E to NON_LVALUE_EXPR<42>.  Binding
"42" to const int & is possible, but requires a temporary, which we don't
create precisely because need_temporary_p is 0.  I.e. the original expr
of the conversion changed behind reference_binding's back.

Now, the call to mark_rvalue_use was added in r159096 to handle
-Wunused-but-set-variable.  Since r261121, we're actually able to turn a V_C_E
into an rvalue.  But it seems we shouldn't be trying to turn the argument into
an rvalue in the ck_user case; mark_lvalue_use should do the job (= mark is as
used) without changing an lvalue into an rvalue, breaking the ICS as above.

I'm not sure if I'm describing the issue clearly enough, but I hope this
will do.

Bootstrapped/regtested on x86_64-linux, ok for trunk/8?

2019-02-04  Marek Polacek  <pola...@redhat.com>

        PR c++/89158 - by-value capture of constexpr variable broken.
        * call.c (convert_like_real) <case ck_user>: Call mark_lvalue_use
        instead of mark_rvalue_use.

        * g++.dg/cpp0x/lambda/lambda-89158.C: New test.

diff --git gcc/cp/call.c gcc/cp/call.c
index c74d1b4ebdf..68395503e1e 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -7006,7 +7006,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, 
int argnum,
            return expr;
          }
 
-       expr = mark_rvalue_use (expr);
+       /* Calling mark_rvalue_use could turn a decl into a constant, breaking
+          e.g. the need_temporary_p assumption in the ICS.  */
+       mark_lvalue_use (expr);
 
        /* Pass LOOKUP_NO_CONVERSION so rvalue/base handling knows not to allow
           any more UDCs.  */
diff --git gcc/testsuite/g++.dg/cpp0x/lambda/lambda-89158.C 
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-89158.C
new file mode 100644
index 00000000000..15f15b46875
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-89158.C
@@ -0,0 +1,11 @@
+// PR c++/89158
+// { dg-do compile { target c++11 } }
+
+struct T { T(const int&); };
+void Func(T);
+
+void test()
+{
+  constexpr int Val = 42;
+  [Val]() { Func(Val); };
+}

Reply via email to