aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorAlejandro Álvarez Ayllón <alejandro.alvarez@sonarsource.com>2023-05-15 07:39:58 -0400
committerAaron Ballman <aaron@aaronballman.com>2023-05-15 07:39:58 -0400
commitb321738f71259d138c9b2002944eb65f099ec2a6 (patch)
tree3fb967d72b11641b7a3473edf92ed09f31a37007 /clang/lib
parent45b899b92f5762c15d435e58666f5eee18e73b40 (diff)
downloadllvm-b321738f71259d138c9b2002944eb65f099ec2a6.zip
llvm-b321738f71259d138c9b2002944eb65f099ec2a6.tar.gz
llvm-b321738f71259d138c9b2002944eb65f099ec2a6.tar.bz2
[clang][parser] Fix namespace dropping after malformed declarations
* After a malformed top-level declaration * After a malformed templated class method declaration In both cases, when there is a malformed declaration, any following namespace is dropped from the AST. This can trigger a cascade of confusing diagnostics that may hide the original error. An example: ``` // Start #include "SomeFile.h" template <class T> void Foo<T>::Bar(void* aRawPtr) { (void)(aRawPtr); } // End #include "SomeFile.h" int main() {} ``` We get the original error, plus 19 others from the standard library. With this patch, we only get the original error. clangd can also benefit from this patch, as namespaces following the malformed declaration is now preserved. i.e. ``` MACRO_FROM_MISSING_INCLUDE("X") namespace my_namespace { //... } ``` Before this patch, my_namespace is not visible for auto-completion. Differential Revision: https://reviews.llvm.org/D150258
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp23
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp5
2 files changed, 13 insertions, 15 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 2bbe2ba..92fa7d8 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2176,13 +2176,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- if (isDeclarationSpecifier(ImplicitTypenameContext::No)) {
- // If there is an invalid declaration specifier right after the
- // function prototype, then we must be in a missing semicolon case
- // where this isn't actually a body. Just fall through into the code
- // that handles it as a prototype, and let the top-level code handle
- // the erroneous declspec where it would otherwise expect a comma or
- // semicolon.
+ if (isDeclarationSpecifier(ImplicitTypenameContext::No) ||
+ Tok.is(tok::kw_namespace)) {
+ // If there is an invalid declaration specifier or a namespace
+ // definition right after the function prototype, then we must be in a
+ // missing semicolon case where this isn't actually a body. Just fall
+ // through into the code that handles it as a prototype, and let the
+ // top-level code handle the erroneous declspec where it would
+ // otherwise expect a comma or semicolon. Note that
+ // isDeclarationSpecifier already covers 'inline namespace', since
+ // 'inline' can be a declaration specifier.
} else {
Diag(Tok, diag::err_expected_fn_body);
SkipUntil(tok::semi);
@@ -2303,10 +2306,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Okay, there was no semicolon and one was expected. If we see a
// declaration specifier, just assume it was missing and continue parsing.
// Otherwise things are very confused and we skip to recover.
- if (!isDeclarationSpecifier(ImplicitTypenameContext::No)) {
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- TryConsumeToken(tok::semi);
- }
+ if (!isDeclarationSpecifier(ImplicitTypenameContext::No))
+ SkipMalformedDecl();
}
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 72df117..964d985 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -275,10 +275,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
- // If so, skip until the semi-colon or a }.
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
+ SkipMalformedDecl();
return nullptr;
}