diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 6bb99c757cd19..37dbcdd59f0aa 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2406,6 +2406,16 @@ those modes. Use ``__has_feature(c_fixed_enum)`` to determine whether support for fixed underlying types is available in C23 and later. +Enumerations with no enumerators +----------------------------------------- + +Clang provides support for Microsoft extensions to support empty enums. + +.. code-block:: c++ + + typedef enum empty { } A; + + Interoperability with C++11 lambdas ----------------------------------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index fe77f917bb801..2b206c9e89c31 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -429,6 +429,7 @@ Bug Fixes in This Version - Fixed a failed assertion with empty filename arguments in ``__has_embed``. (#GH159898) - Fixed a failed assertion with empty filename in ``#embed`` directive. (#GH162951) - Fixed a crash triggered by unterminated ``__has_embed``. (#GH162953) +- Accept empty enumerations in MSVC-compatible C mode. (#GH114402) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 8aa3489a2a62b..1e0321de3f4b6 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1436,6 +1436,7 @@ def MicrosoftDrectveSection : DiagGroup<"microsoft-drectve-section">; def MicrosoftInclude : DiagGroup<"microsoft-include">; def MicrosoftCppMacro : DiagGroup<"microsoft-cpp-macro">; def MicrosoftFixedEnum : DiagGroup<"microsoft-fixed-enum">; +def MicrosoftEmptyEnum : DiagGroup<"microsoft-empty-enum">; def MicrosoftSealed : DiagGroup<"microsoft-sealed">; def MicrosoftAbstract : DiagGroup<"microsoft-abstract">; def MicrosoftUnqualifiedFriend : DiagGroup<"microsoft-unqualified-friend">; @@ -1489,7 +1490,8 @@ def Microsoft : DiagGroup<"microsoft", MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag, MicrosoftCommentPaste, MicrosoftEndOfFile, MicrosoftInitFromPredefined, MicrosoftStringLiteralFromPredefined, - MicrosoftInconsistentDllImport, MicrosoftInlineOnNonFunction]>; + MicrosoftInconsistentDllImport, MicrosoftInlineOnNonFunction, + MicrosoftEmptyEnum]>; def ClangClPch : DiagGroup<"clang-cl-pch">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e5e071f43fa75..aa0ccb0c05101 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -116,6 +116,9 @@ def err_enumerator_unnamed_no_def : Error< def ext_ms_c_enum_fixed_underlying_type : Extension< "enumeration types with a fixed underlying type are a Microsoft extension">, InGroup; +def ext_ms_c_empty_enum_type : Extension< + "empty enumeration types are a Microsoft extension">, + InGroup; def ext_c23_enum_fixed_underlying_type : Extension< "enumeration types with a fixed underlying type are a C23 extension">, InGroup; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e4b158e4a6248..78915192f4b0b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5363,8 +5363,13 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl, T.consumeOpen(); // C does not allow an empty enumerator-list, C++ does [dcl.enum]. - if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) - Diag(Tok, diag::err_empty_enum); + if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) { + if (getLangOpts().MicrosoftExt) + Diag(T.getOpenLocation(), diag::ext_ms_c_empty_enum_type) + << SourceRange(T.getOpenLocation(), Tok.getLocation()); + else + Diag(Tok, diag::err_empty_enum); + } SmallVector EnumConstantDecls; SmallVector EnumAvailabilityDiags; diff --git a/clang/test/CodeGen/ms-empty-enum.c b/clang/test/CodeGen/ms-empty-enum.c new file mode 100644 index 0000000000000..6c1c87b756f9a --- /dev/null +++ b/clang/test/CodeGen/ms-empty-enum.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fms-extensions -triple x86_64-windows-msvc -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fms-extensions -triple i386-windows-msvc -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s + +typedef enum tag1 {} A; + +// CHECK: void @empty_enum(i32 noundef %a) +void empty_enum(A a) {} diff --git a/clang/test/Parser/ms-empty-enum.c b/clang/test/Parser/ms-empty-enum.c new file mode 100644 index 0000000000000..790547af88bab --- /dev/null +++ b/clang/test/Parser/ms-empty-enum.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions + +typedef enum tag1 { } A; // expected-warning {{empty enumeration types are a Microsoft extension}} +typedef enum tag2 { } B; // expected-warning {{empty enumeration types are a Microsoft extension}} +typedef enum : unsigned { } C; // expected-warning {{enumeration types with a fixed underlying type are a Microsoft extension}}\ + // expected-warning {{empty enumeration types are a Microsoft extension}}