In this testcase, N is only used in the lambda for its constant value, so it should not be captured. The problem was that we didn't call mark_rvalue_use on N when instantiating the lambda, because it was wrapped in a NOP_EXPR converting it to the type of the template argument. Rather than try to add mark_rvalue_use everywhere that calls build_nop, let's make mark_rvalue_use look through all NOP_EXPR, not just location wrappers.
Tested x86_64-pc-linux-gnu, applying to trunk and 8.
commit 6f0db97dbb4a43a69bc4ea4c32960cbd77b104a0 Author: Jason Merrill <ja...@redhat.com> Date: Fri Jun 15 17:05:39 2018 -0400 PR c++/86147 - wrong capture for template argument. * expr.c (mark_use): Look through NOP_EXPR. diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 9780b75d1cd..133a01b8a51 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -186,12 +186,15 @@ mark_use (tree expr, bool rvalue_p, bool read_p, expr = convert_from_reference (r); } break; - default: + + CASE_CONVERT: + case VIEW_CONVERT_EXPR: if (location_wrapper_p (expr)) - { - loc = EXPR_LOCATION (expr); - recurse_op[0] = true; - } + loc = EXPR_LOCATION (expr); + recurse_op[0] = true; + break; + + default: break; } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const9.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const9.C new file mode 100644 index 00000000000..0724ae15d88 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const9.C @@ -0,0 +1,17 @@ +// PR c++/86147 +// { dg-do compile { target c++11 } } + +template <class T, T N> struct X { }; + +struct A { static constexpr int value = 0; }; + +template<class C> +void foo() { + constexpr int N = C::value; + auto f = [&]{ X<int, N> a; }; +} + +int main() { + foo<A>(); + return 0; +}