icpx generates incorrect program when using std::format with if branches and custom type formatter
- Dominant language
- LLVM
- Stars
- 1.5k
- Forks
- 854
- Avg merge
- 3d 17h
- Merged PRs (30d)
- 137
Description
### Describe the bug
icpx generates corrupted or crashing code when compiling custom `std::formatter` specializations with if/else branches at optimization levels -O2 or higher. The same code works correctly with -O0, -O1, or `-fno-inline`, and works without issue on GCC.
I once thought that this might be some of mine programming errors but given the test results both chatgpt and github copilot says it's unlikely a programming issue.
### To reproduce
```cpp
#include
#include
#include
template struct ArrayFormatter {
const std::array &arr;
ArrayFormatter(const std::array &a) : arr(a) {}
};
template
struct std::formatter> {
constexpr auto parse(std::format_parse_context &ctx) { return ctx.begin(); }
auto format(const ArrayFormatter &x, std::format_context &ctx) const {
auto out = ctx.out();
out = std::format_to(out, "[");
for (std::size_t i = 0; i < N; ++i) {
if (i > 0) {
out = std::format_to(out, " {}", x.arr[i]);
} else {
out = std::format_to(out, "{}", x.arr[i]);
}
}
out = std::format_to(out, "]");
return out;
}
};
std::string generate(bool opt) {
std::array a{1, 2, 3};
if (!opt) {
return std::format("false branch: {}\n", ArrayFormatter(a));
}
std::array b{4, 5, 6};
std::array c{7, 8, 9};
return std::format("true branch: {} {} {}\n", ArrayFormatter(a),
ArrayFormatter(b), ArrayFormatter(c));
}
int main(int argc, char **) {
bool opt = false;
if (argc > 1)
opt = true;
std::cout << generate(opt);
}
```
## Expected behavior
Code should compile and run correctly at all optimization levels, producing:
```
false branch: [1 2 3]
```
when running with no arguments, or with >=1 arguments giving:
```
true branch: [1 2 3] [4 5 6] [7 8 9]
```
### Compilation and Results
**icpx with -O2/-O3:**
- Correct output on false branch
- true branch segfault
**icpx with -O2/-O3 and -fno-inline:**
- Correct output
**icpx with -O0/-O1:**
- Correct output
**GCC (all optimization levels):**
- Correct output
### Workaround
- directly specializing std::array or changing the reference in ArrayFormatter to value will show corrupted elements:
Print `true branch: [-125385936 32583 32] [0 6 -2147483648] [0 0 2]` Code
```cpp
template struct ArrayFormatter {
std::array arr;
ArrayFormatter(const std::array &a) : arr(a) {}
};
```
- when ArrayFormatter stores by value, adding an a[0] in format shows correct elements for a but b,c are still corrupted, same for b[0]
Print `true branch: [1 2 3] [0 6 -2147483648] [0 0 2] 1` Code
```cpp
return std::format("true branch: {} {} {} {}\n", ArrayFormatter(a), ArrayFormatter(b), ArrayFormatter(c), a[0]);
```
- when ArrayFormatter stores by value, add a[0] b[0] c[0] in the format gives the correct result, but still segfault when it stores by reference.
Print `true branch: [1 2 3] [4 5 6] [7 8 9] 1 4 7` Code
```cpp
return std::format("true branch: {} {} {} {} {} {}\n", ArrayFormatter(a), ArrayFormatter(b), ArrayFormatter(c), a[0], b[0], c[0]);
```
- when ArrayFormatter stores by value, adding int b_prod = b[0] * b[1] * b[2] after b, c initialization and add to the format gives correct product but still corrupted values for a,b,c.
Print `true branch: [405698400 30117 407337256] [0 6 -2147483648] [0 0 2] 120` Code
```cpp
std::string generate(bool opt) {
std::array a{1, 2, 3};
if (!opt) {
return std::format("false branch: {}\n", ArrayFormatter(a));
}
std::array b{4, 5, 6};
std::array c{7, 8, 9};
int b_prod = b[0] * b[1] * b[2];
return std::format("true branch: {} {} {} {}\n", ArrayFormatter(a),
ArrayFormatter(b), ArrayFormatter(c), b_prod);
}
```
### Environment
- OS: Linux
- Target device and vendor: Intel CPU
Intel(R) oneAPI DPC++/C++ Compiler 2025.3.2 (2025.3.2.20260112)
Target: x86_64-unknown-linux-gnu
Thread model: posix
I tested on two devices, icpx version is the same, giving same errors.
### Additional context
_No response_
Contributor guide
Research direction
Start with the provided C++ reproducer and compile it with icpx at -O2 and -O3, then compare against -O0, -O1, -fno-inline, and GCC. Trace the custom std::formatter and optimized if/else path; done means both branches produce the expected output without corruption or a segfault.
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
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 62/100