https://github.com/riyaz86a updated 
https://github.com/llvm/llvm-project/pull/176551

>From d1f68b116134570b1c826f9532a2a7ddf1e9b348 Mon Sep 17 00:00:00 2001
From: Riyaz Ahmad <[email protected]>
Date: Sat, 17 Jan 2026 04:16:28 -0500
Subject: [PATCH] [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        |  5 ++
 clang/lib/Driver/ToolChains/Clang.cpp         |  4 +-
 clang/lib/Sema/SemaDecl.cpp                   |  3 +-
 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       | 24 ++++++
 9 files changed, 136 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..f6d128a4dd916 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -3327,6 +3327,11 @@ 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]>,
+      HelpText<"Enable Microsoft anonymous struct/union extension.">,
+      MarshallingInfoFlag<LangOpts<"MSAnonymousStructs">>;
 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..c2359c6c549d0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5342,7 +5342,8 @@ 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().MicrosoftExt) ||
+          (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..a9d5b57d3bc3f 100644
--- a/clang/unittests/Frontend/CompilerInvocationTest.cpp
+++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp
@@ -190,6 +190,30 @@ 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);
+
+  Invocation.generateCC1CommandLine(GeneratedArgs, *this);
+
+  ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fms-anonymous-structs")));
+}
+
 TEST_F(CommandLineTest, CC1FlagPresentWhenDoingRoundTrip) {
   const char *Args[] = {"-cc1", "-round-trip-args"};
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to