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 ------------------------- 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..1b959826daade 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, Visibility<[ClangOption, CC1Option, CLOption]>, HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">, MarshallingInfoFlag>, ImpliedByAnyOf<[fms_compatibility.KeyPath]>; +def fms_anonymous_structs + : Flag<["-"], "fms-anonymous-structs">, + Visibility<[CC1Option]>, + MarshallingInfoFlag>, + ImpliedByAnyOf<[fms_extensions.KeyPath, fms_compatibility.KeyPath]>, + HelpText<"Enable Microsoft anonymous struct/union extension.">; defm asm_blocks : BoolFOption<"asm-blocks", LangOpts<"AsmBlocks">, Default, PosFlag, 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(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/Frontend/ms-anon-structs-args.c b/clang/test/Frontend/ms-anon-structs-args.c new file mode 100644 index 0000000000000..e2f6edeef20c1 --- /dev/null +++ b/clang/test/Frontend/ms-anon-structs-args.c @@ -0,0 +1,20 @@ +// 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 +// 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 + +// 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 new file mode 100644 index 0000000000000..f9b6fa20c5bd1 --- /dev/null +++ b/clang/test/Sema/MicrosoftAnonymousStructs.c @@ -0,0 +1,56 @@ +// 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 + +struct union_mem { + long g; +}; + +typedef struct nested1 { + long a; +} 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}} +}; + +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 { + int c; + struct nested2; // ms-anonymous-warning {{anonymous structs 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.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'}} +}