From: Eli Friedman Date: Wed, 4 Jan 2012 02:40:39 +0000 (+0000) Subject: Stub out the Sema interface for lambda expressions, and change the parser to use... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dc3b723d35067e5d13474247b94a10c869cc7e58;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147515 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7e5fff8ab4..d5047506cc 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 086bf23dab..940ae2da98 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 0dd48a2946..7eac984172 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index bd97fcee7c..901a537f5e 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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 diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index eaa330b183..67e1c2fb09 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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(); +} diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp index e762b57a93..ff9118a0e1 100644 --- a/test/Parser/cxx0x-attributes.cpp +++ b/test/Parser/cxx0x-attributes.cpp @@ -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 void before_template_attr (); // expected-error {{an attribute list cannot appear here}} diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp index 4fa4e6f1b9..df8d804931 100644 --- a/test/Parser/cxx0x-lambda-expressions.cpp +++ b/test/Parser/cxx0x-lambda-expressions.cpp @@ -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; } diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm index 937464918b..b9a96d6b2d 100644 --- a/test/Parser/objcxx0x-lambda-expressions.mm +++ b/test/Parser/objcxx0x-lambda-expressions.mm @@ -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}} } }; diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 051176bf9c..56e64d23a6 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -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() {