aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseCXXInlineMethods.cpp
diff options
context:
space:
mode:
authorKrystian Stasiowski <sdkrystian@gmail.com>2024-07-29 14:01:00 -0400
committerGitHub <noreply@github.com>2024-07-29 14:01:00 -0400
commit708a9a06cba66bc8f739b05646e7d3be9247feee (patch)
treeb22b5d17e04e01c5d040c55ea7c95c8c93638c9f /clang/lib/Parse/ParseCXXInlineMethods.cpp
parentc66d25d1429fbf49c97ee9cd0195246642178cb7 (diff)
downloadllvm-708a9a06cba66bc8f739b05646e7d3be9247feee.zip
llvm-708a9a06cba66bc8f739b05646e7d3be9247feee.tar.gz
llvm-708a9a06cba66bc8f739b05646e7d3be9247feee.tar.bz2
[Clang][Parse] Fix ambiguity with nested-name-specifiers that may declarative (#96364)
Consider the following: ``` template<typename T> struct A { }; template<typename T> int A<T>::B::* f(); // error: no member named 'B' in 'A<T>' ``` Although this is clearly valid, clang rejects it because the _nested-name-specifier_ `A<T>::` is parsed as-if it was declarative, meaning, we parse it as-if it was the _nested-name-specifier_ in a redeclaration/specialization. However, we don't (and can't) know whether the _nested-name-specifier_ is declarative until we see the '`*`' token, but at that point we have already complained that `A` has no member named `B`! This patch addresses this bug by adding support for _fully_ unannotated _and_ unbounded tentative parsing, which allows for us to parse past tokens without having to cache them until we reach a point where we can guarantee to be past the construct we are disambiguating. I don't know where the approach taken here is ideal -- alternatives are welcome. However, the performance impact (as measured by llvm-compile-time-tracker (https://llvm-compile-time-tracker.com/?config=Overview&stat=instructions%3Au&remote=sdkrystian) is quite minimal (0.09%, which I plan to further improve).
Diffstat (limited to 'clang/lib/Parse/ParseCXXInlineMethods.cpp')
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp41
1 files changed, 2 insertions, 39 deletions
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 9ccbbf9..b461743 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -1205,41 +1205,6 @@ bool Parser::ConsumeAndStoreConditional(CachedTokens &Toks) {
return true;
}
-/// A tentative parsing action that can also revert token annotations.
-class Parser::UnannotatedTentativeParsingAction : public TentativeParsingAction {
-public:
- explicit UnannotatedTentativeParsingAction(Parser &Self,
- tok::TokenKind EndKind)
- : TentativeParsingAction(Self), Self(Self), EndKind(EndKind) {
- // Stash away the old token stream, so we can restore it once the
- // tentative parse is complete.
- TentativeParsingAction Inner(Self);
- Self.ConsumeAndStoreUntil(EndKind, Toks, true, /*ConsumeFinalToken*/false);
- Inner.Revert();
- }
-
- void RevertAnnotations() {
- Revert();
-
- // Put back the original tokens.
- Self.SkipUntil(EndKind, StopAtSemi | StopBeforeMatch);
- if (Toks.size()) {
- auto Buffer = std::make_unique<Token[]>(Toks.size());
- std::copy(Toks.begin() + 1, Toks.end(), Buffer.get());
- Buffer[Toks.size() - 1] = Self.Tok;
- Self.PP.EnterTokenStream(std::move(Buffer), Toks.size(), true,
- /*IsReinject*/ true);
-
- Self.Tok = Toks.front();
- }
- }
-
-private:
- Parser &Self;
- CachedTokens Toks;
- tok::TokenKind EndKind;
-};
-
/// ConsumeAndStoreInitializer - Consume and store the token at the passed token
/// container until the end of the current initializer expression (either a
/// default argument or an in-class initializer for a non-static data member).
@@ -1277,9 +1242,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
// syntactically-valid init-declarator-list, then this comma ends
// the default initializer.
{
- UnannotatedTentativeParsingAction PA(*this,
- CIK == CIK_DefaultInitializer
- ? tok::semi : tok::r_paren);
+ TentativeParsingAction TPA(*this, /*Unannotated=*/true);
Sema::TentativeAnalysisScope Scope(Actions);
TPResult Result = TPResult::Error;
@@ -1307,7 +1270,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
// Put the token stream back and undo any annotations we performed
// after the comma. They may reflect a different parse than the one
// we will actually perform at the end of the class.
- PA.RevertAnnotations();
+ TPA.Revert();
// If what follows could be a declaration, it is a declaration.
if (Result != TPResult::False && Result != TPResult::Error)