[clang] [C11] Diagnose C11 keywords as being incompatible w/earlier standards (PR #82015)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 16 09:52:20 PST 2024
https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/82015
Our usual pattern when issuing an extension warning is to also issue a
default-off diagnostic about the keywords not being compatible with
standards before a certain point. This adds those diagnostics for C11
keywords.
>From a32d6677cc5398750a21c1328f72ecbb6fa97517 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 16 Feb 2024 12:44:32 -0500
Subject: [PATCH 1/2] [C11] Diagnose C11 keywords as being incompatible
w/earlier standards
Our usual pattern when issuing an extension warning is to also issue a
default-off diagnostic about the keywords not being compatible with
standards before a certain point. This adds those diagnostics for C11
keywords.
---
clang/include/clang/Basic/DiagnosticGroups.td | 3 ++
.../clang/Basic/DiagnosticParseKinds.td | 3 ++
clang/include/clang/Parse/Parser.h | 2 +
clang/lib/Parse/ParseDecl.cpp | 16 +++-----
clang/lib/Parse/ParseDeclCXX.cpp | 6 +--
clang/lib/Parse/ParseExpr.cpp | 7 ++--
clang/lib/Parse/Parser.cpp | 13 +++++++
clang/test/Sema/c11-keywords.c | 37 +++++++++++++++++++
8 files changed, 69 insertions(+), 18 deletions(-)
create mode 100644 clang/test/Sema/c11-keywords.c
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 7679b8528a4197..e8b4139d7893ce 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -290,6 +290,9 @@ def : DiagGroup<"c++1z-compat-mangling", [CXX17CompatMangling]>;
def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>;
// Warnings for C code which is not compatible with previous C standards.
+def CPre11Compat : DiagGroup<"pre-c11-compat">;
+def CPre11CompatPedantic : DiagGroup<"pre-c11-compat-pedantic",
+ [CPre11Compat]>;
def CPre23Compat : DiagGroup<"pre-c23-compat">;
def CPre23CompatPedantic : DiagGroup<"pre-c23-compat-pedantic",
[CPre23Compat]>;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 11b490a0928e60..c0dbc25a0c3265 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -165,6 +165,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_c11_compat_keyword : Warning<
+ "'%0' is incompatible with C standards before C11">,
+ InGroup<CPre11Compat>, DefaultIgnore;
def warn_c23_compat_keyword : Warning<
"'%0' is incompatible with C standards before C23">,
InGroup<CPre23Compat>, DefaultIgnore;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 69b9e837fe8bef..071520f535bc95 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1122,6 +1122,8 @@ class Parser : public CodeCompletionHandler {
void checkCompoundToken(SourceLocation FirstTokLoc,
tok::TokenKind FirstTokKind, CompoundToken Op);
+ void diagnoseUseOfC11Keyword(const Token &Tok);
+
public:
//===--------------------------------------------------------------------===//
// Scope manipulation
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 9640d7ee70d27f..0728113ba7c936 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3520,8 +3520,7 @@ void Parser::ParseDeclarationSpecifiers(
// alignment-specifier
case tok::kw__Alignas:
- if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+ diagnoseUseOfC11Keyword(Tok);
[[fallthrough]];
case tok::kw_alignas:
// _Alignas and alignas (C23, not C++) should parse the same way. The C++
@@ -4184,8 +4183,7 @@ void Parser::ParseDeclarationSpecifiers(
isStorageClass = true;
break;
case tok::kw__Thread_local:
- if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+ diagnoseUseOfC11Keyword(Tok);
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
Loc, PrevSpec, DiagID);
isStorageClass = true;
@@ -4245,8 +4243,7 @@ void Parser::ParseDeclarationSpecifiers(
break;
}
case tok::kw__Noreturn:
- if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+ diagnoseUseOfC11Keyword(Tok);
isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
break;
@@ -4576,9 +4573,7 @@ void Parser::ParseDeclarationSpecifiers(
// If the _Atomic keyword is immediately followed by a left parenthesis,
// it is interpreted as a type specifier (with a type name), not as a
// type qualifier.
- if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
-
+ diagnoseUseOfC11Keyword(Tok);
if (NextToken().is(tok::l_paren)) {
ParseAtomicSpecifier(DS);
continue;
@@ -6154,8 +6149,7 @@ void Parser::ParseTypeQualifierListOpt(
case tok::kw__Atomic:
if (!AtomicAllowed)
goto DoneWithTypeQuals;
- if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+ diagnoseUseOfC11Keyword(Tok);
isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
getLangOpts());
break;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 7d0dbc4ac69490..62632b2d79792e 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -968,9 +968,9 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) {
// Save the token name used for static assertion.
const char *TokName = Tok.getName();
- if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
- if (Tok.is(tok::kw_static_assert)) {
+ if (Tok.is(tok::kw__Static_assert))
+ diagnoseUseOfC11Keyword(Tok);
+ else if (Tok.is(tok::kw_static_assert)) {
if (!getLangOpts().CPlusPlus) {
if (getLangOpts().C23)
Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName();
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 52cebdb6f64bac..f1417456ffe510 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1462,8 +1462,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
return Res;
}
case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')'
- if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+ diagnoseUseOfC11Keyword(Tok);
[[fallthrough]];
case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')'
case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
@@ -3389,8 +3388,8 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral,
/// \endverbatim
ExprResult Parser::ParseGenericSelectionExpression() {
assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
- if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+
+ diagnoseUseOfC11Keyword(Tok);
SourceLocation KeyLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 2dd4a73bfbc262..abc06468fc9d61 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -2742,6 +2742,19 @@ bool Parser::parseMisplacedModuleImport() {
return false;
}
+void Parser::diagnoseUseOfC11Keyword(const Token& Tok) {
+ // Warn that this is a C11 extension if in an older mode or if in C++.
+ // Otherwise, warn that it is incompatible with standards before C11 if in
+ // C11 or later.
+ unsigned DiagId;
+ if (!getLangOpts().C11) {
+ DiagId = diag::ext_c11_feature;
+ } else {
+ DiagId = diag::warn_c11_compat_keyword;
+ }
+ Diag(Tok, DiagId) << Tok.getName();
+}
+
bool BalancedDelimiterTracker::diagnoseOverflow() {
P.Diag(P.Tok, diag::err_bracket_depth_exceeded)
<< P.getLangOpts().BracketDepth;
diff --git a/clang/test/Sema/c11-keywords.c b/clang/test/Sema/c11-keywords.c
new file mode 100644
index 00000000000000..2621e1a1a8595d
--- /dev/null
+++ b/clang/test/Sema/c11-keywords.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 %s -std=c11 -fsyntax-only -verify=compat -Wpre-c11-compat
+// RUN: %clang_cc1 %s -std=c99 -fsyntax-only -verify=ext -pedantic
+// RUN: %clang_cc1 %s -std=c11 -fsyntax-only -verify=good
+// RUN: %clang_cc1 -x c++ %s -fsyntax-only -verify=ext -pedantic
+
+// good-no-diagnostics
+
+extern _Noreturn void exit(int); /* compat-warning {{'_Noreturn' is incompatible with C standards before C11}}
+ ext-warning {{'_Noreturn' is a C11 extension}}
+ */
+
+void func(void) {
+ static _Thread_local int tl; /* compat-warning {{'_Thread_local' is incompatible with C standards before C11}}
+ ext-warning {{'_Thread_local' is a C11 extension}}
+ */
+ _Alignas(8) char c; /* compat-warning {{'_Alignas' is incompatible with C standards before C11}}
+ ext-warning {{'_Alignas' is a C11 extension}}
+ */
+ _Atomic int i1; /* compat-warning {{'_Atomic' is incompatible with C standards before C11}}
+ ext-warning {{'_Atomic' is a C11 extension}}
+ */
+ _Atomic(int) i2; /* compat-warning {{'_Atomic' is incompatible with C standards before C11}}
+ ext-warning {{'_Atomic' is a C11 extension}}
+ */
+
+ _Static_assert(1, ""); /* compat-warning {{'_Static_assert' is incompatible with C standards before C11}}
+ ext-warning {{'_Static_assert' is a C11 extension}}
+ */
+
+ (void)_Generic(1, int : 1); /* compat-warning {{'_Generic' is incompatible with C standards before C11}}
+ ext-warning {{'_Generic' is a C11 extension}}
+ */
+ (void)_Alignof(int); /* compat-warning {{'_Alignof' is incompatible with C standards before C11}}
+ ext-warning {{'_Alignof' is a C11 extension}}
+ */
+}
+
>From 6bce3bc879072a915c6c77b2a3d9d96d60d568ee Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 16 Feb 2024 12:49:58 -0500
Subject: [PATCH 2/2] Add release note
---
clang/docs/ReleaseNotes.rst | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 16f79a349c20c8..06c7d57d73ca70 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -185,6 +185,9 @@ Improvements to Clang's diagnostics
- Clang now diagnoses friend declarations with an ``enum`` elaborated-type-specifier in language modes after C++98.
+- Added diagnostics for C11 keywords being incompatible with language standards
+ before C11, under a new warning group: ``-Wpre-c11-compat``.
+
Improvements to Clang's time-trace
----------------------------------
More information about the cfe-commits
mailing list