diff options
author | Faisal Vali <faisalv@yahoo.com> | 2013-12-05 01:40:41 +0000 |
---|---|---|
committer | Faisal Vali <faisalv@yahoo.com> | 2013-12-05 01:40:41 +0000 |
commit | 5fb7c3c4ed4415809ce877113d0850ad4ae61169 (patch) | |
tree | efe9ea79ad01fe212629ed85fe0c68b750b03012 /clang/lib/Sema/TreeTransform.h | |
parent | 3252fd0d5be322cd5172126c30ebdedf88f4ef4b (diff) | |
download | bcm5719-llvm-5fb7c3c4ed4415809ce877113d0850ad4ae61169.tar.gz bcm5719-llvm-5fb7c3c4ed4415809ce877113d0850ad4ae61169.zip |
Fix init-captures for generic lambdas.
For 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.
Make sure TranformLambdaExpr is also aware of this.
Patch approved by Richard (Thanks!!)
http://llvm-reviews.chandlerc.com/D2092
llvm-svn: 196454
Diffstat (limited to 'clang/lib/Sema/TreeTransform.h')
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 80 |
1 files changed, 53 insertions, 27 deletions
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index e9cb95006fe..aa25cbe163a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -593,9 +593,11 @@ public: StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E); - + + typedef std::pair<ExprResult, QualType> InitCaptureInfoTy; /// \brief Transform the captures and body of a lambda expression. - ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator); + ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator, + ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes); TemplateParameterList *TransformTemplateParameterList( TemplateParameterList *TPL) { @@ -8263,7 +8265,40 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> ExprResult TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { - + + // Transform any init-capture expressions before entering the scope of the + // lambda body, because they are not semantically within that scope. + SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes; + InitCaptureExprsAndTypes.resize(E->explicit_capture_end() - + E->explicit_capture_begin()); + + for (LambdaExpr::capture_iterator C = E->capture_begin(), + CEnd = E->capture_end(); + C != CEnd; ++C) { + if (!C->isInitCapture()) + continue; + EnterExpressionEvaluationContext EEEC(getSema(), + Sema::PotentiallyEvaluated); + ExprResult NewExprInitResult = getDerived().TransformInitializer( + C->getCapturedVar()->getInit(), + C->getCapturedVar()->getInitStyle() == VarDecl::CallInit); + + if (NewExprInitResult.isInvalid()) + return ExprError(); + Expr *NewExprInit = NewExprInitResult.get(); + + VarDecl *OldVD = C->getCapturedVar(); + QualType NewInitCaptureType = + getSema().performLambdaInitCaptureInitialization(C->getLocation(), + OldVD->getType()->isReferenceType(), OldVD->getIdentifier(), + NewExprInit); + NewExprInitResult = NewExprInit; + VarDecl *NewVD = 0; + InitCaptureExprsAndTypes[C - E->capture_begin()] = + std::make_pair(NewExprInitResult, NewInitCaptureType); + + } + LambdaScopeInfo *LSI = getSema().PushLambdaScope(); // Transform the template parameters, and add them to the current // instantiation scope. The null case is handled correctly. @@ -8358,31 +8393,17 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); - return getDerived().TransformLambdaScope(E, NewCallOperator); + return getDerived().TransformLambdaScope(E, NewCallOperator, + InitCaptureExprsAndTypes); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, - CXXMethodDecl *CallOperator) { + CXXMethodDecl *CallOperator, + ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) { bool Invalid = false; - // Transform any init-capture expressions before entering the scope of the - // lambda. - SmallVector<ExprResult, 8> InitCaptureExprs; - InitCaptureExprs.resize(E->explicit_capture_end() - - E->explicit_capture_begin()); - for (LambdaExpr::capture_iterator C = E->capture_begin(), - CEnd = E->capture_end(); - C != CEnd; ++C) { - if (!C->isInitCapture()) - continue; - InitCaptureExprs[C - E->capture_begin()] = - getDerived().TransformInitializer( - C->getCapturedVar()->getInit(), - C->getCapturedVar()->getInitStyle() == VarDecl::CallInit); - } - // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), CallOperator); @@ -8415,19 +8436,24 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, // Rebuild init-captures, including the implied field declaration. if (C->isInitCapture()) { - ExprResult Init = InitCaptureExprs[C - E->capture_begin()]; - if (Init.isInvalid()) { + + InitCaptureInfoTy InitExprTypePair = + InitCaptureExprsAndTypes[C - E->capture_begin()]; + ExprResult Init = InitExprTypePair.first; + QualType InitQualType = InitExprTypePair.second; + if (Init.isInvalid() || InitQualType.isNull()) { Invalid = true; continue; } VarDecl *OldVD = C->getCapturedVar(); - VarDecl *NewVD = getSema().checkInitCapture( - C->getLocation(), OldVD->getType()->isReferenceType(), - OldVD->getIdentifier(), Init.take()); + VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl( + OldVD->getLocation(), InitExprTypePair.second, + OldVD->getIdentifier(), Init.get()); if (!NewVD) Invalid = true; - else + else { getDerived().transformedLocalDecl(OldVD, NewVD); + } getSema().buildInitCaptureField(LSI, NewVD); continue; } |