summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse/ParseExprCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Parse/ParseExprCXX.cpp')
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp65
1 files changed, 59 insertions, 6 deletions
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 9489b4787e2..3f6d36c8b8d 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -637,8 +637,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
ExprResult Parser::ParseLambdaExpression() {
// Parse lambda-introducer.
LambdaIntroducer Intro;
-
- Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ Optional<unsigned> DiagID = ParseLambdaIntroducer(Intro);
if (DiagID) {
Diag(Tok, DiagID.getValue());
SkipUntil(tok::r_square, StopAtSemi);
@@ -678,7 +677,7 @@ ExprResult Parser::TryParseLambdaExpression() {
if (Next.is(tok::identifier) && After.is(tok::identifier)) {
return ExprEmpty();
}
-
+
// Here, we're stuck: lambda introducers and Objective-C message sends are
// unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a
// lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of
@@ -688,6 +687,7 @@ ExprResult Parser::TryParseLambdaExpression() {
LambdaIntroducer Intro;
if (TryParseLambdaIntroducer(Intro))
return ExprEmpty();
+
return ParseLambdaExpressionAfterIntroducer(Intro);
}
@@ -813,6 +813,11 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
Exprs);
}
} else if (Tok.is(tok::l_brace) || Tok.is(tok::equal)) {
+ // Each lambda init-capture forms its own full expression, which clears
+ // Actions.MaybeODRUseExprs. So create an expression evaluation context
+ // to save the necessary state, and restore it later.
+ EnterExpressionEvaluationContext EC(Actions,
+ Sema::PotentiallyEvaluated);
if (Tok.is(tok::equal))
ConsumeToken();
@@ -866,13 +871,61 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
} else if (Tok.is(tok::ellipsis))
EllipsisLoc = ConsumeToken();
}
-
- Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init);
+ // If this is an init capture, process the initialization expression
+ // right away. For lambda init-captures such as the following:
+ // const int x = 10;
+ // auto L = [i = x+1](int a) {
+ // return [j = x+2,
+ // &k = x](char b) { };
+ // };
+ // keep in mind that each lambda init-capture has to have:
+ // - its initialization expression executed in the context
+ // of the enclosing/parent decl-context.
+ // - but the variable itself has to be 'injected' into the
+ // decl-context of its lambda's call-operator (which has
+ // not yet been created).
+ // Each init-expression is a full-expression that has to get
+ // Sema-analyzed (for capturing etc.) before its lambda's
+ // call-operator's decl-context, scope & scopeinfo are pushed on their
+ // respective stacks. Thus if any variable is odr-used in the init-capture
+ // it will correctly get captured in the enclosing lambda, if one exists.
+ // The init-variables above are created later once the lambdascope and
+ // call-operators decl-context is pushed onto its respective stack.
+
+ // Since the lambda init-capture's initializer expression occurs in the
+ // context of the enclosing function or lambda, therefore we can not wait
+ // till a lambda scope has been pushed on before deciding whether the
+ // variable needs to be captured. We also need to process all
+ // lvalue-to-rvalue conversions and discarded-value conversions,
+ // so that we can avoid capturing certain constant variables.
+ // For e.g.,
+ // void test() {
+ // const int x = 10;
+ // auto L = [&z = x](char a) { <-- don't capture by the current lambda
+ // return [y = x](int i) { <-- don't capture by enclosing lambda
+ // return y;
+ // }
+ // };
+ // If x was not const, the second use would require 'L' to capture, and
+ // that would be an error.
+
+ ParsedType InitCaptureParsedType;
+ if (Init.isUsable()) {
+ // Get the pointer and store it in an lvalue, so we can use it as an
+ // out argument.
+ Expr *InitExpr = Init.get();
+ // This performs any lvalue-to-rvalue conversions if necessary, which
+ // can affect what gets captured in the containing decl-context.
+ QualType InitCaptureType = Actions.performLambdaInitCaptureInitialization(
+ Loc, Kind == LCK_ByRef, Id, InitExpr);
+ Init = InitExpr;
+ InitCaptureParsedType.set(InitCaptureType);
+ }
+ Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init, InitCaptureParsedType);
}
T.consumeClose();
Intro.Range.setEnd(T.getCloseLocation());
-
return DiagResult();
}
OpenPOWER on IntegriCloud