[clang] [clang] more useful error message for decomposition declaration missing initializer (PR #127924)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 26 05:59:49 PST 2025
https://github.com/kbrav updated https://github.com/llvm/llvm-project/pull/127924
>From 7f7b9b3f2e7324bd290decb7151c9432875b1dd6 Mon Sep 17 00:00:00 2001
From: kbrav <kevin at halys.dev>
Date: Wed, 19 Feb 2025 19:05:05 -0500
Subject: [PATCH 1/3] [clang] more useful error message for decomposition
declaration missing initializer (#90107)
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/SemaDecl.cpp | 12 +++++++++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index feef50812eca9..ad36ae898b147 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -555,7 +555,7 @@ def err_decomp_decl_template : Error<
def err_decomp_decl_not_alone : Error<
"decomposition declaration must be the only declaration in its group">;
def err_decomp_decl_requires_init : Error<
- "decomposition declaration %0 requires an initializer">;
+ "decomposition declaration %0 requires an initializer, but got %1 instead">;
def err_decomp_decl_wrong_number_bindings : Error<
"type %0 decomposes into %3 %plural{1:element|:elements}2, but "
"%select{%plural{0:no|:only %1}1|%1}4 "
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 362df485a025c..c62041c8c5e93 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14058,7 +14058,17 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory.
if (isa<DecompositionDecl>(RealDecl)) {
- Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var;
+ Preprocessor &PP = getPreprocessor();
+ SourceManager &SM = Context.getSourceManager();
+ LangOptions LO = Context.getLangOpts();
+
+ // Lexer previously checked for '=' and didn't find it
+ // Highlight the token found in its place in the error message
+ Token Tok;
+ Lexer::getRawToken(PP.getLastCachedTokenLocation(), Tok, SM, LO);
+
+ Diag(Tok.getLocation(), diag::err_decomp_decl_requires_init)
+ << Var << Lexer::getSpelling(Tok, SM, LO);
Var->setInvalidDecl();
return;
}
>From cd657462ec40663896fa60fdabf565625188958f Mon Sep 17 00:00:00 2001
From: kbrav <kevin at halys.dev>
Date: Wed, 19 Feb 2025 19:51:19 -0500
Subject: [PATCH 2/3] run clang-format
---
clang/lib/Sema/SemaDecl.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c62041c8c5e93..724da72b8115e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14058,9 +14058,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory.
if (isa<DecompositionDecl>(RealDecl)) {
- Preprocessor &PP = getPreprocessor();
+ Preprocessor &PP = getPreprocessor();
SourceManager &SM = Context.getSourceManager();
- LangOptions LO = Context.getLangOpts();
+ LangOptions LO = Context.getLangOpts();
// Lexer previously checked for '=' and didn't find it
// Highlight the token found in its place in the error message
@@ -14068,7 +14068,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
Lexer::getRawToken(PP.getLastCachedTokenLocation(), Tok, SM, LO);
Diag(Tok.getLocation(), diag::err_decomp_decl_requires_init)
- << Var << Lexer::getSpelling(Tok, SM, LO);
+ << Var << Lexer::getSpelling(Tok, SM, LO);
Var->setInvalidDecl();
return;
}
>From feac0003628dd18a54a8c1f101bd21be4e714534 Mon Sep 17 00:00:00 2001
From: kbrav <kevin at halys.dev>
Date: Tue, 25 Feb 2025 02:01:22 -0500
Subject: [PATCH 3/3] highlight token after decomposition decl in parser
---
clang/docs/ReleaseNotes.rst | 1 +
clang/include/clang/Basic/DiagnosticParseKinds.td | 1 +
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Parse/ParseDecl.cpp | 2 ++
clang/lib/Sema/SemaDecl.cpp | 12 +-----------
clang/test/PCH/cxx1z-decomposition.cpp | 2 +-
clang/test/Parser/cxx1z-decomposition.cpp | 9 +++++----
clang/test/SemaCXX/cxx1z-decomposition.cpp | 2 +-
8 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 657340c170503..109abdef4ad01 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -193,6 +193,7 @@ Improvements to Clang's diagnostics
under the subgroup ``-Wunsafe-buffer-usage-in-libc-call``.
- Diagnostics on chained comparisons (``a < b < c``) are now an error by default. This can be disabled with
``-Wno-error=parentheses``.
+- Added a clearer diagnostic for uninitialized decomposition declarations.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c513dab810d1f..f80670949e58a 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -497,6 +497,7 @@ def err_expected_coloncolon_after_super : Error<
def ext_decomp_decl_empty : ExtWarn<
"ISO C++17 does not allow a decomposition group to be empty">,
InGroup<DiagGroup<"empty-decomposition">>;
+def err_expected_init : Error<"expected initializer before '%0'">;
def err_function_parameter_limit_exceeded : Error<
"too many function parameters; subsequent parameters will be ignored">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 980960095d68a..51301d95e55b9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -555,7 +555,7 @@ def err_decomp_decl_template : Error<
def err_decomp_decl_not_alone : Error<
"decomposition declaration must be the only declaration in its group">;
def err_decomp_decl_requires_init : Error<
- "decomposition declaration %0 requires an initializer, but got %1 instead">;
+ "decomposition declaration %0 requires an initializer">;
def err_decomp_decl_wrong_number_bindings : Error<
"type %0 decomposes into %3 %plural{1:element|:elements}2, but "
"%select{%plural{0:no|:only %1}1|%1}4 "
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 7ae136af47391..1cb871493aaeb 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2932,6 +2932,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
break;
}
case InitKind::Uninitialized: {
+ if (D.isDecompositionDeclarator())
+ Diag(Tok, diag::err_expected_init) << PP.getSpelling(Tok);
Actions.ActOnUninitializedDecl(ThisDecl);
break;
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 54bd22a4f5254..285bd27a35a76 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14065,17 +14065,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory.
if (isa<DecompositionDecl>(RealDecl)) {
- Preprocessor &PP = getPreprocessor();
- SourceManager &SM = Context.getSourceManager();
- LangOptions LO = Context.getLangOpts();
-
- // Lexer previously checked for '=' and didn't find it
- // Highlight the token found in its place in the error message
- Token Tok;
- Lexer::getRawToken(PP.getLastCachedTokenLocation(), Tok, SM, LO);
-
- Diag(Tok.getLocation(), diag::err_decomp_decl_requires_init)
- << Var << Lexer::getSpelling(Tok, SM, LO);
+ Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var;
Var->setInvalidDecl();
return;
}
diff --git a/clang/test/PCH/cxx1z-decomposition.cpp b/clang/test/PCH/cxx1z-decomposition.cpp
index 914ce80c550d1..e6d56bfefd3d0 100644
--- a/clang/test/PCH/cxx1z-decomposition.cpp
+++ b/clang/test/PCH/cxx1z-decomposition.cpp
@@ -22,7 +22,7 @@ constexpr int foo(Q &&q) {
return a * 10 + b;
}
-auto [noinit]; // expected-error{{decomposition declaration '[noinit]' requires an initializer}}
+auto [noinit]; // expected-error{{decomposition declaration '[noinit]' requires an initializer}} expected-error{{expected initializer before ';'}}
#else
diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp
index acf3f99069185..94d3f15f2e498 100644
--- a/clang/test/Parser/cxx1z-decomposition.cpp
+++ b/clang/test/Parser/cxx1z-decomposition.cpp
@@ -103,10 +103,10 @@ namespace BadSpecifiers {
// FIXME: This error is not very good.
auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}}
- auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}}
+ auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}} expected-error {{expected initializer before '['}}
// FIXME: This should fire the 'misplaced array declarator' diagnostic.
- int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}}
+ int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}} expected-error {{expected initializer before 'arr'}}
int [5] arr = {0}; // expected-error {{place the brackets after the name}}
auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}}
@@ -120,7 +120,7 @@ namespace BadSpecifiers {
[[]] auto [ok_3] = s;
alignas(S) auto [ok_4] = s;
- auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}}
+ auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}} expected-error {{decomposition declaration '[bad_attr_2]' requires an initializer}}
}
}
@@ -144,7 +144,7 @@ namespace Init {
void f() {
int arr[1];
struct S { int n; };
- auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}}
+ auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} expected-error {{expected initializer before ';'}}
const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}}
const auto &[bad3](); // expected-error {{expected expression}}
auto &[good1] = arr;
@@ -152,6 +152,7 @@ namespace Init {
const auto &[good3](S{});
S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}}
S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}}
+ auto [A, B] C = {1, 2}; // expected-error{{expected initializer before 'C'}} expected-error{{decomposition declaration '[A, B]' requires an initializer}} expected-error{{expected ';' at end of declaration}}
}
}
diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp
index 95c64bc3b8bff..f68d87446d33a 100644
--- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -121,7 +121,7 @@ void for_range() {
}
int error_recovery() {
- auto [foobar]; // expected-error {{requires an initializer}}
+ auto [foobar]; // expected-error {{requires an initializer}} expected-error {{expected initializer before ';'}}
return foobar_; // expected-error {{undeclared identifier 'foobar_'}}
}
More information about the cfe-commits
mailing list