cor3ntin created this revision.
Herald added a project: All.
cor3ntin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

`(T())(foo)` is a cast expression because `T()`
is treated as a type-id, and the expression is valid.

However, `(T())(foo...)` is not a valid cast-expression,
because `(type-id)(foo...)` is invalid.
Yet, it is a valid postfix expression, ie,
`T().operator()(foo...)`

We previously would uncontitionally consider the whole thing
a cast expression and complained about expecting a
right parenthesis after `foo`.

We do keep track of whether we are in a context where the
type-id is ambiguous to keep the existing diagnostics for
the non ambiguous case (ie `(void)(foo...)`).

Fixes #64926


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158718

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Parse/Parser.h
  clang/lib/Parse/ParseExpr.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/Parser.cpp
  clang/test/Parser/cxx-ambig-paren-expr.cpp

Index: clang/test/Parser/cxx-ambig-paren-expr.cpp
===================================================================
--- clang/test/Parser/cxx-ambig-paren-expr.cpp
+++ clang/test/Parser/cxx-ambig-paren-expr.cpp
@@ -70,3 +70,24 @@
     return;
 }
 
+namespace GH64926 {
+template<typename T, typename... Args>
+void PackInAmbiguousCastExpression(Args... args) {
+	  (void) (Args::foo()...); // expected-error {{expression contains unexpanded parameter pack 'Args'}} \
+                            // expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+    (void) (args...);  // expected-error {{expression contains unexpanded parameter pack 'args'}} \
+                       // expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+    (void) (((args))...);  // expected-error {{expression contains unexpanded parameter pack 'args'}} \
+                           // expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+    (void) (((args...)));  // expected-error {{expression contains unexpanded parameter pack 'args'}} \
+                           // expected-error {{expected ')'}} expected-note {{to match this '('}}
+    (T()) (Args::foo()...);
+    (T()) (args...);
+    (T()) (((args))...);
+    (T()) (((args...))); // expected-error {{expression contains unexpanded parameter pack 'args'}} \
+                         // expected-error {{expected ')'}} expected-note {{to match this '('}}
+}
+}
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -53,6 +53,7 @@
     : PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions),
       Diags(PP.getDiagnostics()), GreaterThanIsOperator(true),
       ColonIsSacred(false), InMessageExpression(false),
+      InAmbiguousCXXParenExprParsing(false),
       TemplateParameterDepth(0), ParsingInObjCContainer(false) {
   SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
   Tok.startToken();
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -3981,6 +3981,7 @@
       // If it is not a cast-expression, NotCastExpr will be true and no token
       // will be consumed.
       ColonProt.restore();
+      SaveAndRestore AmbiguousParenRAII(InAmbiguousCXXParenExprParsing, true);
       Result = ParseCastExpression(AnyCastExpr,
                                    false/*isAddressofOperand*/,
                                    NotCastExpr,
Index: clang/lib/Parse/ParseExpr.cpp
===================================================================
--- clang/lib/Parse/ParseExpr.cpp
+++ clang/lib/Parse/ParseExpr.cpp
@@ -28,6 +28,7 @@
 #include "clang/Parse/RAIIObjectsForParser.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/EnterExpressionEvaluationContext.h"
+#include "clang/Sema/Ownership.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/TypoCorrection.h"
@@ -3164,6 +3165,14 @@
         return ParseFoldExpression(ArgExprs[0], T);
       }
 
+      // If we find an ellipsis, this cannot be part of a cast expression,
+      // stop there and try to parse a simple expression instead.
+      // This handles `(T())(expr...)`.
+      if(InAmbiguousCXXParenExprParsing && isTypeCast && Tok.is(tok::ellipsis)
+          && ExprType == Parser::CastExpr && getLangOpts().CPlusPlus) {
+        return ExprError();
+      }
+
       ExprType = SimpleExpr;
       Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
                                           ArgExprs);
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -245,6 +245,10 @@
   /// should not be set directly.
   bool InMessageExpression;
 
+  /// Track whether we are currently trying to parse an ambiguous
+  /// paren expression after a cast expression.
+  bool InAmbiguousCXXParenExprParsing;
+
   /// Gets set to true after calling ProduceSignatureHelp, it is for a
   /// workaround to make sure ProduceSignatureHelp is only called at the deepest
   /// function call.
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -198,6 +198,10 @@
 - Update ``FunctionDeclBitfields.NumFunctionDeclBits``. This fixes:
   (`#64171 <https://github.com/llvm/llvm-project/issues/64171>`_).
 
+- Correctly parse ``(T())(pack...)`` as a call to ``T::operator()``
+  instead of an invalid cast expression.
+  (`#64926 <https://github.com/llvm/llvm-project/issues/64926>`_)
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 - Fixed an import failure of recursive friend class template.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D158718: [Clang] Ha... Corentin Jabot via Phabricator via cfe-commits

Reply via email to