Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constexpr non-scalar variable not usable in lambda without capture or local class #34603

Open
DaemonSnake opened this issue Nov 8, 2017 · 4 comments
Labels
bugzilla Issues migrated from bugzilla c++17 clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid

Comments

@DaemonSnake
Copy link

DaemonSnake commented Nov 8, 2017

Bugzilla Link 35255
Version trunk
OS other
CC @davidstone,@DougGregor,@JohelEGP

Extended Description

Tested through compiler explorer with the version 6.0.0 (trunk 317548).
Link of the example: https://godbolt.org/g/Q91sd1

code:

struct A { constexpr A() {} };

template<class T>
void func(T x)
{
    constexpr auto y = x();
    (void)[] { auto x = y; }; //with non literal: "error: variable 'y' cannot be implicitly captured in a lambda with no capture-default specified"
    struct A { decltype(y) value = y; }; //with non-literal: "error: reference to local variable 'y' declared in enclosing function ..."
}

int main()
{
    func([]{return 3;}); //no error
    func([]{return A{}; }); //error
}

log:

7 : <source>:7:25: error: variable 'y' cannot be implicitly captured in a lambda with no capture-default specified
    (void)[] { auto x = y; };
                        ^
14 : <source>:14:5: note: in instantiation of function template specialization 'func<(lambda at /tmp/compiler-explorer-compiler117108-60-mn1ptp.k9dm5i2j4i/example.cpp:14:10)>' requested here
    func([]{return A{}; });
    ^
6 : <source>:6:20: note: 'y' declared here
    constexpr auto y = x();
                   ^
7 : <source>:7:11: note: lambda expression begins here
    (void)[] { auto x = y; };
          ^
8 : <source>:8:36: error: reference to local variable 'y' declared in enclosing function 'func<(lambda at /tmp/compiler-explorer-compiler117108-60-mn1ptp.k9dm5i2j4i/example.cpp:14:10)>'
    struct A { decltype(y) value = y; };
                                   ^
8 : <source>:8:12: note: in instantiation of default member initializer 'func((lambda at /tmp/compiler-explorer-compiler117108-60-mn1ptp.k9dm5i2j4i/example.cpp:14:10))::A::value' requested here
    struct A { decltype(y) value = y; };
           ^
14 : <source>:14:5: note: in instantiation of function template specialization 'func<(lambda at /tmp/compiler-explorer-compiler117108-60-mn1ptp.k9dm5i2j4i/example.cpp:14:10)>' requested here
    func([]{return A{}; });
    ^
6 : <source>:6:20: note: 'y' declared here
    constexpr auto y = x();
                   ^

version:
clang version 6.0.0 (trunk 317548)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/compiler-explorer/clang-trunk/bin
Found candidate GCC installation: /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0
Selected GCC installation: /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0
Candidate multilib: .;@m64
Selected multilib: .;@m64
 "/opt/compiler-explorer/clang-trunk-20171107/bin/clang-6.0" -cc1 -triple x86_64-unknown-linux-gnu -S -disable-free -disable-llvm-verifier -discard-value-names -main-file-name example.cpp -mrelocation-model static -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -v -coverage-notes-file /tmp/compiler-explorer-compiler117108-60-ffz0kd.942tymn29/output.gcno -resource-dir /opt/compiler-explorer/clang-trunk-20171107/lib/clang/6.0.0 -c-isystem /usr/include/x86_64-linux-gnu -cxx-isystem /usr/include/x86_64-linux-gnu -internal-isystem /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0/../../../../include/c++/7.1.0 -internal-isystem /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0/../../../../include/c++/7.1.0/x86_64-linux-gnu -internal-isystem /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0/../../../../include/c++/7.1.0/backward -internal-isystem /usr/local/include -internal-isystem /opt/compiler-explorer/clang-trunk-20171107/lib/clang/6.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c++1z -fdeprecated-macro -fdebug-compilation-dir /compiler-explorer -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -mllvm --x86-asm-syntax=intel -o /tmp/compiler-explorer-compiler117108-60-ffz0kd.942tymn29/output.s -x c++ <source>
clang -cc1 version 6.0.0 based upon LLVM 6.0.0svn default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/include"
ignoring duplicate directory "/usr/include/x86_64-linux-gnu"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/x86_64-linux-gnu
 /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0/../../../../include/c++/7.1.0
 /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0/../../../../include/c++/7.1.0/x86_64-linux-gnu
 /opt/compiler-explorer/gcc-7.1.0/lib/gcc/x86_64-linux-gnu/7.1.0/../../../../include/c++/7.1.0/backward
 /usr/local/include
 /opt/compiler-explorer/clang-trunk-20171107/lib/clang/6.0.0/include
 /usr/include
@davidstone
Copy link
Contributor

It looks like you have two separate test cases here. The first test case can be reduced to

void a() {
	constexpr auto x = 0;
	[] { x; };
}

I believe clang is correct to reject this program.

The second test case is

struct A { };

void g() {
	constexpr auto x = A();
	struct B { A value = x; };
}

clang also rejects this program, and I agree that it's surprising that it is accepted if all of the A in g are replaced with int, but I also believe clang is correct to reject this program.

@DaemonSnake
Copy link
Author

From: https://en.cppreference.com/w/cpp/language/lambda
A lambda expression can read the value of a variable without capturing it if the variable has const non-volatile integral or enumeration type and has been initialized with a constant expression, or is constexpr and has no mutable members.

So the example you've provided is actually a reject-valid here:

void a() {
	constexpr auto x = 0;
	[] { x; }; //error here
}

but even if, it doesn't explain why being in a dependent scope (template) would turn it into a valid:

template<class T = int>
void func()
{
    constexpr auto y = 0;
    [] { auto x = y; }; //no longer an error here
}

int main()
{
    func();
}

@shafik
Copy link
Collaborator

shafik commented Jul 11, 2023

CC @cor3ntin

@EugeneZelenko EugeneZelenko added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Jul 11, 2023
@llvmbot
Copy link
Member

llvmbot commented Jul 11, 2023

@llvm/issue-subscribers-clang-frontend

@Endilll Endilll added rejects-valid and removed compile-fail Use [accepts-invalid] and [rejects-valid] instead labels Aug 16, 2023
@Endilll Endilll changed the title [rejects valid] constexpr non-scalar variable not usable in lambda without capture or local class Constexpr non-scalar variable not usable in lambda without capture or local class Aug 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla c++17 clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid
Projects
None yet
Development

No branches or pull requests

6 participants