[ C++ 23] Confusing behavior when temporaries are provided to a function that is part of a range loop initializer.
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
https://godbolt.org/z/TT8xM4eYe
When providing temporaries into a function that is used as the for-range-initializer, the temporaries are destroyed before the end of the full expression. Sample code can be found below with a live example in compiler explorer. This only happens when the function arguments for `foo` are values. When the function arguments of `foo` are references (l-value / r-value), clang's output matches the one from gcc below.
```cpp
struct Foo
{
int num = 0;
Foo() { std::cout << "Constructed!\n"; }
~Foo() { std::cout << "Destructed!\n"; }
Foo(const Foo&) = default;
Foo(Foo&&) = default;
auto operator=(const Foo&) -> Foo& = default;
auto operator=(Foo&&) -> Foo& = default;
};
struct JankStringView : std::string_view
{
using super = std::string_view;
using super::super;
~JankStringView() { std::cout << "string view is destroyed\n"; }
};
struct JankString : std::string
{
using super = std::string;
using super::super;
~JankString() { std::cout << "string is destroyed\n"; }
};
auto foo([[maybe_unused]] Foo f, [[maybe_unused]] JankStringView view) -> std::vector
{
std::cout << view.data() << "\n";
std::cout << "Exiting coroutine\n";
return { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
};
auto main() -> int
{
for (auto x : foo(Foo{}, JankStringView{ JankString{ "Hello" }.c_str() }))
{
std::cout << "x: " << x << "\n";
}
return 0;
}
```
On Clang (trunk), the output is:
```
Constructed!
Hello
Exiting coroutine
string view is destroyed
Destructed!
x: 1
x: 2
x: 3
x: 4
x: 5
x: 6
x: 7
x: 8
x: 9
x: 10
string is destroyed
```
On GCC (trunk) however, the output is more aligned with the wording that's in the [standard](https://eel.is/c++draft/class.temporary#4).
```
Constructed!
Hello
Exiting coroutine
x: 1
x: 2
x: 3
x: 4
x: 5
x: 6
x: 7
x: 8
x: 9
x: 10
string view is destroyed
string is destroyed
Destructed!
```
Contributor guide
Research direction
Start with the Compiler Explorer reproducer at https://godbolt.org/z/TT8xM4eYe and read the linked standard wording on temporary object lifetimes. Trace Clang's C++23 range-for handling and compare its result with GCC; done means the temporaries remain alive through the loop as required by the standard.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100