diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -198,6 +198,10 @@ - Update ``FunctionDeclBitfields.NumFunctionDeclBits``. This fixes: (`#64171 `_). +- Correctly parse ``(T())(pack...)`` as a call to ``T::operator()`` + instead of an invalid cast expression. + (`#64926 `_) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/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. diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/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); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/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, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/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(); diff --git a/clang/test/Parser/cxx-ambig-paren-expr.cpp b/clang/test/Parser/cxx-ambig-paren-expr.cpp --- a/clang/test/Parser/cxx-ambig-paren-expr.cpp +++ b/clang/test/Parser/cxx-ambig-paren-expr.cpp @@ -70,3 +70,24 @@ return; } +namespace GH64926 { +template +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 '('}} +} +}