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