Skip to content

[win][clang] Do not inject static_assert macro definition #147030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,11 @@ Bug Fixes in This Version
- Fixed an infinite recursion when checking constexpr destructors. (#GH141789)
- Fixed a crash when a malformed using declaration appears in a ``constexpr`` function. (#GH144264)
- Fixed a bug when use unicode character name in macro concatenation. (#GH145240)
- Clang doesn't erroneously inject a ``static_assert`` macro in ms-compatibility and
-std=c99 mode. This resulted in deletion of ``-W/Wno-microsoft-static-assert``
flag and diagnostic because the macro injection was used to emit this warning.
Unfortunately there is no other good way to diagnose usage of ``static_assert``
macro without inclusion of ``<assert.h>``.

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
3 changes: 1 addition & 2 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1450,7 +1450,6 @@ def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">;
def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">;
def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">;
def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">;
def MicrosoftStaticAssert : DiagGroup<"microsoft-static-assert">;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was curious whether we should leave the diagnostic group so it's not disruptive, but: https://sourcegraph.com/search?q=context:global+Wno-microsoft-static-assert&patternType=keyword&sm=0

Given there's so little use in the wild, I think it's better to just pull the group entirely so we don't keep it around as tech debt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to mention in the release note that there is no flag anymore?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well! Better to over-communicate than under.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

def MicrosoftInitFromPredefined : DiagGroup<"microsoft-init-from-predefined">;
def MicrosoftStringLiteralFromPredefined : DiagGroup<
"microsoft-string-literal-from-predefined">;
Expand All @@ -1472,7 +1471,7 @@ def Microsoft : DiagGroup<"microsoft",
MicrosoftRedeclareStatic, MicrosoftEnumForwardReference, MicrosoftGoto,
MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast,
MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag,
MicrosoftCommentPaste, MicrosoftEndOfFile, MicrosoftStaticAssert,
MicrosoftCommentPaste, MicrosoftEndOfFile,
MicrosoftInitFromPredefined, MicrosoftStringLiteralFromPredefined,
MicrosoftInconsistentDllImport, MicrosoftInlineOnNonFunction]>;

Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,6 @@ def err_bool_redeclaration : Error<
def warn_cxx98_compat_static_assert : Warning<
"'static_assert' declarations are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_ms_static_assert : ExtWarn<
"use of 'static_assert' without inclusion of <assert.h> is a Microsoft "
"extension">, InGroup<MicrosoftStaticAssert>;
def ext_cxx_static_assert_no_message : ExtWarn<
"'static_assert' with no message is a C++17 extension">, InGroup<CXX17>;
def ext_c_static_assert_no_message : ExtWarn<
Expand Down
17 changes: 0 additions & 17 deletions clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3304,23 +3304,6 @@ void Preprocessor::HandleDefineDirective(
// If the callbacks want to know, tell them about the macro definition.
if (Callbacks)
Callbacks->MacroDefined(MacroNameTok, MD);

// If we're in MS compatibility mode and the macro being defined is the
// assert macro, implicitly add a macro definition for static_assert to work
// around their broken assert.h header file in C. Only do so if there isn't
// already a static_assert macro defined.
if (!getLangOpts().CPlusPlus && getLangOpts().MSVCCompat &&
MacroNameTok.getIdentifierInfo()->isStr("assert") &&
!isMacroDefined("static_assert")) {
MacroInfo *MI = AllocateMacroInfo(SourceLocation());

Token Tok;
Tok.startToken();
Tok.setKind(tok::kw__Static_assert);
Tok.setIdentifierInfo(getIdentifierInfo("_Static_assert"));
MI->setTokens({Tok}, BP);
(void)appendDefMacroDirective(getIdentifierInfo("static_assert"), MI);
}
}

/// HandleUndefDirective - Implements \#undef.
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -937,9 +937,6 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) {
if (!getLangOpts().CPlusPlus) {
if (getLangOpts().C23)
Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName();
else
Diag(Tok, diag::ext_ms_static_assert) << FixItHint::CreateReplacement(
Tok.getLocation(), "_Static_assert");
} else
Diag(Tok, diag::warn_cxx98_compat_static_assert);
}
Expand Down
1 change: 0 additions & 1 deletion clang/test/Parser/static_assert.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ static_assert(1, ""); // c17-warning {{'static_assert' is a keyword in C23}} \
// c17-error {{expected ')'}} \
// c17-note {{to match this '('}} \
// c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \
// c17-ms-warning {{use of 'static_assert' without inclusion of <assert.h> is a Microsoft extension}}

#endif

Expand Down
12 changes: 0 additions & 12 deletions clang/test/Preprocessor/static_assert.c

This file was deleted.

28 changes: 20 additions & 8 deletions clang/test/Sema/static-assert.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -std=c11 -Wgnu-folding-constant -fsyntax-only -verify %s
// RUN: %clang_cc1 -fms-compatibility -Wgnu-folding-constant -DMS -fsyntax-only -verify=expected,ms %s
// RUN: %clang_cc1 -std=c99 -fms-compatibility -Wgnu-folding-constant -DMS -fsyntax-only -verify=expected,ms %s
// RUN: %clang_cc1 -std=c99 -pedantic -Wgnu-folding-constant -fsyntax-only -verify=expected,ext %s
// RUN: %clang_cc1 -xc++ -std=c++11 -pedantic -fsyntax-only -verify=expected,ext,cxx %s

Expand All @@ -13,15 +14,15 @@ _Static_assert(0, "0 is nonzero"); // expected-error {{static assertion failed:
// ext-warning {{'_Static_assert' is a C11 extension}}

#ifdef MS
static_assert(1, "1 is nonzero"); // ms-warning {{use of 'static_assert' without inclusion of <assert.h> is a Microsoft extension}}
static_assert(1, "1 is nonzero");
#endif

void foo(void) {
_Static_assert(1, "1 is nonzero"); // ext-warning {{'_Static_assert' is a C11 extension}}
_Static_assert(0, "0 is nonzero"); // expected-error {{static assertion failed: 0 is nonzero}} \
// ext-warning {{'_Static_assert' is a C11 extension}}
#ifdef MS
static_assert(1, "1 is nonzero"); // ms-warning {{use of 'static_assert' without}}
static_assert(1, "1 is nonzero");
#endif
}

Expand All @@ -38,7 +39,7 @@ struct A {
_Static_assert(0, "0 is nonzero"); // expected-error {{static assertion failed: 0 is nonzero}} \
// ext-warning {{'_Static_assert' is a C11 extension}}
#ifdef MS
static_assert(1, "1 is nonzero"); // ms-warning {{use of 'static_assert' without}}
static_assert(1, "1 is nonzero");
#endif
};

Expand All @@ -64,16 +65,27 @@ typedef UNION(char, short) U3; // expected-error {{static assertion failed due t
typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}} \
// ext-warning 3 {{'_Static_assert' is a C11 extension}}

// After defining the assert macro in MS-compatibility mode, we should
// no longer warn about including <assert.h> under the assumption the
// user already did that.
// MSVC accepts static_assert in all language modes without including <assert.h>
// and so do we in ms-compatibility mode. Unfortunately, there is no good way
// to diagnose that with a pedantic warning. We'd have to track inclusion of
// <assert.h> which is difficult when modules and PCH are involved. Adding
// implicit definition of the macro causes unexpected results in c99 mode.
#ifdef MS

#if __STDC_VERSION__ < 201112L
#if defined(static_assert)
static_assert(0, "0 is nonzero"); // ok because we should not define static_assert
// macro in c99.
#endif

static_assert(0, "0 is nonzero"); // ms-error {{static assertion failed: 0 is nonzero}}
#endif

#define assert(expr)
static_assert(1, "1 is nonzero"); // ok

// But we should still warn if the user did something bonkers.
#undef static_assert
static_assert(1, "1 is nonzero"); // ms-warning {{use of 'static_assert' without}}
static_assert(1, "1 is nonzero"); // yes, still ok.
#endif

_Static_assert(1 , "") // expected-error {{expected ';' after '_Static_assert'}} \
Expand Down