forked from OSchip/llvm-project
[REFACTOR] Refactored some of the generic-lambda capturing code.
Employed the following refactorings: - Renamed some functions - Introduced explaining variables - Cleaned up & added comments - Used Optional<unsigned> for return value instead of an out parameter - Added assertions - Constified a few member functions No functionality change. All regressions pass. llvm-svn: 196662
This commit is contained in:
parent
080133453b
commit
ab3d646a9d
|
@ -757,7 +757,7 @@ public:
|
|||
|| isa<MemberExpr>(CapturingVarExpr));
|
||||
NonODRUsedCapturingExprs.insert(CapturingVarExpr);
|
||||
}
|
||||
bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) {
|
||||
bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const {
|
||||
assert(isa<DeclRefExpr>(CapturingVarExpr)
|
||||
|| isa<MemberExpr>(CapturingVarExpr));
|
||||
return NonODRUsedCapturingExprs.count(CapturingVarExpr);
|
||||
|
@ -780,13 +780,11 @@ public:
|
|||
return getNumPotentialVariableCaptures() ||
|
||||
PotentialThisCaptureLocation.isValid();
|
||||
}
|
||||
|
||||
// When passed the index, returns the VarDecl and Expr associated
|
||||
// with the index.
|
||||
void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E);
|
||||
|
||||
};
|
||||
|
||||
// When passed the index, returns the VarDecl and Expr associated
|
||||
// with the index.
|
||||
void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const;
|
||||
};
|
||||
|
||||
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
|
||||
: Base(0, false), Property(0) {}
|
||||
|
|
|
@ -19,20 +19,17 @@
|
|||
#include "clang/Sema/ScopeInfo.h"
|
||||
namespace clang {
|
||||
|
||||
// Given a lambda's call operator and a variable (or null for 'this'),
|
||||
// compute the nearest enclosing lambda that is capture-ready (i.e
|
||||
// the enclosing context is not dependent, and all intervening lambdas can
|
||||
// either implicitly or explicitly capture Var)
|
||||
//
|
||||
// Return the CallOperator of the capturable lambda and set function scope
|
||||
// index to the correct index within the function scope stack to correspond
|
||||
// to the capturable lambda.
|
||||
// If VarDecl *VD is null, we check for 'this' capture.
|
||||
CXXMethodDecl*
|
||||
GetInnermostEnclosingCapturableLambda(
|
||||
ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,
|
||||
unsigned &FunctionScopeIndex,
|
||||
DeclContext *const CurContext, VarDecl *VD, Sema &S);
|
||||
|
||||
/// \brief Examines the FunctionScopeInfo stack to determine the nearest
|
||||
/// enclosing lambda (to the current lambda) that is 'capture-capable' for
|
||||
/// the variable referenced in the current lambda (i.e. \p VarToCapture).
|
||||
/// If successful, returns the index into Sema's FunctionScopeInfo stack
|
||||
/// of the capture-capable lambda's LambdaScopeInfo.
|
||||
/// See Implementation for more detailed comments.
|
||||
|
||||
Optional<unsigned> getStackIndexOfNearestEnclosingCaptureCapableLambda(
|
||||
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
|
||||
VarDecl *VarToCapture, Sema &S);
|
||||
|
||||
} // clang
|
||||
|
||||
|
|
|
@ -190,10 +190,11 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
|
|||
ThisUse->markSafe();
|
||||
}
|
||||
|
||||
void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) {
|
||||
void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD,
|
||||
Expr *&E) const {
|
||||
assert(Idx < getNumPotentialVariableCaptures() &&
|
||||
"Index of potential capture must be within 0 to less than the "
|
||||
"number of captures!");
|
||||
"Index of potential capture must be within 0 to less than the "
|
||||
"number of captures!");
|
||||
E = PotentiallyCapturingExprs[Idx];
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
|
||||
VD = dyn_cast<VarDecl>(DRE->getFoundDecl());
|
||||
|
|
|
@ -5868,42 +5868,58 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var,
|
|||
return !IsVariableAConstantExpression(Var, Context);
|
||||
}
|
||||
|
||||
/// \brief Check if the current lambda scope has any potential captures, and
|
||||
/// whether they can be captured by any of the enclosing lambdas that are
|
||||
/// ready to capture. If there is a lambda that can capture a nested
|
||||
/// potential-capture, go ahead and do so. Also, check to see if any
|
||||
/// variables are uncaptureable or do not involve an odr-use so do not
|
||||
/// need to be captured.
|
||||
/// \brief Check if the current lambda has any potential captures
|
||||
/// that must be captured by any of its enclosing lambdas that are ready to
|
||||
/// capture. If there is a lambda that can capture a nested
|
||||
/// potential-capture, go ahead and do so. Also, check to see if any
|
||||
/// variables are uncaptureable or do not involve an odr-use so do not
|
||||
/// need to be captured.
|
||||
|
||||
static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
|
||||
Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) {
|
||||
|
||||
static void CheckLambdaCaptures(Expr *const FE,
|
||||
LambdaScopeInfo *const CurrentLSI, Sema &S) {
|
||||
|
||||
assert(!S.isUnevaluatedContext());
|
||||
assert(S.CurContext->isDependentContext());
|
||||
const bool IsFullExprInstantiationDependent =
|
||||
FE->isInstantiationDependent();
|
||||
// All the potentially captureable variables in the current nested
|
||||
assert(CurrentLSI->CallOperator == S.CurContext &&
|
||||
"The current call operator must be synchronized with Sema's CurContext");
|
||||
|
||||
const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent();
|
||||
|
||||
ArrayRef<const FunctionScopeInfo *> FunctionScopesArrayRef(
|
||||
S.FunctionScopes.data(), S.FunctionScopes.size());
|
||||
|
||||
// All the potentially captureable variables in the current nested
|
||||
// lambda (within a generic outer lambda), must be captured by an
|
||||
// outer lambda that is enclosed within a non-dependent context.
|
||||
|
||||
for (size_t I = 0, N = CurrentLSI->getNumPotentialVariableCaptures();
|
||||
I != N; ++I) {
|
||||
const unsigned NumPotentialCaptures =
|
||||
CurrentLSI->getNumPotentialVariableCaptures();
|
||||
for (unsigned I = 0; I != NumPotentialCaptures; ++I) {
|
||||
Expr *VarExpr = 0;
|
||||
VarDecl *Var = 0;
|
||||
CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);
|
||||
//
|
||||
if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
|
||||
// If the variable is clearly identified as non-odr-used and the full
|
||||
// expression is not instantiation dependent, only then do we not
|
||||
// need to check enclosing lambda's for speculative captures.
|
||||
// For e.g.:
|
||||
// Even though 'x' is not odr-used, it should be captured.
|
||||
// int test() {
|
||||
// const int x = 10;
|
||||
// auto L = [=](auto a) {
|
||||
// (void) +x + a;
|
||||
// };
|
||||
// }
|
||||
if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
|
||||
!IsFullExprInstantiationDependent)
|
||||
continue;
|
||||
// Climb up until we find a lambda that can capture:
|
||||
// - a generic-or-non-generic lambda call operator that is enclosed
|
||||
// within a non-dependent context.
|
||||
unsigned FunctionScopeIndexOfCapturableLambda = 0;
|
||||
if (GetInnermostEnclosingCapturableLambda(
|
||||
S.FunctionScopes, FunctionScopeIndexOfCapturableLambda,
|
||||
S.CurContext, Var, S)) {
|
||||
MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(),
|
||||
S, &FunctionScopeIndexOfCapturableLambda);
|
||||
continue;
|
||||
|
||||
// If we have a capture-capable lambda for the variable, go ahead and
|
||||
// capture the variable in that lambda (and all its enclosing lambdas).
|
||||
if (const Optional<unsigned> Index =
|
||||
getStackIndexOfNearestEnclosingCaptureCapableLambda(
|
||||
FunctionScopesArrayRef, Var, S)) {
|
||||
const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue();
|
||||
MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S,
|
||||
&FunctionScopeIndexOfCapturableLambda);
|
||||
}
|
||||
const bool IsVarNeverAConstantExpression =
|
||||
VariableCanNeverBeAConstantExpression(Var, S.Context);
|
||||
|
@ -5930,16 +5946,21 @@ static void CheckLambdaCaptures(Expr *const FE,
|
|||
}
|
||||
}
|
||||
|
||||
// Check if 'this' needs to be captured.
|
||||
if (CurrentLSI->hasPotentialThisCapture()) {
|
||||
unsigned FunctionScopeIndexOfCapturableLambda = 0;
|
||||
if (GetInnermostEnclosingCapturableLambda(
|
||||
S.FunctionScopes, FunctionScopeIndexOfCapturableLambda,
|
||||
S.CurContext, /*0 is 'this'*/ 0, S)) {
|
||||
S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation,
|
||||
/*Explicit*/false, /*BuildAndDiagnose*/true,
|
||||
&FunctionScopeIndexOfCapturableLambda);
|
||||
// If we have a capture-capable lambda for 'this', go ahead and capture
|
||||
// 'this' in that lambda (and all its enclosing lambdas).
|
||||
if (const Optional<unsigned> Index =
|
||||
getStackIndexOfNearestEnclosingCaptureCapableLambda(
|
||||
FunctionScopesArrayRef, /*0 is 'this'*/ 0, S)) {
|
||||
const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue();
|
||||
S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation,
|
||||
/*Explicit*/ false, /*BuildAndDiagnose*/ true,
|
||||
&FunctionScopeIndexOfCapturableLambda);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset all the potential captures at the end of each full-expression.
|
||||
CurrentLSI->clearPotentialCaptures();
|
||||
}
|
||||
|
||||
|
@ -6036,11 +6057,12 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
|
|||
// FunctionScopes.size() in InstantiatingTemplate's
|
||||
// constructor/destructor.
|
||||
// - Teach the handful of places that iterate over FunctionScopes to
|
||||
// stop at the outermost enclosing lexical scope."
|
||||
const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext);
|
||||
if (IsInLambdaDeclContext && CurrentLSI &&
|
||||
// stop at the outermost enclosing lexical scope."
|
||||
const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext);
|
||||
if (IsInLambdaDeclContext && CurrentLSI &&
|
||||
CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid())
|
||||
CheckLambdaCaptures(FE, CurrentLSI, *this);
|
||||
CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI,
|
||||
*this);
|
||||
return MaybeCreateExprWithCleanups(FullExpr);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,111 +25,203 @@
|
|||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
||||
// returns -1 if none of the lambdas on the scope stack can capture.
|
||||
// A lambda 'L' is capture-ready for a certain variable 'V' if,
|
||||
// - its enclosing context is non-dependent
|
||||
// - and if the chain of lambdas between L and the lambda in which
|
||||
// V is potentially used, call all capture or have captured V.
|
||||
static inline int GetScopeIndexOfNearestCaptureReadyLambda(
|
||||
ArrayRef<clang::sema::FunctionScopeInfo*> FunctionScopes,
|
||||
DeclContext *const CurContext, VarDecl *VD) {
|
||||
/// \brief Examines the FunctionScopeInfo stack to determine the nearest
|
||||
/// enclosing lambda (to the current lambda) that is 'capture-ready' for
|
||||
/// the variable referenced in the current lambda (i.e. \p VarToCapture).
|
||||
/// If successful, returns the index into Sema's FunctionScopeInfo stack
|
||||
/// of the capture-ready lambda's LambdaScopeInfo.
|
||||
///
|
||||
/// Climbs down the stack of lambdas (deepest nested lambda - i.e. current
|
||||
/// lambda - is on top) to determine the index of the nearest enclosing/outer
|
||||
/// lambda that is ready to capture the \p VarToCapture being referenced in
|
||||
/// the current lambda.
|
||||
/// As we climb down the stack, we want the index of the first such lambda -
|
||||
/// that is the lambda with the highest index that is 'capture-ready'.
|
||||
///
|
||||
/// A lambda 'L' is capture-ready for 'V' (var or this) if:
|
||||
/// - its enclosing context is non-dependent
|
||||
/// - and if the chain of lambdas between L and the lambda in which
|
||||
/// V is potentially used (i.e. the lambda at the top of the scope info
|
||||
/// stack), can all capture or have already captured V.
|
||||
/// If \p VarToCapture is 'null' then we are trying to capture 'this'.
|
||||
///
|
||||
/// Note that a lambda that is deemed 'capture-ready' still needs to be checked
|
||||
/// for whether it is 'capture-capable' (see
|
||||
/// getStackIndexOfNearestEnclosingCaptureCapableLambda), before it can truly
|
||||
/// capture.
|
||||
///
|
||||
/// \param FunctionScopes - Sema's stack of nested FunctionScopeInfo's (which a
|
||||
/// LambdaScopeInfo inherits from). The current/deepest/innermost lambda
|
||||
/// is at the top of the stack and has the highest index.
|
||||
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
|
||||
///
|
||||
/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
|
||||
/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
|
||||
/// which is capture-ready. If the return value evaluates to 'false' then
|
||||
/// no lambda is capture-ready for \p VarToCapture.
|
||||
|
||||
static inline Optional<unsigned>
|
||||
getStackIndexOfNearestEnclosingCaptureReadyLambda(
|
||||
ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes,
|
||||
VarDecl *VarToCapture) {
|
||||
// Label failure to capture.
|
||||
const Optional<unsigned> NoLambdaIsCaptureReady;
|
||||
|
||||
assert(
|
||||
isa<clang::sema::LambdaScopeInfo>(
|
||||
FunctionScopes[FunctionScopes.size() - 1]) &&
|
||||
"The function on the top of sema's function-info stack must be a lambda");
|
||||
|
||||
DeclContext *EnclosingDC = CurContext;
|
||||
// If VD is null, we are attempting to capture 'this'
|
||||
const bool IsCapturingThis = !VD;
|
||||
// If VarToCapture is null, we are attempting to capture 'this'.
|
||||
const bool IsCapturingThis = !VarToCapture;
|
||||
const bool IsCapturingVariable = !IsCapturingThis;
|
||||
int RetIndex = -1;
|
||||
|
||||
// Start with the current lambda at the top of the stack (highest index).
|
||||
unsigned CurScopeIndex = FunctionScopes.size() - 1;
|
||||
while (!EnclosingDC->isTranslationUnit() &&
|
||||
EnclosingDC->isDependentContext() && isLambdaCallOperator(EnclosingDC)) {
|
||||
RetIndex = CurScopeIndex;
|
||||
clang::sema::LambdaScopeInfo *LSI =
|
||||
cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]);
|
||||
// We have crawled up to an intervening lambda that contains the
|
||||
// variable declaration - so not only does it not need to capture;
|
||||
// none of the enclosing lambdas need to capture it, and since all
|
||||
// other nested lambdas are dependent (otherwise we wouldn't have
|
||||
// arrived here) - we don't yet have a lambda that can capture the
|
||||
DeclContext *EnclosingDC =
|
||||
cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex])->CallOperator;
|
||||
|
||||
do {
|
||||
const clang::sema::LambdaScopeInfo *LSI =
|
||||
cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]);
|
||||
// IF we have climbed down to an intervening enclosing lambda that contains
|
||||
// the variable declaration - it obviously can/must not capture the
|
||||
// variable.
|
||||
if (IsCapturingVariable && VD->getDeclContext()->Equals(EnclosingDC))
|
||||
return -1;
|
||||
// All intervening lambda call operators have to be able to capture.
|
||||
// Since its enclosing DC is dependent, all the lambdas between it and the
|
||||
// innermost nested lambda are dependent (otherwise we wouldn't have
|
||||
// arrived here) - so we don't yet have a lambda that can capture the
|
||||
// variable.
|
||||
if (IsCapturingVariable &&
|
||||
VarToCapture->getDeclContext()->Equals(EnclosingDC))
|
||||
return NoLambdaIsCaptureReady;
|
||||
|
||||
// For an enclosing lambda to be capture ready for an entity, all
|
||||
// intervening lambda's have to be able to capture that entity. If even
|
||||
// one of the intervening lambda's is not capable of capturing the entity
|
||||
// then no enclosing lambda can ever capture that entity.
|
||||
// For e.g.
|
||||
// const int x = 10;
|
||||
// [=](auto a) { #1
|
||||
// [](auto b) { #2 <-- an intervening lambda that can never capture 'x'
|
||||
// [=](auto c) { #3
|
||||
// f(x, c); <-- can not lead to x's speculative capture by #1 or #2
|
||||
// }; }; };
|
||||
// If they do not have a default implicit capture, check to see
|
||||
// if the entity has already been explicitly captured.
|
||||
// If even a single dependent enclosing lambda lacks the capability
|
||||
// to ever capture this variable, there is no further enclosing
|
||||
// If even a single dependent enclosing lambda lacks the capability
|
||||
// to ever capture this variable, there is no further enclosing
|
||||
// non-dependent lambda that can capture this variable.
|
||||
if (LSI->ImpCaptureStyle == sema::LambdaScopeInfo::ImpCap_None) {
|
||||
if (IsCapturingVariable && !LSI->isCaptured(VD))
|
||||
return -1;
|
||||
if (IsCapturingVariable && !LSI->isCaptured(VarToCapture))
|
||||
return NoLambdaIsCaptureReady;
|
||||
if (IsCapturingThis && !LSI->isCXXThisCaptured())
|
||||
return -1;
|
||||
return NoLambdaIsCaptureReady;
|
||||
}
|
||||
EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC);
|
||||
|
||||
assert(CurScopeIndex);
|
||||
--CurScopeIndex;
|
||||
}
|
||||
// If the enclosingDC is not dependent, then the immediately nested lambda
|
||||
// is capture-ready.
|
||||
if (!EnclosingDC->isDependentContext())
|
||||
return RetIndex;
|
||||
return -1;
|
||||
}
|
||||
// Given a lambda's call operator and a variable (or null for 'this'),
|
||||
// compute the nearest enclosing lambda that is capture-ready (i.e
|
||||
// the enclosing context is not dependent, and all intervening lambdas can
|
||||
// either implicitly or explicitly capture Var)
|
||||
//
|
||||
// The approach is as follows, for the entity VD ('this' if null):
|
||||
// - start with the current lambda
|
||||
// - if it is non-dependent and can capture VD, return it.
|
||||
// - if it is dependent and has an implicit or explicit capture, check its parent
|
||||
// whether the parent is non-depdendent and all its intervening lambdas
|
||||
// can capture, if so return the child.
|
||||
// [Note: When we hit a generic lambda specialization, do not climb up
|
||||
// the scope stack any further since not only do we not need to,
|
||||
// the scope stack will often not be synchronized with any lambdas
|
||||
// enclosing the specialized generic lambda]
|
||||
//
|
||||
// Return the CallOperator of the capturable lambda and set function scope
|
||||
// index to the correct index within the function scope stack to correspond
|
||||
// to the capturable lambda.
|
||||
// If VarDecl *VD is null, we check for 'this' capture.
|
||||
CXXMethodDecl* clang::GetInnermostEnclosingCapturableLambda(
|
||||
ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,
|
||||
unsigned &FunctionScopeIndex,
|
||||
DeclContext *const CurContext, VarDecl *VD,
|
||||
Sema &S) {
|
||||
} while (!EnclosingDC->isTranslationUnit() &&
|
||||
EnclosingDC->isDependentContext() &&
|
||||
isLambdaCallOperator(EnclosingDC));
|
||||
|
||||
const int IndexOfCaptureReadyLambda =
|
||||
GetScopeIndexOfNearestCaptureReadyLambda(FunctionScopes,CurContext, VD);
|
||||
if (IndexOfCaptureReadyLambda == -1) return 0;
|
||||
assert(IndexOfCaptureReadyLambda >= 0);
|
||||
const unsigned IndexOfCaptureReadyLambdaU =
|
||||
static_cast<unsigned>(IndexOfCaptureReadyLambda);
|
||||
sema::LambdaScopeInfo *const CaptureReadyLambdaLSI =
|
||||
cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambdaU]);
|
||||
// If VD is null, we are attempting to capture 'this'
|
||||
const bool IsCapturingThis = !VD;
|
||||
assert(CurScopeIndex < (FunctionScopes.size() - 1));
|
||||
// If the enclosingDC is not dependent, then the immediately nested lambda
|
||||
// (one index above) is capture-ready.
|
||||
if (!EnclosingDC->isDependentContext())
|
||||
return CurScopeIndex + 1;
|
||||
return NoLambdaIsCaptureReady;
|
||||
}
|
||||
|
||||
/// \brief Examines the FunctionScopeInfo stack to determine the nearest
|
||||
/// enclosing lambda (to the current lambda) that is 'capture-capable' for
|
||||
/// the variable referenced in the current lambda (i.e. \p VarToCapture).
|
||||
/// If successful, returns the index into Sema's FunctionScopeInfo stack
|
||||
/// of the capture-capable lambda's LambdaScopeInfo.
|
||||
///
|
||||
/// Given the current stack of lambdas being processed by Sema and
|
||||
/// the variable of interest, to identify the nearest enclosing lambda (to the
|
||||
/// current lambda at the top of the stack) that can truly capture
|
||||
/// a variable, it has to have the following two properties:
|
||||
/// a) 'capture-ready' - be the innermost lambda that is 'capture-ready':
|
||||
/// - climb down the stack (i.e. starting from the innermost and examining
|
||||
/// each outer lambda step by step) checking if each enclosing
|
||||
/// lambda can either implicitly or explicitly capture the variable.
|
||||
/// Record the first such lambda that is enclosed in a non-dependent
|
||||
/// context. If no such lambda currently exists return failure.
|
||||
/// b) 'capture-capable' - make sure the 'capture-ready' lambda can truly
|
||||
/// capture the variable by checking all its enclosing lambdas:
|
||||
/// - check if all outer lambdas enclosing the 'capture-ready' lambda
|
||||
/// identified above in 'a' can also capture the variable (this is done
|
||||
/// via tryCaptureVariable for variables and CheckCXXThisCapture for
|
||||
/// 'this' by passing in the index of the Lambda identified in step 'a')
|
||||
///
|
||||
/// \param FunctionScopes - Sema's stack of nested FunctionScopeInfo's (which a
|
||||
/// LambdaScopeInfo inherits from). The current/deepest/innermost lambda
|
||||
/// is at the top of the stack.
|
||||
///
|
||||
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
|
||||
///
|
||||
///
|
||||
/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
|
||||
/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
|
||||
/// which is capture-capable. If the return value evaluates to 'false' then
|
||||
/// no lambda is capture-capable for \p VarToCapture.
|
||||
|
||||
Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
|
||||
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
|
||||
VarDecl *VarToCapture, Sema &S) {
|
||||
|
||||
const Optional<unsigned> FailDistance;
|
||||
|
||||
const Optional<unsigned> OptionalStackIndex =
|
||||
getStackIndexOfNearestEnclosingCaptureReadyLambda(FunctionScopes,
|
||||
VarToCapture);
|
||||
if (!OptionalStackIndex)
|
||||
return FailDistance;
|
||||
|
||||
const unsigned IndexOfCaptureReadyLambda = OptionalStackIndex.getValue();
|
||||
assert(
|
||||
((IndexOfCaptureReadyLambda != (FunctionScopes.size() - 1)) ||
|
||||
(S.getCurGenericLambda() && S.getCurGenericLambda()->ImpCaptureStyle !=
|
||||
sema::LambdaScopeInfo::ImpCap_None)) &&
|
||||
"The capture ready lambda for a potential capture can only be the "
|
||||
"current lambda if it is a generic lambda with an implicit capture");
|
||||
|
||||
const sema::LambdaScopeInfo *const CaptureReadyLambdaLSI =
|
||||
cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambda]);
|
||||
|
||||
// If VarToCapture is null, we are attempting to capture 'this'
|
||||
const bool IsCapturingThis = !VarToCapture;
|
||||
const bool IsCapturingVariable = !IsCapturingThis;
|
||||
|
||||
if (IsCapturingVariable) {
|
||||
// Now check to see if this lambda can truly capture, and also
|
||||
// if all enclosing lambdas of this lambda allow this capture.
|
||||
// Check if the capture-ready lambda can truly capture the variable, by
|
||||
// checking whether all enclosing lambdas of the capture-ready lambda allow
|
||||
// the capture - i.e. make sure it is capture-capable.
|
||||
QualType CaptureType, DeclRefType;
|
||||
const bool CanCaptureVariable = !S.tryCaptureVariable(VD,
|
||||
/*ExprVarIsUsedInLoc*/SourceLocation(), clang::Sema::TryCapture_Implicit,
|
||||
/*EllipsisLoc*/ SourceLocation(),
|
||||
/*BuildAndDiagnose*/false, CaptureType, DeclRefType,
|
||||
&IndexOfCaptureReadyLambdaU);
|
||||
if (!CanCaptureVariable) return 0;
|
||||
} else {
|
||||
const bool CanCaptureThis = !S.CheckCXXThisCapture(
|
||||
CaptureReadyLambdaLSI->PotentialThisCaptureLocation, false, false,
|
||||
&IndexOfCaptureReadyLambdaU);
|
||||
if (!CanCaptureThis) return 0;
|
||||
} // end 'this' capture test
|
||||
FunctionScopeIndex = IndexOfCaptureReadyLambdaU;
|
||||
return CaptureReadyLambdaLSI->CallOperator;
|
||||
const bool CanCaptureVariable =
|
||||
!S.tryCaptureVariable(VarToCapture,
|
||||
/*ExprVarIsUsedInLoc*/ SourceLocation(),
|
||||
clang::Sema::TryCapture_Implicit,
|
||||
/*EllipsisLoc*/ SourceLocation(),
|
||||
/*BuildAndDiagnose*/ false, CaptureType,
|
||||
DeclRefType, &IndexOfCaptureReadyLambda);
|
||||
if (!CanCaptureVariable)
|
||||
return FailDistance;
|
||||
} else {
|
||||
// Check if the capture-ready lambda can truly capture 'this' by checking
|
||||
// whether all enclosing lambdas of the capture-ready lambda can capture
|
||||
// 'this'.
|
||||
const bool CanCaptureThis =
|
||||
!S.CheckCXXThisCapture(
|
||||
CaptureReadyLambdaLSI->PotentialThisCaptureLocation,
|
||||
/*Explicit*/ false, /*BuildAndDiagnose*/ false,
|
||||
&IndexOfCaptureReadyLambda);
|
||||
if (!CanCaptureThis)
|
||||
return FailDistance;
|
||||
}
|
||||
return IndexOfCaptureReadyLambda;
|
||||
}
|
||||
|
||||
static inline TemplateParameterList *
|
||||
|
@ -142,17 +234,14 @@ getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
|
|||
SourceLocation LAngleLoc = IntroRange.getBegin();
|
||||
SourceLocation RAngleLoc = IntroRange.getEnd();
|
||||
LSI->GLTemplateParameterList = TemplateParameterList::Create(
|
||||
SemaRef.Context,
|
||||
/*Template kw loc*/SourceLocation(),
|
||||
LAngleLoc,
|
||||
(NamedDecl**)LSI->AutoTemplateParams.data(),
|
||||
LSI->AutoTemplateParams.size(), RAngleLoc);
|
||||
SemaRef.Context,
|
||||
/*Template kw loc*/ SourceLocation(), LAngleLoc,
|
||||
(NamedDecl **)LSI->AutoTemplateParams.data(),
|
||||
LSI->AutoTemplateParams.size(), RAngleLoc);
|
||||
}
|
||||
return LSI->GLTemplateParameterList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
|
||||
TypeSourceInfo *Info,
|
||||
bool KnownDependent,
|
||||
|
|
Loading…
Reference in New Issue