Keep track of the set of array index variables we use when we

synthesize a by-copy captured array in a lambda. This information will
be needed by IR generation.

llvm-svn: 150396
This commit is contained in:
Douglas Gregor 2012-02-13 16:35:30 +00:00
parent f299a55482
commit 54fcea6e16
7 changed files with 92 additions and 15 deletions

View File

@ -561,7 +561,8 @@ class CXXRecordDecl : public RecordDecl {
typedef LambdaExpr::Capture Capture;
LambdaDefinitionData(CXXRecordDecl *D)
: DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0), Extra(0) {
: DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0),
HasArrayIndexVars(false), Extra(0) {
IsLambda = true;
}
@ -569,15 +570,22 @@ class CXXRecordDecl : public RecordDecl {
unsigned NumCaptures : 16;
/// \brief The number of explicit captures in this lambda.
unsigned NumExplicitCaptures : 16;
unsigned NumExplicitCaptures : 15;
/// \brief Whether This lambda has any by-copy array captures, and therefore
/// has array index variables.
unsigned HasArrayIndexVars : 1;
/// \brief The "extra" data associated with the lambda, including
/// captures, capture initializers, and the body of the lambda.
/// captures, capture initializers, the body of the lambda, and the
/// array-index variables for array captures.
void *Extra;
/// \brief Allocate the "extra" data associated with a lambda definition.
void allocateExtra(ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
Stmt *Body);
/// \brief Retrieve the set of captures.
@ -588,6 +596,18 @@ class CXXRecordDecl : public RecordDecl {
Stmt **getStoredStmts() const {
return reinterpret_cast<Stmt **>(getCaptures() + NumCaptures);
}
/// \brief Retrieve the mapping from captures to the first array index
/// variable.
unsigned *getArrayIndexStarts() const {
return reinterpret_cast<unsigned *>(getStoredStmts() + NumCaptures + 1);
}
/// \brief Retrieve the complete set of array-index variables.
VarDecl **getArrayIndexVars() const {
return reinterpret_cast<VarDecl **>(
getArrayIndexStarts() + NumCaptures + 1);
}
};
struct DefinitionData &data() {

View File

@ -1066,22 +1066,16 @@ class LambdaExpr : public Expr {
/// module file just to determine the source range.
SourceLocation ClosingBrace;
// Note: The Create method allocates storage after the LambdaExpr
// object, which contains the captures, followed by the capture
// initializers, and finally the body of the lambda. The capture
// initializers and lambda body are placed next to each other so
// that the children() function can visit all of them easily.
public:
/// \brief Describes the capture of either a variable or 'this'.
class Capture {
llvm::PointerIntPair<VarDecl *, 2> VarAndBits;
SourceLocation Loc;
SourceLocation EllipsisLoc;
friend class ASTStmtReader;
friend class ASTStmtWriter;
public:
/// \brief Create a new capture.
///
@ -1155,6 +1149,8 @@ private:
ArrayRef<Capture> Captures,
bool ExplicitParams,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace);
public:
@ -1166,6 +1162,8 @@ public:
ArrayRef<Capture> Captures,
bool ExplicitParams,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace);
/// \brief Determine the default capture kind for this lambda.
@ -1212,6 +1210,13 @@ public:
/// initialization argument for this lambda expression.
capture_init_iterator capture_init_end() const;
/// \brief Retrieve the set of index variables used in the capture
/// initializer of an array captured by copy.
///
/// \param Iter The iterator that points at the capture initializer for
/// which we are extracting the corresponding index variables.
ArrayRef<VarDecl *> getCaptureInitIndexVars(capture_init_iterator Iter) const;
/// \brief Retrieve the source range covering the lambda introducer,
/// which contains the explicit capture list surrounded by square
/// brackets ([...]).

View File

@ -301,6 +301,13 @@ public:
/// \brief Whether any of the capture expressions requires cleanups.
bool ExprNeedsCleanups;
/// \brief Variables used to index into by-copy array captures.
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
/// \brief Offsets into the ArrayIndexVars array at which each capture starts
/// its list of array index variables.
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
CXXMethodDecl *CallOperator)
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),

View File

