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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits