intel / intel/llvm

icpx generates incorrect program when using std::format with if branches and custom type formatter

Open
#23,040 1 comment 0 reactions 0 assignees View on GitHub
bug
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.