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:
parent
cc1d7893d6
commit
c7c97144af
|
@ -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<
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue