You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
c(msvc): #1745 drops MS anonymous tagged/typedef members on *-windows-msvc (Buster predefines _MSC_EXTENSIONS) — sizeof/offsetof and member access now diverge from cl/clang-cl, and the new fixture pins the GNU answer on the Windows lanes #1750
#1745 (fixing #1706) changed c_type_parse_aggregate_segment_step so that a member declaration with no declarators adds a member only if the aggregate is untagged and defined in place. This is correct for GNU targets. But Buster applies it to every target, including *-windows-msvc. On those targets Buster predefines _MSC_VER 1940 and _MSC_EXTENSIONS 1 (c_source.c). The Microsoft C dialect accepts struct S;, union U;, a typedef name, or a nested tagged definition as an anonymous member that adds storage and promotes its fields. MSVC documents this as the "anonymous structures" extension. Clang enables it by default for *-pc-windows-msvc: -fms-extensions is implied, and it emits -Wmicrosoft-anon-tag.
Before #1745, Buster matched the MSVC layout everywhere; that was wrong on GNU targets, which is #1706. After #1745, it matches the GNU layout everywhere, which is wrong on MSVC. Neither side keys the rule on the target. The fixture #1745 added (c_test_tagged_member_declares_nothing) runs on target_native, so on the Windows CI lanes it asserts the non-MSVC sizes. The test and the compiler agree on an answer that the platform's own compiler rejects. That is the same common-mode pattern as #1439.
clang x86_64-pc-windows-msvc: accepted, with warning -Wmicrosoft-anon-tag.
clang -fno-ms-extensions, MinGW and Linux: no member named 'areacode'.
Bit-field interaction
For the same pattern under the c_record_layout_rule policy of #1452, here are size, align and offset of c, from clang x86_64-pc-windows-msvc:
struct d1 { char a; struct T; int b : 4; char c; } gives 16,4,12.
struct __attribute__((packed)) d4 { char a; struct T; int b : 20; char c; } gives 10,1,9.
union d5 { char a; struct T; int b : 3; } gives 4,4,0.
Pre-#1745 Buster matched these. Main now gives 12,4,8 / 6,1,5 / 4,1,0, which is the -fno-ms-extensions answer.
Root cause
The anonymous-member decision in c_type_parse_aggregate_segment_step (src/buster/lib/compiler/frontend/c/c_parse.c) depends only on the syntax. Whether a tagged or typedef-named aggregate is an anonymous member is a property of the dialect. Buster selects that dialect by target: Windows targets already get _MSC_VER, _MSC_EXTENSIONS, __int64 and so on. Only one oracle target was checked, gcc and clang on x86-64 Linux. The fixture then inherited that target's answer on every lane.
Proposed fix
On targets where Buster predefines _MSC_EXTENSIONS, a declarator-less member whose type is a complete struct or union (tagged, typedef-named, or a nested tagged definition) is an anonymous member. This matches clang *-pc-windows-msvc.
An incomplete tag, such as struct Fwd;, still declares nothing. Clang rejects it; rejecting it too is optional.
Summary
#1745 (fixing #1706) changed
c_type_parse_aggregate_segment_stepso that a member declaration with no declarators adds a member only if the aggregate is untagged and defined in place. This is correct for GNU targets. But Buster applies it to every target, including*-windows-msvc. On those targets Buster predefines_MSC_VER 1940and_MSC_EXTENSIONS 1(c_source.c). The Microsoft C dialect acceptsstruct S;,union U;, a typedef name, or a nested tagged definition as an anonymous member that adds storage and promotes its fields. MSVC documents this as the "anonymous structures" extension. Clang enables it by default for*-pc-windows-msvc:-fms-extensionsis implied, and it emits-Wmicrosoft-anon-tag.Before #1745, Buster matched the MSVC layout everywhere; that was wrong on GNU targets, which is #1706. After #1745, it matches the GNU layout everywhere, which is wrong on MSVC. Neither side keys the rule on the target. The fixture #1745 added (
c_test_tagged_member_declares_nothing) runs ontarget_native, so on the Windows CI lanes it asserts the non-MSVC sizes. The test and the compiler agree on an answer that the platform's own compiler rejects. That is the same common-mode pattern as #1439.Evidence
Revisions:
mainf0430c6: c: a tagged or typedef-named aggregate member declaration declares nothing (#1706) #1745 merged at 7492b42.Oracle: clang 18. Both sides are read from the
.dataimage ofunsigned long long R[].Fixture shapes from #1745
The
struct Z { struct Fwd; ... }line is omitted. Clang in MS mode rejects it with "field has incomplete type".x86_64-pc-windows-msvcaarch64-pc-windows-msvcx86_64-pc-windows-msvc -fno-ms-extensionsx86_64-w64-windows-gnux86_64-unknown-linux-gnux86_64-windows-msvcx86_64-unknown-linux-gnux86_64-windows-msvc/aarch64-windows-msvcx86_64-unknown-linux-gnuMicrosoft's documented example no longer compiles on the MSVC target
This is the example from the MSVC "Anonymous structures" documentation:
-target x86_64-windows-msvc:error: in function 'area': type 'person' has no member named 'areacode' (4 fields available).x86_64-pc-windows-msvc: accepted, with warning-Wmicrosoft-anon-tag.-fno-ms-extensions, MinGW and Linux:no member named 'areacode'.Bit-field interaction
For the same pattern under the
c_record_layout_rulepolicy of #1452, here are size, align and offset ofc, from clangx86_64-pc-windows-msvc:struct d1 { char a; struct T; int b : 4; char c; }gives 16,4,12.struct __attribute__((packed)) d4 { char a; struct T; int b : 20; char c; }gives 10,1,9.union d5 { char a; struct T; int b : 3; }gives 4,4,0.Pre-#1745 Buster matched these. Main now gives 12,4,8 / 6,1,5 / 4,1,0, which is the
-fno-ms-extensionsanswer.Root cause
The anonymous-member decision in
c_type_parse_aggregate_segment_step(src/buster/lib/compiler/frontend/c/c_parse.c) depends only on the syntax. Whether a tagged or typedef-named aggregate is an anonymous member is a property of the dialect. Buster selects that dialect by target: Windows targets already get_MSC_VER,_MSC_EXTENSIONS,__int64and so on. Only one oracle target was checked, gcc and clang on x86-64 Linux. The fixture then inherited that target's answer on every lane.Proposed fix
_MSC_EXTENSIONS, a declarator-less member whose type is a complete struct or union (tagged, typedef-named, or a nested tagged definition) is an anonymous member. This matches clang*-pc-windows-msvc.struct Fwd;, still declares nothing. Clang rejects it; rejecting it too is optional.x86_64-unknown-linux-gnufor the GNU answer, instead oftarget_native.*-windows-gnuis currently an alias of the MSVC target, so MinGW would inherit the MS answer until that split lands. That is consistent with the rest of the MinGW aliasing tracked there.Related: #1706, #1745, #1439, #1492, PR #1452.