Stub out the Sema interface for lambda expressions, and change the parser to use it. Unconditionally error on lambda expressions because they don't work in any meaningful way yet.

llvm-svn: 147515
This commit is contained in:
Eli Friedman 2012-01-04 02:40:39 +00:00
parent cc1d7893d6
commit c7c97144af
9 changed files with 118 additions and 33 deletions

View File

@ -3984,6 +3984,8 @@ def err_throw_incomplete_ptr : Error<
def err_return_in_constructor_handler : Error<
"return in the catch of a function try block of a constructor is illegal">;
def err_lambda_unsupported : Error<"lambda expressions are not supported yet">;
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
def err_pseudo_dtor_base_not_scalar : Error<

View File

@ -3449,6 +3449,23 @@ 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);
/// ActOnLambdaError - If there is an error parsing a lambda, this callback
/// is invoked to pop the information about the lambda from the action impl.
void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope);
/// ActOnLambdaExpr - This is called when the body of a lambda expression
/// was successfully completed.
ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope);
// ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
Expr **Strings,

View File

@ -1132,8 +1132,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::l_square:
if (getLang().CPlusPlus0x) {
if (getLang().ObjC1) {
// C++11 lambda expressions and Objective-C message sends both start with a
// square bracket. There are three possibilities here:
// we have a valid lambda expression, we have an invalid lambda
// expression, or we have something that doesn't appear to be a lambda.
// If we're in the last case, we fall back to ParseObjCMessageExpression.
Res = TryParseLambdaExpression();
if (Res.isInvalid())
if (!Res.isInvalid() && !Res.get())
Res = ParseObjCMessageExpression();
break;
}

View File

@ -14,6 +14,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
@ -563,6 +564,9 @@ ExprResult Parser::ParseLambdaExpression() {
if (DiagID) {
Diag(Tok, DiagID.getValue());
SkipUntil(tok::r_square);
SkipUntil(tok::l_brace);
SkipUntil(tok::r_brace);
return ExprError();
}
return ParseLambdaExpressionAfterIntroducer(Intro);
@ -591,14 +595,21 @@ ExprResult Parser::TryParseLambdaExpression() {
return ParseLambdaExpression();
}
// If lookahead indicates this is an Objective-C message...
// If lookahead indicates an ObjC message send...
// [identifier identifier
if (Next.is(tok::identifier) && After.is(tok::identifier)) {
return ExprError();
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
// writing two routines to parse a lambda introducer, just try to parse
// a lambda introducer first, and fall back if that fails.
// (TryParseLambdaIntroducer never produces any diagnostic output.)
LambdaIntroducer Intro;
if (TryParseLambdaIntroducer(Intro))
return ExprError();
return ExprEmpty();
return ParseLambdaExpressionAfterIntroducer(Intro);
}
@ -694,11 +705,17 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro) {
Diag(Intro.Range.getBegin(), diag::warn_cxx98_compat_lambda);
SourceLocation LambdaBeginLoc = Intro.Range.getBegin();
Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda);
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
"lambda expression parsing");
Actions.ActOnLambdaStart(LambdaBeginLoc, getCurScope());
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
Declarator D(DS, Declarator::PrototypeContext);
Declarator D(DS, Declarator::BlockLiteralContext);
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
@ -775,24 +792,32 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
// Inform sema that we are starting a block.
Actions.ActOnLambdaArguments(D, getCurScope());
}
// Parse compound-statement.
if (Tok.is(tok::l_brace)) {
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
// it.
ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope |
Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope);
ParseCompoundStatementBody();
BodyScope.Exit();
} else {
if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_lambda_body);
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
}
return ExprEmpty();
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
// it.
ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope |
Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope);
StmtResult Stmt(ParseCompoundStatementBody());
BodyScope.Exit();
if (!Stmt.isInvalid())
return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(),
getCurScope());
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
}
/// ParseCXXCasts - This handles the various ways to cast expressions to another

View File

@ -4774,3 +4774,38 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
}
//===----------------------------------------------------------------------===//
// Lambdas.
//===----------------------------------------------------------------------===//
void Sema::ActOnLambdaStart(SourceLocation StartLoc, Scope *CurScope) {
// FIXME: Add lambda-scope
// FIXME: Build lambda-decl
// FIXME: PushDeclContext
// Enter a new evaluation context to insulate the block from any
// cleanups from the enclosing full-expression.
PushExpressionEvaluationContext(PotentiallyEvaluated);
}
void Sema::ActOnLambdaArguments(Declarator &ParamInfo, Scope *CurScope) {
// FIXME: Implement
}
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
// Leave the expression-evaluation context.
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
// Leave the context of the lambda.
// FIXME: PopDeclContext
// FIXME: Pop lambda-scope
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
Stmt *Body, Scope *CurScope) {
// FIXME: Implement
Diag(StartLoc, diag::err_lambda_unsupported);
ActOnLambdaError(StartLoc, CurScope);
return ExprError();
}

View File

@ -20,7 +20,7 @@ int scope_attr [[foo::]]; // expected-error {{expected identifier}}
unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}}
int & [[]] ref_attr = after_attr; // expected-error {{an attribute list cannot appear here}}
class foo {
void after_const_attr () const [[]]; // expected-error {{expected body of lambda expression}} expected-error {{array has incomplete element type 'void'}}
void after_const_attr () const [[]]; // expected-error {{expected body of lambda expression}}
};
extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}

View File

@ -12,13 +12,13 @@ class C {
[&this] {}; // expected-error {{'this' cannot be captured by reference}}
[&,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
[=,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
[] {};
[=] (int i) {};
[&] (int) mutable -> void {};
[foo,bar] () { return 3; };
[=,&foo] () {};
[&,foo] () {};
[this] () {};
[] {}; // 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}}
[foo,bar] () { return 3; }; // expected-error {{lambda expressions are not supported yet}}
[=,&foo] () {}; // 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}}
return 1;
}

View File

@ -11,15 +11,15 @@ class C {
[]; // expected-error {{expected body of lambda expression}}
[=,foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}}
[&this] {}; // expected-error {{address expression must be an lvalue}}
[] {};
[=] (int i) {};
[&] (int) mutable -> void {};
[] {}; // 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}}
[=,&foo] () {};
[this] () {};
[foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}} 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}}
}
};

View File

@ -34,7 +34,8 @@ namespace TemplateParsing {
}
void Lambda() {
[]{}; // expected-warning {{lambda expressions are incompatible with C++98}}
// FIXME: Enable when lambdas are minimally working.
//[]{}; // FIXME-warning {{lambda expressions are incompatible with C++98}}
}
int InitList() {