@ -38,13 +38,23 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void CXXRecordDecl::LambdaDefinitionData::allocateExtra(
ArrayRef<LambdaExpr::Capture> Captures,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
Stmt *Body) {
NumCaptures = Captures.size();
NumExplicitCaptures = 0;
ASTContext &Context = Definition->getASTContext();
unsigned ArrayIndexSize = 0;
if (ArrayIndexVars.size() > 0) {
HasArrayIndexVars = true;
ArrayIndexSize = sizeof(unsigned) * (Captures.size() + 1)
+ sizeof(VarDecl *) * ArrayIndexVars.size();
}
this->Extra = Context.Allocate(sizeof(Capture) * Captures.size() +
sizeof(Stmt*) * (Captures.size() + 1));
sizeof(Stmt*) * (Captures.size() + 1) +
ArrayIndexSize);
// Copy captures.
Capture *ToCapture = getCaptures();
@ -62,6 +72,15 @@ void CXXRecordDecl::LambdaDefinitionData::allocateExtra(
// Copy the body of the lambda.
*Stored++ = Body;
if (ArrayIndexVars.size() > 0) {
assert(ArrayIndexStarts.size() == Captures.size());
memcpy(getArrayIndexVars(), ArrayIndexVars.data(),
sizeof(VarDecl *) * ArrayIndexVars.size());
memcpy(getArrayIndexStarts(), ArrayIndexStarts.data(),
sizeof(unsigned) * Captures.size());
getArrayIndexStarts()[Captures.size()] = ArrayIndexVars.size();
}
}

View File

@ -753,6 +753,8 @@ LambdaExpr::LambdaExpr(QualType T,
ArrayRef<Capture> Captures,
bool ExplicitParams,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayElementVars,
ArrayRef<unsigned> ArrayElementStarts,
SourceLocation ClosingBrace)
: Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
T->isDependentType(), T->isDependentType(), T->isDependentType(),
@ -765,7 +767,8 @@ LambdaExpr::LambdaExpr(QualType T,
assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
CXXRecordDecl *Class = getLambdaClass();
CXXRecordDecl::LambdaDefinitionData &Data = Class->getLambdaData();
Data.allocateExtra(Captures, CaptureInits, getCallOperator()->getBody());
Data.allocateExtra(Captures, CaptureInits, ArrayElementVars,
ArrayElementStarts, getCallOperator()->getBody());
// FIXME: Propagate "has unexpanded parameter pack" bit.
}
@ -777,6 +780,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
ArrayRef<Capture> Captures,
bool ExplicitParams,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayElementVars,
ArrayRef<unsigned> ArrayElementStarts,
SourceLocation ClosingBrace) {
// Determine the type of the expression (i.e., the type of the
// function object we're creating).
@ -784,6 +789,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
return new (Context) LambdaExpr(T, IntroducerRange, CaptureDefault,
Captures, ExplicitParams, CaptureInits,
ArrayElementVars, ArrayElementStarts,
ClosingBrace);
}
@ -826,6 +832,19 @@ LambdaExpr::capture_init_iterator LambdaExpr::capture_init_end() const {
return reinterpret_cast<Expr **>(Data.getStoredStmts() + Data.NumCaptures);
}
ArrayRef<VarDecl *>
LambdaExpr::getCaptureInitIndexVars(capture_init_iterator Iter) const {
CXXRecordDecl::LambdaDefinitionData &Data = getLambdaClass()->getLambdaData();
assert(Data.HasArrayIndexVars && "No array index-var data?");
unsigned Index = Iter - capture_init_begin();
assert(Index < Data.NumCaptures && "Capture index out-of-range");
VarDecl **IndexVars = Data.getArrayIndexVars();
unsigned *IndexStarts = Data.getArrayIndexStarts();
return ArrayRef<VarDecl *>(IndexVars + IndexStarts[Index],
IndexVars + IndexStarts[Index + 1]);
}
CXXRecordDecl *LambdaExpr::getLambdaClass() const {
return getType()->getAsCXXRecordDecl();
}

View File

@ -9642,6 +9642,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
bool InitializingArray = false;
QualType BaseType = FieldType;
QualType SizeType = S.Context.getSizeType();
LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
while (const ConstantArrayType *Array
= S.Context.getAsConstantArrayType(BaseType)) {
InitializingArray = true;
@ -9660,7 +9661,8 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
SC_None, SC_None);
IndexVariables.push_back(IterationVar);
LSI->ArrayIndexVars.push_back(IterationVar);
// Create a reference to the iteration variable.
ExprResult IterationVarRef
= S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);

View File

@ -306,6 +306,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
SourceRange IntroducerRange;
bool ExplicitParams;
bool LambdaExprNeedsCleanups;
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
{
LambdaScopeInfo *LSI = getCurLambda();
CallOperator = LSI->CallOperator;
@ -313,7 +315,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
IntroducerRange = LSI->IntroducerRange;
ExplicitParams = LSI->ExplicitParams;
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
ArrayIndexVars.swap(LSI->ArrayIndexVars);
ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
// Translate captures.
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
LambdaScopeInfo::Capture From = LSI->Captures[I];
@ -467,6 +471,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
CaptureDefault, Captures,
ExplicitParams, CaptureInits,
ArrayIndexVars, ArrayIndexStarts,
Body->getLocEnd());
// C++11 [expr.prim.lambda]p2: