llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Tadeusz (tadeuszjt)

<details>
<summary>Changes</summary>

**Problem**
`ParseOptionalCXXScopeSpecifier` is called with a `MayBePseudoDestructor` 
argument present, meaning it has to check for `~` symbols, but the token stream 
contains an `annot_cxxscope` token instead of regular tokens which was created 
by a different tentative branch. The code logic had simply not accounted for 
this possibility.

**Solution**
Added the missing logic to `ParseOptionalCXXScopeSpecifier` which is consistent 
with the other `~` checks in this function and created tests to verify the 
output. 

**Assumptions**
Unfortunately the code in this area is complex and has lots of different 
functionality built into it so it's hard to be sure about the solution but it's 
based on the following assumptions. Luckily, there's only one case where 
`ParseOptionalCXXScopeSpecifier` is called with a `MayBePsuedoDestructor` 
argument, in `ParsePostfixExpressionSuffix`, so the added logic shouldn't 
affect anything else:

1.) That it is normal for a `annot_cxxscope` token to be left in the stream 
from a different path because it can be re-used.

2.) That the sequence of `annot_cxxscope, token(~), ...` is a valid 
early-exit-if-possible-destructor case.

3.) That the new logic should not `RestoreNestedNameSpecifierAnnotation` or 
`ConsumeAnnotationToken` (causes subsequent `ParseCXXPseudoDestructor` crash).

Call stack which creates the `annot_cxxscope`:
```
ParseFunctionDefinition
...
              → ParseAssignmentExpression
                → ParseCastExpression
                  → ParseCastExpression
                    → ParseParenExpression
                      → isCXXTypeId
                        → TryParseDeclarator
                          → TryParseFunctionDeclarator
                            → isCXXTypeId
                              → isCXXDeclarationSpecifier
                                → TryAnnotateTypeOrScopeToken
                                  → TryAnnotateTypeOrScopeTokenAfterScopeSpec
                                    → setTypeAnnotation
                                      → Token::setAnnotationValue
                                        → AnnotateScopeToken
```

Call stack which fails on the `annot_cxxscope`:
```
ParseFunctionDefinition
...
              → ParseAssignmentExpression
                → ParseCastExpression
                  → ParseCastExpression
                    → ParseParenExpression
                      → ParseExpression
                        → ParseAssignmentExpression
                          → ParseCastExpression
                            → ParseCastExpression
                              → ParsePostfixExpressionSuffix
                                → ParseOptionalCXXScopeSpecifier
```

---
Full diff: https://github.com/llvm/llvm-project/pull/221209.diff


2 Files Affected:

- (modified) clang/lib/Parse/ParseExprCXX.cpp (+12-8) 
- (added) clang/test/Parser/gh220186.cpp (+10) 


``````````diff
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index b1216a07f7624..dbd1e89070939 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -112,9 +112,20 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
   assert(getLangOpts().CPlusPlus &&
          "Call sites of this function should be guarded by checking for C++");
 
+  // Has to happen before any "return false"s in this function.
+  bool CheckForDestructor = false;
+  if (MayBePseudoDestructor && *MayBePseudoDestructor) {
+    CheckForDestructor = true;
+    *MayBePseudoDestructor = false;
+  }
+
   if (Tok.is(tok::annot_cxxscope)) {
     assert(!LastII && "want last identifier but have already annotated scope");
-    assert(!MayBePseudoDestructor && "unexpected annot_cxxscope");
+    if (CheckForDestructor && Tok.is(tok::tilde)) {
+      *MayBePseudoDestructor = true;
+      return false;
+    }
+
     Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
                                                  Tok.getAnnotationRange(),
                                                  SS);
@@ -122,13 +133,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
     return false;
   }
 
-  // Has to happen before any "return false"s in this function.
-  bool CheckForDestructor = false;
-  if (MayBePseudoDestructor && *MayBePseudoDestructor) {
-    CheckForDestructor = true;
-    *MayBePseudoDestructor = false;
-  }
-
   if (LastII)
     *LastII = nullptr;
 
diff --git a/clang/test/Parser/gh220186.cpp b/clang/test/Parser/gh220186.cpp
new file mode 100644
index 0000000000000..6ac4e8a1a3970
--- /dev/null
+++ b/clang/test/Parser/gh220186.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+
+void foo1() { (auto()->bar::); }
+// expected-error@-1 {{use of undeclared identifier 'bar'}}
+// expected-error@-2 {{initializer for functional-style cast to 'auto' is 
empty}}
+// expected-error@-3 {{expected unqualified-id}}
+
+void foo2() { (auto()->bar::~bar()); }
+// expected-error@-1 {{use of undeclared identifier 'bar'}}
+// expected-error@-2 {{initializer for functional-style cast to 'auto' is 
empty}}

``````````

</details>


https://github.com/llvm/llvm-project/pull/221209
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to