Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16.2?

-- >8 --
Thanks to DR 696 (r253266), this works:

  int g;
  void fn ()
  {
    int &c = g;
    auto l = [] { c++; };
    l();
  }

because `c` in the lambda body is not an odr-use because we can
evaluate it to a constant and so there's no capture.  But when
fn is a template, we reject the code and crash.  This patch fixes
both.

Outside a template, the call to maybe_constant_value in mark_use
evaluates `c` to `(int&) &g` but in a template, it remains `c`.
Then we emit an error, and crash on the error_mark_node from
process_outer_var_ref.  One of the reasons is
      else if (TYPE_REF_P (TREE_TYPE (expression)))
        /* FIXME cp_finish_decl doesn't fold reference initializers.  */
        return true;
in value_dependent_expression_p but even if that changed, we still
wouldn't get the referent because decl_really_constant_value wouldn't
give it to us; the DECL_INITIAL is not a TREE_CONSTANT yet.

So I stopped trying to make this work in a template, and instead
I'm delaying the processing to instantiating when we know that
maybe_constant_value wouldn't even try to evaluate.

The is_capture_proxy change is due to lambda-scope10.C: we are
checking is_nondependent_constant_expression before the enclosing
function has been built up.

        PR c++/123536

gcc/cp/ChangeLog:

        * expr.cc (mark_use) <case VAR_DECL>: Check
        is_nondependent_constant_expression before
        process_outer_var_ref.
        * lambda.cc (is_capture_proxy): Check DECL_CONTEXT.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/lambda/lambda-const12.C: New test.
---
 gcc/cp/expr.cc                                |  3 +-
 gcc/cp/lambda.cc                              |  1 +
 .../g++.dg/cpp0x/lambda/lambda-const12.C      | 48 +++++++++++++++++++
 3 files changed, 51 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C

diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
index 4d017d530ef..15036cf7cad 100644
--- a/gcc/cp/expr.cc
+++ b/gcc/cp/expr.cc
@@ -131,7 +131,8 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
            }
        }
       if (outer_automatic_var_p (expr)
-         && decl_constant_var_p (expr))
+         && decl_constant_var_p (expr)
+         && is_nondependent_constant_expression (expr))
        {
          if (rvalue_p)
            {
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index af0b66afe81..0b35c18da13 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -288,6 +288,7 @@ is_capture_proxy (tree decl)
          && !(DECL_ARTIFICIAL (decl)
               && DECL_LANG_SPECIFIC (decl)
               && DECL_OMP_PRIVATIZED_MEMBER (decl))
+         && DECL_CONTEXT (decl)
          && LAMBDA_FUNCTION_P (DECL_CONTEXT (decl)));
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C 
b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C
new file mode 100644
index 00000000000..eca53461c69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C
@@ -0,0 +1,48 @@
+// PR c++/123536
+// { dg-do compile { target c++11 } }
+
+int g;
+
+template<int = 1>
+void
+fn1 ()
+{
+  int &c = g;
+  auto l = [] { c++; };
+  l();
+}
+
+template<int N = 1>
+void
+fn2 ()
+{
+  const int &c = N;
+  auto l = [] { int i = c; (void) i; }; // { dg-error ".c. is not captured" }
+  l();
+}
+
+void
+fn3 ()
+{
+  int &c = g;
+  auto l = [] { c++; };
+  l();
+}
+
+void
+fn4 ()
+{
+  int n = 42;
+  const int &c = n;
+  auto l = [] { int i = c; (void) i; }; // { dg-error ".c. is not captured" }
+  l();
+}
+
+void
+bar ()
+{
+  fn1 ();
+  fn2 ();
+  fn3 ();
+  fn4 ();
+}

base-commit: 8b40209e48c8212ad870724b83718ed244bdf6eb
-- 
2.54.0

Reply via email to