[clang-cl][x86] miscompiles `co_return std::string("hello")` in a coroutine returning `std::string`
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
# clang-cl x86 miscompiles `co_return std::string("hello")` in a coroutine returning `std::string`
## Bug Summary
`clang-cl` on Windows x86 appears to miscompile this coroutine:
```cpp
Task run() { co_return std::string("hello"); }
```
It reproduces for me in both x86 Debug and x86 Release builds.
The same source works on the same machine with:
- `clang-cl` x64
- MSVC
## Reproducer
```cpp
#include
#include
#include
#include
#include
template
struct Task {
struct promise_type {
std::optional result;
Task get_return_object() { return { std::coroutine_handle::from_promise(*this) }; }
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_value(T value) { result.emplace(std::move(value)); }
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle h;
Task(std::coroutine_handle h) : h(h) {}
Task(Task&& other) noexcept : h(std::exchange(other.h, {})) {}
Task(const Task&) = delete;
Task& operator=(const Task&) = delete;
~Task() { if (h) h.destroy(); }
T take() { return std::move(*h.promise().result); }
};
Task run() { co_return std::string("hello"); }
int main() { return run().take() == "hello" ? 0 : 1; }
```
## Commands
Failing x86 Debug build:
```bat
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
"C:\Program Files\LLVM\bin\clang-cl.exe" ^
/nologo /std:c++20 /EHsc /Od /Zi /MDd /DDEBUG /clang:-m32 ^
repro.cpp
repro.exe
```
Failing x86 Release build:
```bat
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
"C:\Program Files\LLVM\bin\clang-cl.exe" ^
/nologo /std:c++20 /EHsc /O2 /DNDEBUG /MD /clang:-m32 ^
repro.cpp
repro.exe
```
Working control builds:
```bat
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
"C:\Program Files\LLVM\bin\clang-cl.exe" ^
/nologo /std:c++20 /EHsc /Od /Zi /MDd /DDEBUG ^
repro.cpp
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
cl /nologo /std:c++20 /EHsc /Od /Zi /MDd /DDEBUG repro.cpp
```
## Expected Behavior
The program should exit with code `0`.
## Actual Behavior
With `clang-cl` x86, the program crashes with an access violation.
In the Debug build, the fault shows up while the returned `std::string` is being constructed or moved into the promise storage (`std::optional`).
## Stack Trace
From a failing x86 Debug build under `cdb`:
```text
clangcl_x86_coroutine_return_value_repro!std::basic_string,std::allocator >::_Swap_proxy_and_iterators
clangcl_x86_coroutine_return_value_repro!std::basic_string,std::allocator >::_Take_contents
clangcl_x86_coroutine_return_value_repro!std::basic_string,std::allocator >::basic_string
clangcl_x86_coroutine_return_value_repro!std::optional,std::allocator > >::emplace
clangcl_x86_coroutine_return_value_repro!Task,std::allocator > >::promise_type::return_value
clangcl_x86_coroutine_return_value_repro!run
clangcl_x86_coroutine_return_value_repro!main
```
Relevant source frames from my local build:
```text
Task::promise_type::return_value (clangcl_x86_coroutine_return_value_repro.cpp:28)
run (clangcl_x86_coroutine_return_value_repro.cpp:41)
main (clangcl_x86_coroutine_return_value_repro.cpp:43)
```
## Environment
- OS: Microsoft Windows 10.0.19045.6456
- `clang-cl --version`:
```text
clang version 21.1.8
Target: i386-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
```
- MSVC x86 compiler version:
```text
Microsoft (R) C/C++ Optimizing Compiler Version 19.44.35225 for x86
```
- MSVC linker version:
```text
Microsoft (R) Incremental Linker Version 14.44.35225.0
```
## Reduction Notes
I started from a larger reproducer involving:
- a custom wrapper type containing `std::string`
- a separate `make(std::string)` helper
- `co_return make("hello")`
After reduction, these are **not required** in my tests:
- a custom wrapper type
- a separate callee function
- a callee taking `std::string` by value
I also tested a variant where `promise_type::return_value` takes `T&&` instead of `T value`, and that still reproduced, so I am intentionally **not** claiming that pass-by-value in `return_value` is a necessary condition.
Contributor guide
Research direction
Start with the standalone repro.cpp and run the failing clang-cl x86 Debug and Release commands, then compare them with the working clang-cl x64 and MSVC builds. Focus investigation on the coroutine run function and promise_type::return_value path shown in the stack trace. Done means the x86 executable exits with code 0 without an access violation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100