https://github.com/riyaz86a updated https://github.com/llvm/llvm-project/pull/176551
>From 9c01511289217c605e37ca08ee4ccc554d8a9270 Mon Sep 17 00:00:00 2001 From: Riyaz Ahmad <[email protected]> Date: Sat, 17 Jan 2026 04:16:28 -0500 Subject: [PATCH 1/6] [Frontend][Sema] Add CC1-only -fms-anonymous-structs to enable Microsoft anonymous struct/union feature Add a CC1-only option `-fms-anonymous-structs` to enable Microsoft anonymous struct/union feature without enabling full Microsoft extensions. Motivation: - On AIX, some Microsoft extensions (e.g _ptr32) conflict with system headers. - Certain code bases rely on Microsoft anonymous structs/unions behavior. This new option allows selectively enabling the anonymous struct/union features in the front-end without triggering other Microsoft extensions features. CC1 option can be passed via clang "-Xclang -fms-anonymous-structs". Implementation: - Introduced CC1-only option `-fms-anonymous-structs`. - The option updates LangOpts::MSAnonymousStructs and Updated Sema to use this flag. - Added frontend, driver, and Sema tests. --- clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Options/Options.td | 6 ++ clang/lib/Driver/ToolChains/Clang.cpp | 4 +- clang/lib/Sema/SemaDecl.cpp | 2 +- clang/test/Driver/cl-options.c | 3 + clang/test/Driver/unknown-arg.c | 2 + clang/test/Frontend/ms-anon-structs-args.c | 15 ++++ clang/test/Sema/MicrosoftAnonymousStructs.c | 81 +++++++++++++++++++ .../Frontend/CompilerInvocationTest.cpp | 20 +++++ 9 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 clang/test/Frontend/ms-anon-structs-args.c create mode 100644 clang/test/Sema/MicrosoftAnonymousStructs.c diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 36fec24638363..4420cd942cac0 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -47,6 +47,7 @@ LANGOPT(MSVCCompat , 1, 0, NotCompatible, "Microsoft Visual C++ full comp LANGOPT(Kernel , 1, 0, NotCompatible, "Kernel mode") LANGOPT(MicrosoftExt , 1, 0, NotCompatible, "Microsoft C++ extensions") LANGOPT(ZOSExt , 1, 0, NotCompatible, "z/OS extensions") +LANGOPT(MSAnonymousStructs, 1, 0, NotCompatible, "Microsoft anonymous struct and union extension") LANGOPT(AsmBlocks , 1, 0, NotCompatible, "Microsoft inline asm blocks") LANGOPT(Borland , 1, 0, NotCompatible, "Borland extensions") LANGOPT(CPlusPlus , 1, 0, NotCompatible, "C++") diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 188739e72434a..5cdca7132e779 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3327,6 +3327,12 @@ def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">, MarshallingInfoFlag<LangOpts<"MicrosoftExt">>, ImpliedByAnyOf<[fms_compatibility.KeyPath]>; +def fms_anonymous_structs + : Flag<["-"], "fms-anonymous-structs">, + Visibility<[CC1Option]>, + MarshallingInfoFlag<LangOpts<"MSAnonymousStructs">>, + ImpliedByAnyOf<[fms_extensions.KeyPath]>, + HelpText<"Enable Microsoft anonymous struct/union extension.">; defm asm_blocks : BoolFOption<"asm-blocks", LangOpts<"AsmBlocks">, Default<fms_extensions.KeyPath>, PosFlag<SetTrue, [], [ClangOption, CC1Option]>, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 41ee88fd5501a..b0fd41e0a026e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7156,8 +7156,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, - IsWindowsMSVC || IsUEFI)) + IsWindowsMSVC || IsUEFI)) { CmdArgs.push_back("-fms-extensions"); + CmdArgs.push_back("-fms-anonymous-structs"); + } // -fms-compatibility=0 is default. bool IsMSVCCompat = Args.hasFlag( diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ae779d6830d9b..4f030c6ec649f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5342,7 +5342,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DS.getTypeSpecType() == DeclSpec::TST_typename) { RecordDecl *Record = Tag ? dyn_cast<RecordDecl>(Tag) : DS.getRepAsType().get()->getAsRecordDecl(); - if (Record && getLangOpts().MicrosoftExt) { + if (Record && getLangOpts().MSAnonymousStructs) { Diag(DS.getBeginLoc(), diag::ext_ms_anonymous_record) << Record->isUnion() << DS.getSourceRange(); return BuildMicrosoftCAnonymousStruct(S, DS, Record); diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 611d0d2927c43..f4ee39d3fc7d9 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -350,6 +350,9 @@ // WJoined: "-cc1" // WJoined: "-Wunused-pragmas" +// RUN: %clang_cl -c -fms-extensions -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-MS-ANON-STRUCT %s +// CHECK-MS-ANON-STRUCT: "-fms-extensions" "-fms-anonymous-structs" + // We recognize -f[no-]strict-aliasing. // RUN: %clang_cl -c -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTSTRICT %s // DEFAULTSTRICT: "-relaxed-aliasing" diff --git a/clang/test/Driver/unknown-arg.c b/clang/test/Driver/unknown-arg.c index 26032a407f413..b209b1bff0c9f 100644 --- a/clang/test/Driver/unknown-arg.c +++ b/clang/test/Driver/unknown-arg.c @@ -25,6 +25,7 @@ // This needs to exit non-0, for configure scripts. // RUN: not %clang /GR- +// RUN: not %clang %s -fms-anonymous-structs -### 2>&1 | FileCheck %s --check-prefix=CL-MS-ERROR // CHECK: error: unknown argument: '-cake-is-lie' // CHECK: error: unknown argument: '-%0' @@ -70,3 +71,4 @@ // O-WARN: warning: joined argument treated as '-o ffload-arch=sm_70'; did you mean '--offload-arch=sm_70'? // O-WARN-NEXT: warning: joined argument treated as '-o ffload-device-only'; did you mean '--offload-device-only'? // O-WARN-NEXT: warning: joined argument treated as '-o utput'; did you mean '--output'? +// CL-MS-ERROR: error: unknown argument '-fms-anonymous-structs'; did you mean '-Xclang -fms-anonymous-structs'? diff --git a/clang/test/Frontend/ms-anon-structs-args.c b/clang/test/Frontend/ms-anon-structs-args.c new file mode 100644 index 0000000000000..ddd3cea598959 --- /dev/null +++ b/clang/test/Frontend/ms-anon-structs-args.c @@ -0,0 +1,15 @@ +// Test that -fms-anonymous-structs is a CC1-only option and properly rejected by driver + +// RUN: %clang_cc1 -triple powerpc-ibm-aix -fms-anonymous-structs %s -fsyntax-only 2>&1 | \ +// RUN: FileCheck --check-prefix=CC1-OK %s --allow-empty +// CC1-OK-NOT: error: unknown argument + +// Test that multiple occurrences are handled +// RUN: %clang_cc1 -triple powerpc-ibm-aix -fms-anonymous-structs -fms-anonymous-structs %s -fsyntax-only 2>&1 | \ +// RUN: FileCheck --check-prefix=MULTI-OK %s --allow-empty +// MULTI-OK-NOT: error: unknown argument + +// Test with other MS-related options +// RUN: %clang_cc1 -triple powerpc-ibm-aix -fms-extensions -fms-anonymous-structs %s -fsyntax-only 2>&1 | \ +// RUN: FileCheck --check-prefix=WITH-MS-EXT %s --allow-empty +// WITH-MS-EXT-NOT: error: unknown argument diff --git a/clang/test/Sema/MicrosoftAnonymousStructs.c b/clang/test/Sema/MicrosoftAnonymousStructs.c new file mode 100644 index 0000000000000..163c2f726cb67 --- /dev/null +++ b/clang/test/Sema/MicrosoftAnonymousStructs.c @@ -0,0 +1,81 @@ +// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-anonymous-structs +// RUN: %clang_cc1 -triple powerpc-ibm-aix %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-anonymous-structs + +typedef struct notnested { + long bad1; + long bad2; +} NOTNESTED; + + +typedef struct nested1 { + long a; + struct notnested var1; + NOTNESTED var2; +} NESTED1; + +struct nested2 { + long b; + NESTED1; // expected-warning {{anonymous structs are a Microsoft extension}} +}; + +struct nested2 PR20573 = { .a = 3 }; + +struct nested3 { + long d; + struct nested4 { // expected-warning {{anonymous structs are a Microsoft extension}} + long e; + }; + union nested5 { // expected-warning {{anonymous unions are a Microsoft extension}} + long f; + }; +}; + +typedef union nested6 { + long f; +} NESTED6; + +struct test { + int c; + struct nested2; // expected-warning {{anonymous structs are a Microsoft extension}} + NESTED6; // expected-warning {{anonymous unions are a Microsoft extension}} +}; + +void foo(void) +{ + struct test var; + var.a; + var.b; + var.c; + var.bad1; // expected-error {{no member named 'bad1' in 'struct test'}} + var.bad2; // expected-error {{no member named 'bad2' in 'struct test'}} +} + +// Enumeration types with a fixed underlying type. +const int seventeen = 17; +typedef int Int; + +void pointer_to_integral_type_conv(char* ptr) { + char ch = (char)ptr; + short sh = (short)ptr; + ch = (char)ptr; + sh = (short)ptr; + + // This is valid ISO C. + _Bool b = (_Bool)ptr; +} + +typedef struct { + UNKNOWN u; // expected-error {{unknown type name 'UNKNOWN'}} +} AA; + +typedef struct { + AA; // expected-warning {{anonymous structs are a Microsoft extension}} +} BB; + +struct anon_fault { + struct undefined; // expected-warning {{anonymous structs are a Microsoft extension}} + // expected-error@-1 {{field has incomplete type 'struct undefined'}} + // expected-note@-2 {{forward declaration of 'struct undefined'}} +}; + +const int anon_falt_size = sizeof(struct anon_fault); diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp index 64d0f4c38f11c..cf758c4ae2c50 100644 --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -190,6 +190,26 @@ TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) { ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file"))); } +TEST_F(CommandLineTest, MSAnonymousStructsFlagPresent) { + const char *Args[] = {"-cc1", "-fms-anonymous-structs"}; + + ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); + + EXPECT_TRUE(Invocation.getLangOpts().MSAnonymousStructs); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + + ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fms-anonymous-structs"))); +} + +TEST_F(CommandLineTest, MSAnonymousStructsEnabledByMSExtensions) { + const char *Args[] = {"clang", "-fms-extensions"}; + + ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); + + EXPECT_TRUE(Invocation.getLangOpts().MSAnonymousStructs); +} + TEST_F(CommandLineTest, CC1FlagPresentWhenDoingRoundTrip) { const char *Args[] = {"-cc1", "-round-trip-args"}; >From d503955da34dc705678fc1cae8c4a8400c990c6a Mon Sep 17 00:00:00 2001 From: Riyaz Ahmad <[email protected]> Date: Wed, 21 Jan 2026 12:17:55 -0500 Subject: [PATCH 2/6] [Frontend][Sema] Address review comments --- clang/lib/Driver/ToolChains/Clang.cpp | 1 - clang/test/Driver/unknown-arg.c | 2 -- clang/test/Sema/MicrosoftAnonymousStructs.c | 1 + .../Frontend/CompilerInvocationTest.cpp | 20 ------------------- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index b0fd41e0a026e..de4dc62497433 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7158,7 +7158,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC || IsUEFI)) { CmdArgs.push_back("-fms-extensions"); - CmdArgs.push_back("-fms-anonymous-structs"); } // -fms-compatibility=0 is default. diff --git a/clang/test/Driver/unknown-arg.c b/clang/test/Driver/unknown-arg.c index b209b1bff0c9f..26032a407f413 100644 --- a/clang/test/Driver/unknown-arg.c +++ b/clang/test/Driver/unknown-arg.c @@ -25,7 +25,6 @@ // This needs to exit non-0, for configure scripts. // RUN: not %clang /GR- -// RUN: not %clang %s -fms-anonymous-structs -### 2>&1 | FileCheck %s --check-prefix=CL-MS-ERROR // CHECK: error: unknown argument: '-cake-is-lie' // CHECK: error: unknown argument: '-%0' @@ -71,4 +70,3 @@ // O-WARN: warning: joined argument treated as '-o ffload-arch=sm_70'; did you mean '--offload-arch=sm_70'? // O-WARN-NEXT: warning: joined argument treated as '-o ffload-device-only'; did you mean '--offload-device-only'? // O-WARN-NEXT: warning: joined argument treated as '-o utput'; did you mean '--output'? -// CL-MS-ERROR: error: unknown argument '-fms-anonymous-structs'; did you mean '-Xclang -fms-anonymous-structs'? diff --git a/clang/test/Sema/MicrosoftAnonymousStructs.c b/clang/test/Sema/MicrosoftAnonymousStructs.c index 163c2f726cb67..3f81962515d4d 100644 --- a/clang/test/Sema/MicrosoftAnonymousStructs.c +++ b/clang/test/Sema/MicrosoftAnonymousStructs.c @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-anonymous-structs // RUN: %clang_cc1 -triple powerpc-ibm-aix %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-anonymous-structs +// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-extensions typedef struct notnested { long bad1; diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp index cf758c4ae2c50..64d0f4c38f11c 100644 --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -190,26 +190,6 @@ TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) { ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file"))); } -TEST_F(CommandLineTest, MSAnonymousStructsFlagPresent) { - const char *Args[] = {"-cc1", "-fms-anonymous-structs"}; - - ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); - - EXPECT_TRUE(Invocation.getLangOpts().MSAnonymousStructs); - - Invocation.generateCC1CommandLine(GeneratedArgs, *this); - - ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fms-anonymous-structs"))); -} - -TEST_F(CommandLineTest, MSAnonymousStructsEnabledByMSExtensions) { - const char *Args[] = {"clang", "-fms-extensions"}; - - ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); - - EXPECT_TRUE(Invocation.getLangOpts().MSAnonymousStructs); -} - TEST_F(CommandLineTest, CC1FlagPresentWhenDoingRoundTrip) { const char *Args[] = {"-cc1", "-round-trip-args"}; >From 4ea10266307d37d7782b336db3c043ec8b5ff175 Mon Sep 17 00:00:00 2001 From: Riyaz Ahmad <[email protected]> Date: Wed, 21 Jan 2026 14:15:13 -0500 Subject: [PATCH 3/6] [Frontend][Sema] Address review comments. --- clang/include/clang/Options/Options.td | 2 +- clang/lib/Driver/ToolChains/Clang.cpp | 3 +- clang/test/Driver/cl-options.c | 3 -- clang/test/Frontend/ms-anon-structs-args.c | 7 ++- clang/test/Sema/MicrosoftAnonymousStructs.c | 53 ++++++++++++++------- 5 files changed, 43 insertions(+), 25 deletions(-) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 5cdca7132e779..1b959826daade 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3331,7 +3331,7 @@ def fms_anonymous_structs : Flag<["-"], "fms-anonymous-structs">, Visibility<[CC1Option]>, MarshallingInfoFlag<LangOpts<"MSAnonymousStructs">>, - ImpliedByAnyOf<[fms_extensions.KeyPath]>, + ImpliedByAnyOf<[fms_extensions.KeyPath, fms_compatibility.KeyPath]>, HelpText<"Enable Microsoft anonymous struct/union extension.">; defm asm_blocks : BoolFOption<"asm-blocks", LangOpts<"AsmBlocks">, Default<fms_extensions.KeyPath>, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index de4dc62497433..41ee88fd5501a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7156,9 +7156,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, - IsWindowsMSVC || IsUEFI)) { + IsWindowsMSVC || IsUEFI)) CmdArgs.push_back("-fms-extensions"); - } // -fms-compatibility=0 is default. bool IsMSVCCompat = Args.hasFlag( diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index f4ee39d3fc7d9..611d0d2927c43 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -350,9 +350,6 @@ // WJoined: "-cc1" // WJoined: "-Wunused-pragmas" -// RUN: %clang_cl -c -fms-extensions -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-MS-ANON-STRUCT %s -// CHECK-MS-ANON-STRUCT: "-fms-extensions" "-fms-anonymous-structs" - // We recognize -f[no-]strict-aliasing. // RUN: %clang_cl -c -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTSTRICT %s // DEFAULTSTRICT: "-relaxed-aliasing" diff --git a/clang/test/Frontend/ms-anon-structs-args.c b/clang/test/Frontend/ms-anon-structs-args.c index ddd3cea598959..e2f6edeef20c1 100644 --- a/clang/test/Frontend/ms-anon-structs-args.c +++ b/clang/test/Frontend/ms-anon-structs-args.c @@ -1,4 +1,4 @@ -// Test that -fms-anonymous-structs is a CC1-only option and properly rejected by driver +// Test that -fms-anonymous-structs is a CC1-only option and is accepted by CC1 without error. // RUN: %clang_cc1 -triple powerpc-ibm-aix -fms-anonymous-structs %s -fsyntax-only 2>&1 | \ // RUN: FileCheck --check-prefix=CC1-OK %s --allow-empty @@ -13,3 +13,8 @@ // RUN: %clang_cc1 -triple powerpc-ibm-aix -fms-extensions -fms-anonymous-structs %s -fsyntax-only 2>&1 | \ // RUN: FileCheck --check-prefix=WITH-MS-EXT %s --allow-empty // WITH-MS-EXT-NOT: error: unknown argument + +// Test rejection of the unsupported negative form. +// RUN: not %clang_cc1 -triple powerpc-ibm-aix -fno-ms-anonymous-structs %s -fsyntax-only 2>&1 | \ +// RUN: FileCheck %s +// CHECK: error: unknown argument: '-fno-ms-anonymous-structs' diff --git a/clang/test/Sema/MicrosoftAnonymousStructs.c b/clang/test/Sema/MicrosoftAnonymousStructs.c index 3f81962515d4d..cf47322f59df7 100644 --- a/clang/test/Sema/MicrosoftAnonymousStructs.c +++ b/clang/test/Sema/MicrosoftAnonymousStructs.c @@ -1,6 +1,13 @@ -// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-anonymous-structs -// RUN: %clang_cc1 -triple powerpc-ibm-aix %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-anonymous-structs -// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value -Wno-pointer-to-int-cast -Wmicrosoft -verify -fms-extensions +// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value \ +// RUN: -Wno-pointer-to-int-cast -Wmicrosoft -verify=ms-anonymous -fms-anonymous-structs +// RUN: %clang_cc1 -triple powerpc-ibm-aix %s -fsyntax-only -Wno-unused-value \ +// RUN: -Wno-pointer-to-int-cast -Wmicrosoft -verify=ms-anonymous -fms-anonymous-structs +// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value \ +// RUN: -Wno-pointer-to-int-cast -Wmicrosoft -verify=ms-anonymous -fms-extensions +// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value \ +// RUN: -Wno-pointer-to-int-cast -Wmicrosoft -verify=ms-anonymous -fms-compatibility +// RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value \ +// RUN: -Wno-pointer-to-int-cast -Wmicrosoft -verify=ms-anonymous-dis typedef struct notnested { long bad1; @@ -16,17 +23,20 @@ typedef struct nested1 { struct nested2 { long b; - NESTED1; // expected-warning {{anonymous structs are a Microsoft extension}} + NESTED1; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} }; -struct nested2 PR20573 = { .a = 3 }; +struct nested2 PR20573 = { .a = 3 }; // ms-anonymous-dis-error {{field designator 'a' does not refer to any field in type 'struct nested2'}} struct nested3 { long d; - struct nested4 { // expected-warning {{anonymous structs are a Microsoft extension}} + struct nested4 { // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} long e; }; - union nested5 { // expected-warning {{anonymous unions are a Microsoft extension}} + union nested5 { // ms-anonymous-warning {{anonymous unions are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} long f; }; }; @@ -37,18 +47,22 @@ typedef union nested6 { struct test { int c; - struct nested2; // expected-warning {{anonymous structs are a Microsoft extension}} - NESTED6; // expected-warning {{anonymous unions are a Microsoft extension}} + struct nested2; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} + NESTED6; // ms-anonymous-warning {{anonymous unions are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} }; void foo(void) { struct test var; - var.a; - var.b; + var.a; // ms-anonymous-dis-error {{no member named 'a' in 'struct test'}} + var.b; // ms-anonymous-dis-error {{no member named 'b' in 'struct test'}} var.c; - var.bad1; // expected-error {{no member named 'bad1' in 'struct test'}} - var.bad2; // expected-error {{no member named 'bad2' in 'struct test'}} + var.bad1; // ms-anonymous-error {{no member named 'bad1' in 'struct test'}} + // ms-anonymous-dis-error@-1 {{no member named 'bad1' in 'struct test'}} + var.bad2; // ms-anonymous-error {{no member named 'bad2' in 'struct test'}} + // ms-anonymous-dis-error@-1 {{no member named 'bad2' in 'struct test'}} } // Enumeration types with a fixed underlying type. @@ -66,17 +80,20 @@ void pointer_to_integral_type_conv(char* ptr) { } typedef struct { - UNKNOWN u; // expected-error {{unknown type name 'UNKNOWN'}} + UNKNOWN u; // ms-anonymous-error {{unknown type name 'UNKNOWN'}} + // ms-anonymous-dis-error@-1 {{unknown type name 'UNKNOWN'}} } AA; typedef struct { - AA; // expected-warning {{anonymous structs are a Microsoft extension}} + AA; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} } BB; struct anon_fault { - struct undefined; // expected-warning {{anonymous structs are a Microsoft extension}} - // expected-error@-1 {{field has incomplete type 'struct undefined'}} - // expected-note@-2 {{forward declaration of 'struct undefined'}} + struct undefined; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + // ms-anonymous-error@-1 {{field has incomplete type 'struct undefined'}} + // ms-anonymous-note@-2 {{forward declaration of 'struct undefined'}} + // ms-anonymous-dis-warning@-3 {{declaration does not declare anything}} }; const int anon_falt_size = sizeof(struct anon_fault); >From e3fb3bd01360b5ab3ba4babdc9295256f34b3918 Mon Sep 17 00:00:00 2001 From: Riyaz Ahmad <[email protected]> Date: Thu, 22 Jan 2026 02:43:18 -0500 Subject: [PATCH 4/6] [Frontend][Sema] Address review comments. --- clang/test/Sema/MicrosoftAnonymousStructs.c | 76 ++++----------------- 1 file changed, 15 insertions(+), 61 deletions(-) diff --git a/clang/test/Sema/MicrosoftAnonymousStructs.c b/clang/test/Sema/MicrosoftAnonymousStructs.c index cf47322f59df7..d0b32ce53a3ff 100644 --- a/clang/test/Sema/MicrosoftAnonymousStructs.c +++ b/clang/test/Sema/MicrosoftAnonymousStructs.c @@ -11,89 +11,43 @@ typedef struct notnested { long bad1; - long bad2; } NOTNESTED; - typedef struct nested1 { long a; - struct notnested var1; NOTNESTED var2; } NESTED1; struct nested2 { long b; - NESTED1; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} - // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} -}; - -struct nested2 PR20573 = { .a = 3 }; // ms-anonymous-dis-error {{field designator 'a' does not refer to any field in type 'struct nested2'}} - -struct nested3 { - long d; - struct nested4 { // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + NESTED1; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} - long e; - }; - union nested5 { // ms-anonymous-warning {{anonymous unions are a Microsoft extension}} - // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} - long f; - }; }; -typedef union nested6 { +typedef union nested3 { long f; -} NESTED6; +} NESTED3; struct test { int c; struct nested2; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} - NESTED6; // ms-anonymous-warning {{anonymous unions are a Microsoft extension}} - // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} + NESTED3; // ms-anonymous-warning {{anonymous unions are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} +}; + +struct nested4 { + long d; + struct nested5 { // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} + long e; + }; }; void foo(void) { struct test var; - var.a; // ms-anonymous-dis-error {{no member named 'a' in 'struct test'}} - var.b; // ms-anonymous-dis-error {{no member named 'b' in 'struct test'}} var.c; - var.bad1; // ms-anonymous-error {{no member named 'bad1' in 'struct test'}} - // ms-anonymous-dis-error@-1 {{no member named 'bad1' in 'struct test'}} - var.bad2; // ms-anonymous-error {{no member named 'bad2' in 'struct test'}} - // ms-anonymous-dis-error@-1 {{no member named 'bad2' in 'struct test'}} -} - -// Enumeration types with a fixed underlying type. -const int seventeen = 17; -typedef int Int; - -void pointer_to_integral_type_conv(char* ptr) { - char ch = (char)ptr; - short sh = (short)ptr; - ch = (char)ptr; - sh = (short)ptr; - - // This is valid ISO C. - _Bool b = (_Bool)ptr; + var.b; // ms-anonymous-dis-error {{no member named 'b' in 'struct test'}} + var.f; // ms-anonymous-dis-error {{no member named 'f' in 'struct test'}} } - -typedef struct { - UNKNOWN u; // ms-anonymous-error {{unknown type name 'UNKNOWN'}} - // ms-anonymous-dis-error@-1 {{unknown type name 'UNKNOWN'}} -} AA; - -typedef struct { - AA; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} - // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} -} BB; - -struct anon_fault { - struct undefined; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} - // ms-anonymous-error@-1 {{field has incomplete type 'struct undefined'}} - // ms-anonymous-note@-2 {{forward declaration of 'struct undefined'}} - // ms-anonymous-dis-warning@-3 {{declaration does not declare anything}} -}; - -const int anon_falt_size = sizeof(struct anon_fault); >From 368d435724608fee9655faa660c803111b2054f9 Mon Sep 17 00:00:00 2001 From: Riyaz Ahmad <[email protected]> Date: Fri, 23 Jan 2026 01:03:05 -0500 Subject: [PATCH 5/6] [Frontend][Sema] Address review comments. --- clang/test/Sema/MicrosoftAnonymousStructs.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/clang/test/Sema/MicrosoftAnonymousStructs.c b/clang/test/Sema/MicrosoftAnonymousStructs.c index d0b32ce53a3ff..f9b6fa20c5bd1 100644 --- a/clang/test/Sema/MicrosoftAnonymousStructs.c +++ b/clang/test/Sema/MicrosoftAnonymousStructs.c @@ -9,13 +9,12 @@ // RUN: %clang_cc1 -triple i686-windows %s -fsyntax-only -Wno-unused-value \ // RUN: -Wno-pointer-to-int-cast -Wmicrosoft -verify=ms-anonymous-dis -typedef struct notnested { - long bad1; -} NOTNESTED; +struct union_mem { + long g; +}; typedef struct nested1 { long a; - NOTNESTED var2; } NESTED1; struct nested2 { @@ -26,6 +25,8 @@ struct nested2 { typedef union nested3 { long f; + struct union_mem; // ms-anonymous-warning {{anonymous structs are a Microsoft extension}} + // ms-anonymous-dis-warning@-1 {{declaration does not declare anything}} } NESTED3; struct test { @@ -48,6 +49,8 @@ void foo(void) { struct test var; var.c; + var.a; // ms-anonymous-dis-error {{no member named 'a' in 'struct test'}} var.b; // ms-anonymous-dis-error {{no member named 'b' in 'struct test'}} var.f; // ms-anonymous-dis-error {{no member named 'f' in 'struct test'}} + var.g; // ms-anonymous-dis-error {{no member named 'g' in 'struct test'}} } >From 6bda77381fa52674a13dee70e6640818119112d8 Mon Sep 17 00:00:00 2001 From: Riyaz Ahmad <[email protected]> Date: Fri, 23 Jan 2026 11:12:55 -0500 Subject: [PATCH 6/6] [Clang] Add release notes for -fms-anonymous-structs CC1 option --- clang/docs/ReleaseNotes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5fd607d98faa3..b8b2b83b58981 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -109,6 +109,7 @@ Non-comprehensive list of changes in this release New Compiler Flags ------------------ +- New CC1 option ``-fms-anonymous-structs`` added to enable only Microsoft's anonymous struct/union extension without enabling other ``-fms-extensions`` features [GH177607]. Deprecated Compiler Flags ------------------------- _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
