Skip to content

Commit 54e90ae

Browse files
committed
Fix __int128_t redefinition in int128.h !CONFIG_INT128 fallback on Clang/GCC
The struct-based fallback aliases the reserved builtin name __int128_t to `struct Int128` so fallback code can name the type. That is only valid on compilers that do NOT provide __int128_t as a builtin; on GCC/Clang it is a "typedef redefinition with different types ('Int128' vs '__int128')" error whenever a build reaches this fallback. It bit real Clang builds — Apple clang on arm64, and the Rust `unicorn-engine-sys` crate's vendored build. PR #2251 guarded this only for clang-cl (`_MSC_VER && __clang__`). Gate instead on `!defined(__SIZEOF_INT128__)` — the standard macro that is defined iff the compiler provides the 128-bit builtin — which correctly skips the alias for all GCC/Clang (including clang-cl) and keeps emitting it for MSVC, subsuming #2251. Add tests/regress/int128_redefinition.c reproducing the exact fallback construct (fails to compile with the old guard on any __int128-capable compiler, compiles with the fix), and a CI workflow compiling it on macos-14 (Apple Silicon, arm64 clang), macos-13 (Intel) and Linux. Existing CI never covers this: the C build on macos-14 uses cmake with CONFIG_INT128 defined (native path, fallback not compiled), and the Rust-crate CI does not run on Apple Silicon.
1 parent 7c5db94 commit 54e90ae

3 files changed

Lines changed: 96 additions & 1 deletion

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: int128 fallback regression
2+
3+
# Guards the !CONFIG_INT128 fallback in qemu/include/qemu/int128.h against the
4+
# __int128_t redefinition that broke real Clang builds (e.g. Apple clang on
5+
# arm64, and the Rust unicorn-engine-sys crate). The existing C-library CI builds
6+
# on macos-14 (arm64) but via cmake with CONFIG_INT128 defined, so it uses the
7+
# native path and never compiles the fallback; the Rust-crate CI does not run on
8+
# Apple Silicon. This job compiles the fallback construct directly on every
9+
# platform whose compiler exposes the __int128_t builtin — including arm64
10+
# Apple clang, where the pre-fix guard fails.
11+
12+
on:
13+
push:
14+
paths:
15+
- 'qemu/include/qemu/int128.h'
16+
- 'tests/regress/int128_redefinition.c'
17+
- '.github/workflows/int128-regression.yml'
18+
pull_request:
19+
paths:
20+
- 'qemu/include/qemu/int128.h'
21+
- 'tests/regress/int128_redefinition.c'
22+
- '.github/workflows/int128-regression.yml'
23+
workflow_dispatch:
24+
25+
jobs:
26+
compile:
27+
name: ${{ matrix.name }}
28+
runs-on: ${{ matrix.os }}
29+
strategy:
30+
fail-fast: false
31+
matrix:
32+
include:
33+
- { os: ubuntu-latest, name: 'linux-x86_64' }
34+
- { os: macos-13, name: 'macos-x86_64 (Intel clang)' }
35+
- { os: macos-14, name: 'macos-arm64 (Apple clang)' }
36+
steps:
37+
- uses: actions/checkout@v4
38+
- name: Compile + run int128 fallback regression
39+
run: |
40+
cc -Wall -Wextra -Werror -o int128_regress tests/regress/int128_redefinition.c
41+
./int128_regress

qemu/include/qemu/int128.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,18 @@ static inline Int128 bswap128(Int128 a)
146146
#else /* !CONFIG_INT128 */
147147

148148
typedef struct Int128 Int128;
149-
#if !(defined(_MSC_VER) && defined(__clang__))
149+
/*
150+
* In the !CONFIG_INT128 fallback, QEMU aliases the reserved builtin name
151+
* __int128_t to the struct so fallback code can name it. That is only valid on
152+
* compilers that do NOT provide __int128_t as a builtin: emitting it where the
153+
* builtin exists is a "typedef redefinition with different types" error. The
154+
* builtin is present iff __SIZEOF_INT128__ is defined (GCC/Clang), so gate on
155+
* that. This subsumes the earlier clang-cl-only guard (#2251) and fixes the
156+
* redefinition seen with regular Clang (e.g. Apple clang on arm64) whenever the
157+
* build reaches this fallback. Regression test: tests/regress/int128_redefinition.c
158+
* (keep the guard below in sync with it).
159+
*/
160+
#if !defined(__SIZEOF_INT128__)
150161
typedef Int128 __int128_t;
151162
#endif
152163

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Regression guard for the __int128_t redefinition in
3+
* qemu/include/qemu/int128.h (the "#else / !CONFIG_INT128" fallback).
4+
*
5+
* In that fallback QEMU aliases the reserved builtin name __int128_t to its
6+
* struct Int128 so fallback code can name the type. That is only valid on
7+
* compilers that do NOT provide __int128_t as a builtin; on GCC/Clang (where
8+
* __SIZEOF_INT128__ is defined) emitting the alias is a "typedef redefinition
9+
* with different types" error. It bit real Clang builds (e.g. Apple clang on
10+
* arm64, and the Rust unicorn-engine-sys crate) whenever the build reached the
11+
* fallback. int128.h now gates the alias on !defined(__SIZEOF_INT128__), which
12+
* subsumes the earlier clang-cl-only guard from PR #2251.
13+
*
14+
* This test reproduces the exact construct so CI compilers that DO have the
15+
* __int128_t builtin (every Linux/macOS runner) keep compiling it. Compiled
16+
* with -Werror, the pre-fix clang-cl-only guard fails here on such compilers.
17+
* Keep the guard below in sync with int128.h's fallback typedef.
18+
*/
19+
20+
#include <stdint.h>
21+
22+
typedef struct Int128 Int128;
23+
#if !defined(__SIZEOF_INT128__)
24+
/* Only aliased when the compiler lacks the __int128_t builtin (e.g. MSVC). */
25+
typedef Int128 __int128_t;
26+
#endif
27+
28+
struct Int128 {
29+
uint64_t lo;
30+
int64_t hi;
31+
};
32+
33+
int main(void)
34+
{
35+
/*
36+
* On a compiler with the builtin, __int128_t still names the 128-bit type
37+
* (the struct alias above was correctly skipped). Exercise both so the file
38+
* fails to compile if the guard ever redefines the builtin again.
39+
*/
40+
Int128 fallback = { 1, 2 };
41+
__int128_t native = ((__int128_t)fallback.hi << 64) | fallback.lo;
42+
return native == (((__int128_t)2 << 64) | 1) ? 0 : 1;
43+
}

0 commit comments

Comments
 (0)