Author: Aaron Ballman Date: 2023-02-25T09:30:10-05:00 New Revision: 06174134e418251982d43eff9385674b7644007f
URL: https://github.com/llvm/llvm-project/commit/06174134e418251982d43eff9385674b7644007f DIFF: https://github.com/llvm/llvm-project/commit/06174134e418251982d43eff9385674b7644007f.diff LOG: [C2x] Implement support for revised spelling of keywords This implements WG14 N2934 (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2934.pdf), which adds keywords for alignas, alignof, bool, static_assert, and thread_local in C, as aliases for _Alignas, _Alignof, _Bool, _Static_assert, and _Thread_local. We already supported the keywords in C2x mode, but this completes support by adding pre-C2x compat warnings and updates the stdalign.h header in freestanding mode. Added: clang/test/C/C2x/n2934.c Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticParseKinds.td clang/lib/Headers/stdalign.h clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/ParseDeclCXX.cpp clang/lib/Parse/ParseExpr.cpp clang/www/c_status.html Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0397ba0b305eb..b4c64c4e60515 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -97,6 +97,10 @@ C2x Feature Support - Removed the ``ATOMIC_VAR_INIT`` macro in C2x and later standards modes, which implements `WG14 N2886 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2886.htm>`_ +- Implemented `WG14 N2934 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2934.pdf>`_ + which introduces the ``bool``, ``static_assert``, ``alignas``, ``alignof``, + and ``thread_local`` keywords in C2x. + Non-comprehensive list of changes in this release ------------------------------------------------- - Clang now saves the address of ABI-indirect function parameters on the stack, diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e3849c6658d16..243c69a551650 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -162,6 +162,9 @@ def ext_c99_feature : Extension< "'%0' is a C99 extension">, InGroup<C99>; def ext_c11_feature : Extension< "'%0' is a C11 extension">, InGroup<C11>; +def warn_c2x_compat_keyword : Warning< + "'%0' is incompatible with C standards before C2x">, + InGroup<CPre2xCompat>, DefaultIgnore; def err_c11_noreturn_misplaced : Error< "'_Noreturn' keyword must precede function declarator">; @@ -371,9 +374,6 @@ def warn_cxx11_compat_decltype_auto_type_specifier : Warning< def ext_auto_type : Extension< "'__auto_type' is a GNU extension">, InGroup<GNUAutoType>; -def warn_c2x_compat_typeof_type_specifier : Warning< - "'%select{typeof|typeof_unqual}0' is incompatible with C standards before " - "C2x">, InGroup<CPre2xCompat>, DefaultIgnore; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup<CXX11>; def warn_cxx98_compat_for_range : Warning< @@ -704,9 +704,6 @@ def warn_cxx98_compat_nullptr : Warning< "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; def ext_c_nullptr : Extension< "'nullptr' is a C2x extension">, InGroup<C2x>; -def warn_c17_compat_nullptr : Warning< - "'nullptr' is incompatible with C standards before C2x">, - InGroup<CPre2xCompat>, DefaultIgnore; def warn_wrong_clang_attr_namespace : Warning< "'__clang__' is a predefined macro name, not an attribute scope specifier; " @@ -1574,9 +1571,6 @@ def warn_ext_int_deprecated : Warning< def ext_bit_int : Extension< "'_BitInt' in %select{C17 and earlier|C++}0 is a Clang extension">, InGroup<DiagGroup<"bit-int-extension">>; -def warn_c17_compat_bit_int : Warning< - "'_BitInt' is incompatible with C standards before C2x">, - InGroup<CPre2xCompat>, DefaultIgnore; } // end of Parse Issue category. let CategoryName = "Modules Issue" in { diff --git a/clang/lib/Headers/stdalign.h b/clang/lib/Headers/stdalign.h index 6ad25db4539a1..8ae6e658dd0a2 100644 --- a/clang/lib/Headers/stdalign.h +++ b/clang/lib/Headers/stdalign.h @@ -10,6 +10,10 @@ #ifndef __STDALIGN_H #define __STDALIGN_H +/* FIXME: This is using the placeholder dates Clang produces for these macros + in C2x mode; switch to the correct values once they've been published. */ +#if defined(__cplusplus) || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ < 202000L) #ifndef __cplusplus #define alignas _Alignas #define alignof _Alignof @@ -17,5 +21,6 @@ #define __alignas_is_defined 1 #define __alignof_is_defined 1 +#endif /* __STDC_VERSION__ */ #endif /* __STDALIGN_H */ diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index d654cdff847be..3106571728692 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3934,6 +3934,8 @@ void Parser::ParseDeclarationSpecifiers( isStorageClass = true; break; case tok::kw_thread_local: + if (getLangOpts().C2x) + Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc, PrevSpec, DiagID); isStorageClass = true; @@ -4169,6 +4171,9 @@ void Parser::ParseDeclarationSpecifiers( DiagID, Policy); break; case tok::kw_bool: + if (getLangOpts().C2x) + Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); + [[fallthrough]]; case tok::kw__Bool: if (Tok.is(tok::kw__Bool) && !getLangOpts().C99) Diag(Tok, diag::ext_c99_feature) << Tok.getName(); @@ -7657,8 +7662,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { bool IsUnqual = Tok.is(tok::kw_typeof_unqual); const IdentifierInfo *II = Tok.getIdentifierInfo(); if (getLangOpts().C2x && !II->getName().startswith("__")) - Diag(Tok.getLocation(), diag::warn_c2x_compat_typeof_type_specifier) - << IsUnqual; + Diag(Tok.getLocation(), diag::warn_c2x_compat_keyword) << Tok.getName(); Token OpTok = Tok; SourceLocation StartLoc = ConsumeToken(); @@ -7858,7 +7862,7 @@ void Parser::DiagnoseBitIntUse(const Token &Tok) { // In C2x mode, diagnose that the use is not compatible with pre-C2x modes. // Otherwise, diagnose that the use is a Clang extension. if (getLangOpts().C2x) - Diag(Loc, diag::warn_c17_compat_bit_int); + Diag(Loc, diag::warn_c2x_compat_keyword) << Tok.getName(); else Diag(Loc, diag::ext_bit_int) << getLangOpts().CPlusPlus; } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index c7d8eb0af99d4..c2403f0d6f439 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -965,7 +965,9 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) { Diag(Tok, diag::ext_c11_feature) << Tok.getName(); if (Tok.is(tok::kw_static_assert)) { if (!getLangOpts().CPlusPlus) { - if (!getLangOpts().C2x) + if (getLangOpts().C2x) + Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); + else Diag(Tok, diag::ext_ms_static_assert) << FixItHint::CreateReplacement( Tok.getLocation(), "_Static_assert"); } else @@ -4457,7 +4459,10 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, CachedTokens &OpenMPTokens, SourceLocation *EndLoc) { if (Tok.is(tok::kw_alignas)) { - Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); + if (getLangOpts().C2x) + Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName(); + else + Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); ParseAlignmentSpecifier(Attrs, EndLoc); return; } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 66d937ac5742d..e2ada6ad9f82b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1007,8 +1007,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, if (getLangOpts().CPlusPlus) Diag(Tok, diag::warn_cxx98_compat_nullptr); else - Diag(Tok, getLangOpts().C2x ? diag::warn_c17_compat_nullptr - : diag::ext_c_nullptr); + Diag(Tok, getLangOpts().C2x ? diag::warn_c2x_compat_keyword + : diag::ext_c_nullptr) << Tok.getName(); Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); break; @@ -2484,8 +2484,11 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { RParenLoc); } - if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) + if (getLangOpts().CPlusPlus && + OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); + else if (getLangOpts().C2x && OpTok.is(tok::kw_alignof)) + Diag(OpTok, diag::warn_c2x_compat_keyword) << OpTok.getName(); EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, diff --git a/clang/test/C/C2x/n2934.c b/clang/test/C/C2x/n2934.c new file mode 100644 index 0000000000000..d36e0b76344a3 --- /dev/null +++ b/clang/test/C/C2x/n2934.c @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -ffreestanding -verify=c2x -std=c2x -Wpre-c2x-compat %s +// RUN: %clang_cc1 -ffreestanding -verify=c17 -std=c17 %s + +/* WG14 N2934: yes + * Revise spelling of keywords v7 + */ + +thread_local struct alignas(int) S { // c2x-warning {{'alignas' is incompatible with C standards before C2x}} \ + c2x-warning {{'thread_local' is incompatible with C standards before C2x}} \ + c17-error {{unknown type name 'thread_local'}} \ + c17-error {{expected identifier or '('}} \ + c17-error {{expected ')'}} \ + c17-note {{to match this '('}} + bool b; // c2x-warning {{'bool' is incompatible with C standards before C2x}} +} s; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} + +static_assert(alignof(struct S) == alignof(int), ""); // c2x-warning {{'static_assert' is incompatible with C standards before C2x}} \ + c2x-warning 2 {{'alignof' is incompatible with C standards before C2x}} \ + c17-error 2 {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + c17-error {{expected ')'}} \ + c17-warning {{declaration of 'struct S' will not be visible outside of this function}} \ + c17-note {{to match this '('}} + +#include <stdalign.h> + +// C17 and earlier must have __alignas_is_defined and __alignof_is_defined, +// but C2x and later must not. +#if __STDC_VERSION__ <= 201710L + #if __alignas_is_defined != 1 + #error "alignas should be defined" + #endif + #if __alignof_is_defined != 1 + #error "alignof should be defined" + #endif +#else + #ifdef __alignas_is_defined + #error "alignas should not be defined" + #endif + #ifdef __alignof_is_defined + #error "alignof should not be defined" + #endif +#endif + +#include <stdbool.h> + +// C17 and earlier must have bool defined as a macro, but C2x and later should +// not (at least in Clang's implementation; it's permissible for bool to be a +// macro in general, as it could expand to _Bool). +#if __STDC_VERSION__ <= 201710L + #ifndef bool + #error "bool should be defined" + #endif +#else + #ifdef bool + #error "bool should not be defined" + #endif +#endif diff --git a/clang/www/c_status.html b/clang/www/c_status.html index f8cd9f1fd2fcc..7665d24a381dc 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -1105,7 +1105,7 @@ <h2 id="c2x">C2x implementation status</h2> <tr> <td>Revise spelling of keywords v7</td> <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2934.pdf">N2934</a></td> - <td class="none" align="center">No</td> + <td class="unreleased" align="center">Clang 17</td> </tr> <tr> <td>Make false and true first-class language features v8</td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits