Skip to content

decltype((x)) inside lambda is considered odr-use if x is captured #34771

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

Closed
llvmbot opened this issue Nov 26, 2017 · 4 comments
Closed

decltype((x)) inside lambda is considered odr-use if x is captured #34771

llvmbot opened this issue Nov 26, 2017 · 4 comments
Labels
bugzilla Issues migrated from bugzilla c++ invalid Resolved as invalid, i.e. not a bug

Comments

@llvmbot
Copy link
Member

llvmbot commented Nov 26, 2017

Bugzilla Link 35423
Resolution INVALID
Resolved on Dec 16, 2017 08:59
Version trunk
OS All
Reporter LLVM Bugzilla Contributor
CC @dwblaikie,@DougGregor,@zygoloid

Extended Description

https://godbolt.org/g/NmA3ZP

#include <type_traits>

int main() {
int x = 1;
int&& y = static_cast<int&&>(x);

auto A = []{ static_assert(std::is_same_v<decltype((x)), int&>); };
auto B = [=]{ static_assert(std::is_same_v<decltype((x)), int&>); };

auto C = []{ static_assert(std::is_same_v<decltype((y)), int&>); };
auto D = [=]{ static_assert(std::is_same_v<decltype((y)), int&>); };

}

I expected this to compile cleanly, but static asserts B and D fail under clang.

Here is how i would argue for my expectation:

http://eel.is/c++draft/expr.prim.lambda#capture-11.sentence-3
-- "An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type."
http://eel.is/c++draft/basic.def.odr#def:potentially_evaluated
-- "An expression is potentially evaluated unless it is an unevaluated operand or a subexpression thereof."
http://eel.is/c++draft/basic.def.odr#def:odr-used
-- "A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless [...]"
http://eel.is/c++draft/dcl.type.simple#4.sentence-3
-- "The operand of the decltype specifier is an unevaluated operand."

@llvmbot
Copy link
Member Author

llvmbot commented Nov 27, 2017

For the case

[expr.prim.lambda]p20 says that references to outer entities within decltype expressions, other than the special decltype(x) form, are type-checked as if the variables were notionally captured.

gets invoked, there's also the contradictory "lambda capture 'v' is not required to be captured for this use" warning for the following code (https://godbolt.org/g/6pC74v):

template auto f(T &&v) {
return [v] {
return (decltype( (v) )(*)()) nullptr;
} ();
}

template auto g(T &&v) {
return [] {
return (decltype( (v) )(*)()) nullptr;
} ();
}

#include <type_traits>

int main() {
static_assert(
std::is_same_v<decltype(f(42)), decltype(g(42))>,
"not same, so the capture is not required?"
);
}

@zygoloid
Copy link
Mannequin

zygoloid mannequin commented Dec 16, 2017

Prior to P0588R1:

[expr.prim.lambda.capture]/14:

"Every occurrence of decltype((x)) where x is a possibly parenthesized id-expression that names an entity of automatic storage duration is treated as if x were transformed into an access to a corresponding data member of the closure type that would have been declared if x were an odr-use of the denoted entity."

This is clear that Clang is correct that B and D give decltype((x)) as const int&, not int&. But the types of A and C are unclear.

After P0588R1, the wording is a bit clearer:

[expr.prim.id.unqual]/1:

"If the entity is a local entity and naming it from outside of an unevaluated operand within the declarative region where the unqualified-id appears would result in some intervening lambda-expression capturing it by copy, the type of the expression is the type of a class member access expression ([expr.ref]) naming the non-static data member that would be declared for such a capture in the closure object of the innermost such intervening lambda-expression. [ Note: If that lambda-expression is not declared mutable, the type of such an identifier will typically be const qualified. ]"

Here we see that A and C should have type int& and B and D should have type const int&.

@llvmbot
Copy link
Member Author

llvmbot commented Nov 27, 2021

mentioned in issue llvm/llvm-bugzilla-archive#35669

@llvmbot
Copy link
Member Author

llvmbot commented Nov 27, 2021

mentioned in issue llvm/llvm-bugzilla-archive#36753

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
This issue was closed.
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++ invalid Resolved as invalid, i.e. not a bug
Projects
None yet
Development

No branches or pull requests

1 participant