]> granicus.if.org Git - clang/commitdiff
Stub out the Sema interface for lambda expressions, and change the parser to use...
authorEli Friedman <eli.friedman@gmail.com>
Wed, 4 Jan 2012 02:40:39 +0000 (02:40 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Wed, 4 Jan 2012 02:40:39 +0000 (02:40 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147515 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaExprCXX.cpp
test/Parser/cxx0x-attributes.cpp
test/Parser/cxx0x-lambda-expressions.cpp
test/Parser/objcxx0x-lambda-expressions.mm
test/SemaCXX/cxx98-compat.cpp

index 7e5fff8ab4664a7900f88c38d8fe5695808a4421..d5047506cc98659c679e2934702ac2427cff34a6 100644 (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<
index 086bf23dab0a77057cd41d04d53cf0315600b00e..940ae2da98982901f55364cb324acfb1d2ced230 100644 (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,
index 0dd48a29469eb5282073b806775f72be3a3248a7..7eac984172578ee2d81534af36649f4a8f1a6e5d 100644 (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;
       }
index bd97fcee7c5afb39af005e6fdd91dc3504524916..901a537f5ed74e308821456ed6883b1f77ec72ce 100644 (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
index eaa330b183a956297789b97fb49373128ed6b015..67e1c2fb099e93be1ce8e73ad60d6be64b39638f 100644 (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();
+}
index e762b57a93d6293fb58b4586be6de7b02168d3b6..ff9118a0e157c60d6fab4c6ea0db5d8eda0cbdf2 100644 (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}}
index 4fa4e6f1b99ecfc9cc4ba64e8a0915b512120edb..df8d804931d09c8d50dbadea907a481c545406e5 100644 (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;
   }
index 937464918b6ae6e1d0e9df836b843a81de7d855f..b9a96d6b2df2b0e1b164bbdd28cb5ed4e3525240 100644 (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}}
   }
 
 };
index 051176bf9c320b1e8e0d22b0b6e7e66e0bdb81c4..56e64d23a6ea93b51a1e9db3f908e70305fa36e7 100644 (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() {