[clang] b147019 - [clang] Preserve `externs` following broken declarations (#161641)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 2 07:11:35 PDT 2025
Author: Alejandro Álvarez Ayllón
Date: 2025-10-02T16:11:31+02:00
New Revision: b147019f8b11cd491f331bd707f764786792665e
URL: https://github.com/llvm/llvm-project/commit/b147019f8b11cd491f331bd707f764786792665e
DIFF: https://github.com/llvm/llvm-project/commit/b147019f8b11cd491f331bd707f764786792665e.diff
LOG: [clang] Preserve `externs` following broken declarations (#161641)
Treat them as namespaces: if they are at the beginning of the line, they
are likely a good recovery point.
For instance, in
```cpp
1.3.0
extern "C" {
extern int foo();
extern "C++" {
namespace bar {
void baz();
};
}
}
namespace {}
```
Everything until `namespace`... is gone from the AST. Headers (like
libc's C++ `math.h`) can be included from an `extern "C"` context, and
they do an `extern "C++"` back again before including C++ headers (like
`__type_traits`).
However, a malformed declaration just before the include (as the orphan
`1.3.0` in the example) causes everything from these standard headers to
go missing. This patch updates the heuristic to try to recover from the
first `extern` keyword seen, pretty much as it is done for `namespace`.
CPP-4478
Added:
clang/test/Parser/recovery-after-expected-unqualified-id.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Parse/ParseDecl.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c6ee1e282a008..74b0647f38795 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -446,6 +446,7 @@ Bug Fixes to AST Handling
legal representation. This is fixed because ElaboratedTypes don't exist anymore. (#GH43179) (#GH68670) (#GH92757)
- Fix unrecognized html tag causing undesirable comment lexing (#GH152944)
- Fix comment lexing of special command names (#GH152943)
+- Use `extern` as a hint to continue parsing when recovering from a malformed declaration.
Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 22c01c4e371f3..d6cd7eb8c2c3d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2083,6 +2083,9 @@ void Parser::SkipMalformedDecl() {
return;
break;
+ case tok::kw_extern:
+ // 'extern' at the start of a line is almost certainly a good
+ // place to pick back up parsing
case tok::kw_namespace:
// 'namespace' at the start of a line is almost certainly a good
// place to pick back up parsing, except in an Objective-C
diff --git a/clang/test/Parser/recovery-after-expected-unqualified-id.cpp b/clang/test/Parser/recovery-after-expected-unqualified-id.cpp
new file mode 100644
index 0000000000000..8019b46df1e7b
--- /dev/null
+++ b/clang/test/Parser/recovery-after-expected-unqualified-id.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -verify %s
+
+3.2 // expected-error {{expected unqualified-id}}
+
+extern "C" {
+ typedef int Int;
+}
+
+Int foo(); // Ok
More information about the cfe-commits
mailing list