More lambda work. Tweak the Sema interface slightly. Start adding the pieces to build the lambda class and its call operator. Create an actual scope for the lambda body.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147595 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eli Friedman 2012-01-05 03:35:19 +00:00
Родитель edb9459c43
Коммит ec9ea72007
10 изменённых файлов: 140 добавлений и 43 удалений

Просмотреть файл

@ -1078,6 +1078,10 @@ public:
getLocalData()->TrailingReturn = Trailing;
}
ArrayRef<ParmVarDecl *> getParams() const {
return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
}
// ParmVarDecls* are stored after Info, one for each argument.
ParmVarDecl **getParmArray() const {
return (ParmVarDecl**) getExtraLocalData();

Просмотреть файл

@ -45,11 +45,17 @@ public:
/// \brief Retains information about a function, method, or block that is
/// currently being parsed.
class FunctionScopeInfo {
protected:
enum ScopeKind {
SK_Function,
SK_Block,
SK_Lambda
};
public:
/// \brief Whether this scope information structure defined information for
/// a block.
bool IsBlockInfo;
/// \brief What kind of scope we are describing.
///
ScopeKind Kind;
/// \brief Whether this function contains a VLA, @try, try, C++
/// initializer, or anything else that can't be jumped past.
@ -96,7 +102,7 @@ public:
}
FunctionScopeInfo(DiagnosticsEngine &Diag)
: IsBlockInfo(false),
: Kind(SK_Function),
HasBranchProtectedScope(false),
HasBranchIntoScope(false),
HasIndirectGoto(false),
@ -141,15 +147,55 @@ public:
: FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope),
CapturesCXXThis(false)
{
IsBlockInfo = true;
Kind = SK_Block;
}
virtual ~BlockScopeInfo();
static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; }
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Block;
}
static bool classof(const BlockScopeInfo *BSI) { return true; }
};
class LambdaScopeInfo : public FunctionScopeInfo {
public:
/// \brief The class that describes the lambda.
CXXRecordDecl *Lambda;
/// \brief A mapping from the set of captured variables to the
/// fields (within the lambda class) that represent the captured variables.
llvm::DenseMap<VarDecl *, FieldDecl *> CapturedVariables;
/// \brief The list of captured variables, starting with the explicit
/// captures and then finishing with any implicit captures.
// TODO: This is commented out until an implementation of LambdaExpr is
// committed.
// llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
/// \brief The number of captures in the \c Captures list that are
/// explicit captures.
unsigned NumExplicitCaptures;
/// \brief The field associated with the captured 'this' pointer.
FieldDecl *ThisCapture;
LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda)
: FunctionScopeInfo(Diag), Lambda(Lambda),
NumExplicitCaptures(0), ThisCapture(0)
{
Kind = SK_Lambda;
}
virtual ~LambdaScopeInfo();
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Lambda;
}
static bool classof(const LambdaScopeInfo *BSI) { return true; }
};
}
}

Просмотреть файл

@ -767,8 +767,9 @@ public:
void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
void PopFunctionOrBlockScope(const sema::AnalysisBasedWarnings::Policy *WP =0,
const Decl *D = 0, const BlockExpr *blkExpr = 0);
void PushLambdaScope(CXXRecordDecl *Lambda);
void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0,
const Decl *D = 0, const BlockExpr *blkExpr = 0);
sema::FunctionScopeInfo *getCurFunction() const {
return FunctionScopes.back();
@ -3449,16 +3450,15 @@ public:
/// initializer for the declaration 'Dcl'.
void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl);
/// ActOnLambdaStart - This callback is invoked when a lambda expression is
/// started.
void ActOnLambdaStart(SourceLocation StartLoc, Scope *CurScope);
/// ActOnLambdaArguments - This callback allows processing of lambda arguments.
/// If there are no arguments, this is still invoked.
void ActOnLambdaArguments(Declarator &ParamInfo, Scope *CurScope);
/// ActOnStartOfLambdaDefinition - This is called just before we start
/// parsing the body of a lambda; it analyzes the explicit captures and
/// arguments, and sets up various data-structures for the body of the
/// lambda.
void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo, Scope *CurScope);
/// ActOnLambdaError - If there is an error parsing a lambda, this callback
/// is invoked to pop the information about the lambda from the action impl.
/// is invoked to pop the information about the lambda.
void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope);
/// ActOnLambdaExpr - This is called when the body of a lambda expression

Просмотреть файл

@ -711,8 +711,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
"lambda expression parsing");
Actions.ActOnLambdaStart(LambdaBeginLoc, getCurScope());
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
Declarator D(DS, Declarator::LambdaExprContext);
@ -792,11 +790,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
// Inform sema that we are starting a block.
Actions.ActOnLambdaArguments(D, getCurScope());
}
Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
// Parse compound-statement.
if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_lambda_body);

Просмотреть файл

