From fe005eb0696f5255912a6fbe0e6bbd8c168340f7 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Fri, 31 Jan 2025 21:00:52 -0500 Subject: [PATCH] Allow 'inline' on some declarations in MS compatibility mode (#125250) (#125275) Microsoft allows the 'inline' specifier on a typedef of a function type in C modes. This is used by a system header (ufxclient.h), so instead of giving a hard error, we diagnose with a warning. C++ mode and non- Microsoft compatibility modes are not impacted. Fixes https://github.com/llvm/llvm-project/issues/124869 (cherry picked from commit ef91caec2cf313624829114802cff92ae682e550) --- clang/docs/ReleaseNotes.rst | 2 ++ clang/include/clang/Basic/DiagnosticGroups.td | 4 +++- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/lib/Sema/SemaDecl.cpp | 5 ++++- clang/test/Sema/MicrosoftCompatibility.c | 16 ++++++++++++++-- clang/test/Sema/MicrosoftCompatibility.cpp | 7 +++++++ 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3530d1c0e4c19..88c9fc8f95e4a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -397,6 +397,8 @@ Resolutions to C++ Defect Reports C Language Changes ------------------ +- Clang now allows an ``inline`` specifier on a typedef declaration of a + function type in Microsoft compatibility mode. #GH124869 - Extend clang's ```` to define ``LONG_LONG_*`` macros for Android's bionic. - Macro ``__STDC_NO_THREADS__`` is no longer necessary for MSVC 2022 1939 and later. - Exposed the the ``__nullptr`` keyword as an alias for ``nullptr`` in all C language modes. diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 209792f851b6a..af57a42b1ec5a 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1306,6 +1306,8 @@ def MicrosoftStaticAssert : DiagGroup<"microsoft-static-assert">; def MicrosoftInitFromPredefined : DiagGroup<"microsoft-init-from-predefined">; def MicrosoftStringLiteralFromPredefined : DiagGroup< "microsoft-string-literal-from-predefined">; +def MicrosoftInlineOnNonFunction : DiagGroup< + "microsoft-inline-on-non-function">; // Aliases. def : DiagGroup<"msvc-include", [MicrosoftInclude]>; @@ -1324,7 +1326,7 @@ def Microsoft : DiagGroup<"microsoft", MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag, MicrosoftCommentPaste, MicrosoftEndOfFile, MicrosoftStaticAssert, MicrosoftInitFromPredefined, MicrosoftStringLiteralFromPredefined, - MicrosoftInconsistentDllImport]>; + MicrosoftInconsistentDllImport, MicrosoftInlineOnNonFunction]>; def ClangClPch : DiagGroup<"clang-cl-pch">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index db911ed121e95..ec2a140e04d5b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -482,6 +482,8 @@ def ext_use_out_of_scope_declaration : ExtWarn< InGroup>; def err_inline_non_function : Error< "'inline' can only appear on functions%select{| and non-local variables}0">; +def warn_ms_inline_non_function : ExtWarn, + InGroup; def err_noreturn_non_function : Error< "'_Noreturn' can only appear on functions">; def warn_qual_return_type : Warning< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3cad9827fdab6..1ecb9aff5f319 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6681,7 +6681,10 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (D.getDeclSpec().isInlineSpecified()) - Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) + Diag(D.getDeclSpec().getInlineSpecLoc(), + (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus) + ? diag::warn_ms_inline_non_function + : diag::err_inline_non_function) << getLangOpts().CPlusPlus17; if (D.getDeclSpec().hasConstexprSpecifier()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) diff --git a/clang/test/Sema/MicrosoftCompatibility.c b/clang/test/Sema/MicrosoftCompatibility.c index 9a1f050747f9d..8d402d53e004d 100644 --- a/clang/test/Sema/MicrosoftCompatibility.c +++ b/clang/test/Sema/MicrosoftCompatibility.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-compatibility -DMSVCCOMPAT -triple i686-pc-win32 -// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions -triple i686-pc-win32 +// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify=expected,compat -fms-compatibility -DMSVCCOMPAT -triple i686-pc-win32 +// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify=expected,ext -fms-extensions -triple i686-pc-win32 #ifdef MSVCCOMPAT enum ENUM1; // expected-warning {{forward references to 'enum' types are a Microsoft extension}} @@ -35,3 +35,15 @@ size_t x; #else size_t x; // expected-error {{unknown type name 'size_t'}} #endif + +/* Microsoft allows inline, __inline, and __forceinline to appear on a typedef + of a function type; this is used in their system headers such as ufxclient.h + See GitHub #124869 for more details. + */ +typedef int inline Foo1(int); // compat-warning {{'inline' can only appear on functions}} \ + ext-error {{'inline' can only appear on functions}} +typedef int __inline Foo2(int); // compat-warning {{'inline' can only appear on functions}} \ + ext-error {{'inline' can only appear on functions}} +typedef int __forceinline Foo(int); // compat-warning {{'inline' can only appear on functions}} \ + ext-error {{'inline' can only appear on functions}} \ + expected-warning {{'__forceinline' attribute only applies to functions and statements}} diff --git a/clang/test/Sema/MicrosoftCompatibility.cpp b/clang/test/Sema/MicrosoftCompatibility.cpp index 90a45dfaaf176..391977e2765c5 100644 --- a/clang/test/Sema/MicrosoftCompatibility.cpp +++ b/clang/test/Sema/MicrosoftCompatibility.cpp @@ -8,3 +8,10 @@ struct cls { }; char * cls::* __uptr wrong2 = &cls::m; // expected-error {{'__uptr' attribute cannot be used with pointers to members}} + +// Microsoft allows inline, __inline, and __forceinline to appear on a typedef +// of a function type, but only in C. See GitHub #124869 for more details. +typedef int inline Foo1(int); // expected-error {{'inline' can only appear on functions}} +typedef int __inline Foo2(int); // expected-error {{'inline' can only appear on functions}} +typedef int __forceinline Foo(int); // expected-error {{'inline' can only appear on functions}} \ + expected-warning {{'__forceinline' attribute only applies to functions and statements}}