Bug 79378 - lambda init-capture adds const
Summary: lambda init-capture adds const
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.0.1
: P3 normal
Target Milestone: 14.0
Assignee: Patrick Palka
Keywords: c++-lambda, wrong-code
Depends on:
Reported: 2017-02-04 22:40 UTC by Barry Revzin
Modified: 2023-11-10 15:59 UTC (History)
5 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2017-02-06 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Barry Revzin 2017-02-04 22:40:14 UTC
Minimal example:

template <class T, class U> struct is_same { static constexpr bool value = false; };
template <class T> struct is_same<T, T> { static constexpr bool value = true; };

int main() {
    int i = 0;
    return [j = i]() {
        static_assert(is_same<decltype(j), int>::value, "!");
        return j;

The static_assert fires on gcc 7 (and every other version I've tried) because it says that decltype(j) is const int. If the lambda were marked mutable, then decltype(j) is reported correct as int.
Comment 1 Jonathan Wakely 2017-02-06 01:37:02 UTC
We also get the r2 case wrong for the example in [expr.prim.lamda] p20:

template <class T, class U> struct is_same { static constexpr bool value = false; };
template <class T> struct is_same<T, T> { static constexpr bool value = true; };
void f3() {
float x, &r = x;
[=] {
 // x and r are not captured (appearance in a decltype operand is not an odr-use)
decltype(x) y1;
static_assert(is_same<decltype(y1), float>::value, "y1 has type float");
decltype((x)) y2 = y1;
static_assert(is_same<decltype(y2), float const&>::value, "y2 has type float const& because this lambda is not mutable and x is an lvalue");
decltype(r) r1 = y1;
static_assert(is_same<decltype(r1), float&>::value, "r1 has type float& (transformation not considered)");
decltype((r)) r2 = y2;
static_assert(is_same<decltype(r2), float const&>::value, "r2 has type float const&");

lam2.cc: In lambda function:
lam2.cc:13:20: error: binding reference of type ‘float&’ to ‘const float’ discards qualifiers
 decltype((r)) r2 = y2;
lam2.cc:14:1: error: static assertion failed: r2 has type float const&
 static_assert(is_same<decltype(r2), float const&>::value, "r2 has type float const&");
Comment 2 Vittorio Romeo 2020-07-18 11:39:16 UTC
Stumbled upon this again, with this example:

    template <typename, typename>
    constexpr bool is_same_v = false;

    template <typename T>
    constexpr bool is_same_v<T, T> = true;

    auto l = [k = 0]
        static_assert(is_same_v<decltype(k), int>);

This bug is still not fixed in the latest version of GCC (trunk).

Related StackOverflow post: 

Example on Compiler Explorer:
Comment 3 GCC Commits 2023-11-10 15:58:16 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:


commit r14-5330-g705ab7927c81b77503d229513fac991106617766
Author: Patrick Palka <ppalka@redhat.com>
Date:   Fri Nov 10 10:58:04 2023 -0500

    c++: decltype of capture proxy [PR79378, PR96917]
    We typically don't see capture proxies in finish_decltype_type because
    process_outer_var_ref is a no-op within an unevaluated context and so a
    use of a captured variable within decltype resolves to the captured
    variable, not the capture.  But we can see them during decltype(auto)
    deduction and for decltype of an init-capture, which suggests we need to
    handle capture proxies specially within finish_decltype_type after all.
    This patch adds such handling.
            PR c++/79378
            PR c++/96917
            * semantics.cc (finish_decltype_type): Handle an id-expression
            naming a capture proxy specially.
            * g++.dg/cpp1y/decltype-auto7.C: New test.
            * g++.dg/cpp1y/lambda-init20.C: New test.
    Reviewed-by: Jason Merrill <jason@redhat.com>
Comment 4 Patrick Palka 2023-11-10 15:59:27 UTC
Fixed for GCC 14.