@ -55,6 +55,7 @@ void FunctionScopeInfo::Clear() {
}
BlockScopeInfo::~BlockScopeInfo() { }
LambdaScopeInfo::~LambdaScopeInfo() { }
PrintingPolicy Sema::getPrintingPolicy() const {
PrintingPolicy Policy = Context.getPrintingPolicy();
@ -828,8 +829,12 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block));
}
void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
const Decl *D, const BlockExpr *blkExpr) {
void Sema::PushLambdaScope(CXXRecordDecl *Lambda) {
FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda));
}
void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
const Decl *D, const BlockExpr *blkExpr) {
FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");

Просмотреть файл

@ -7207,7 +7207,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (!IsInstantiation)
PopDeclContext();
PopFunctionOrBlockScope(ActivePolicy, dcl);
PopFunctionScopeInfo(ActivePolicy, dcl);
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for

Просмотреть файл

@ -6784,7 +6784,7 @@ namespace {
~ImplicitlyDefinedFunctionScope() {
S.PopExpressionEvaluationContext();
S.PopFunctionOrBlockScope();
S.PopFunctionScopeInfo();
}
};
}

Просмотреть файл

@ -8839,7 +8839,7 @@ void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
// Pop off CurBlock, handle nested blocks.
PopDeclContext();
PopFunctionOrBlockScope();
PopFunctionScopeInfo();
}
/// ActOnBlockStmtExpr - This is called when the body of a block statement
@ -8931,7 +8931,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
// If the block isn't obviously global, i.e. it captures anything at
// all, mark this full-expression as needing a cleanup.

Просмотреть файл

@ -4778,20 +4778,68 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
// Lambdas.
//===----------------------------------------------------------------------===//
void Sema::ActOnLambdaStart(SourceLocation StartLoc, Scope *CurScope) {
// FIXME: Add lambda-scope
// FIXME: PushDeclContext
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo,
Scope *CurScope) {
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isNamespace()))
DC = DC->getParent();
// Enter a new evaluation context to insulate the block from any
// cleanups from the enclosing full-expression.
PushExpressionEvaluationContext(PotentiallyEvaluated);
}
// Start constructing the lambda class.
CXXRecordDecl *Class = CXXRecordDecl::Create(Context, TTK_Class, DC,
Intro.Range.getBegin(),
/*IdLoc=*/SourceLocation(),
/*Id=*/0);
Class->startDefinition();
CurContext->addDecl(Class);
void Sema::ActOnLambdaArguments(Declarator &ParamInfo, Scope *CurScope) {
// Build the call operator; we don't really have all the relevant information
// at this point, but we need something to attach child declarations to.
TypeSourceInfo *MethodTyInfo;
MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
// FIXME: Build CXXMethodDecl
DeclarationName MethodName
= Context.DeclarationNames.getCXXOperatorName(OO_Call);
CXXMethodDecl *Method
= CXXMethodDecl::Create(Context,
Class,
ParamInfo.getSourceRange().getEnd(),
DeclarationNameInfo(MethodName,
/*NameLoc=*/SourceLocation()),
MethodTyInfo->getType(),
MethodTyInfo,
/*isStatic=*/false,
SC_None,
/*isInline=*/true,
/*isConstExpr=*/false,
ParamInfo.getSourceRange().getEnd());
Method->setAccess(AS_public);
Class->addDecl(Method);
Method->setLexicalDeclContext(DC); // FIXME: Is this really correct?
// Set the parameters on the decl, if specified.
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
FunctionProtoTypeLoc Proto =
cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
Method->setParams(Proto.getParams());
CheckParmsForFunctionDef(Method->param_begin(),
Method->param_end(),
/*CheckParameterNames=*/false);
}
ProcessDeclAttributes(CurScope, Method, ParamInfo);
// FIXME: There's a bunch of missing checking etc;
// see ActOnBlockArguments
// Introduce the lambda scope.
PushLambdaScope(Class);
// Enter a new evaluation context to insulate the block from any
// cleanups from the enclosing full-expression.
PushExpressionEvaluationContext(PotentiallyEvaluated);
PushDeclContext(CurScope, Method);
}
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
@ -4800,8 +4848,8 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
PopExpressionEvaluationContext();
// Leave the context of the lambda.
// FIXME: PopDeclContext
// FIXME: Pop lambda-scope
PopDeclContext();
PopFunctionScopeInfo();
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,

Просмотреть файл

@ -14,10 +14,7 @@ class C {
[] {}; // expected-error {{lambda expressions are not supported yet}}
[=] (int i) {}; // expected-error {{lambda expressions are not supported yet}}
[&] (int) mutable -> void {}; // expected-error {{lambda expressions are not supported yet}}
// FIXME: this error occurs because we do not yet handle lambda scopes
// properly. I did not anticipate it because I thought it was a semantic (not
// syntactic) check.
[foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}} expected-error {{lambda expressions are not supported yet}}
[foo,bar] () { return 3; }; // expected-error {{lambda expressions are not supported yet}}
[=,&foo] () {}; // expected-error {{lambda expressions are not supported yet}}
[this] () {}; // expected-error {{lambda expressions are not supported yet}}
}