Improve recovery for lambda expressions that have 'mutable' or a
trailing return type but not a '()'. Recover by inserting the
parentheses. Thanks to Xeo on IRC for the example.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150727 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index dcc6f69..3960d02 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -602,6 +602,8 @@
 def warn_cxx98_compat_lambda : Warning<
   "lambda expressions are incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
+def err_lambda_missing_parens : Error<
+  "lambda requires '()' before %select{'mutable'|return type}0">;
 
 // Availability attribute
 def err_expected_version : Error<
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 7185e93..d09dba2 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -820,7 +820,53 @@
                                            DeclLoc, DeclEndLoc, D,
                                            TrailingReturnType),
                   Attr, DeclEndLoc);
+  } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) {
+    // It's common to forget that one needs '()' before 'mutable' or the 
+    // result type. Deal with this.
+    Diag(Tok, diag::err_lambda_missing_parens)
+      << Tok.is(tok::arrow)
+      << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
+    SourceLocation DeclLoc = Tok.getLocation();
+    SourceLocation DeclEndLoc = DeclLoc;
+    
+    // Parse 'mutable', if it's there.
+    SourceLocation MutableLoc;
+    if (Tok.is(tok::kw_mutable)) {
+      MutableLoc = ConsumeToken();
+      DeclEndLoc = MutableLoc;
+    }
+    
+    // Parse the return type, if there is one.
+    ParsedType TrailingReturnType;
+    if (Tok.is(tok::arrow)) {
+      SourceRange Range;
+      TrailingReturnType = ParseTrailingReturnType(Range).get();
+      if (Range.getEnd().isValid())
+        DeclEndLoc = Range.getEnd();      
+    }
+
+    ParsedAttributes Attr(AttrFactory);
+    D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
+                     /*isVariadic=*/false,
+                     /*EllipsisLoc=*/SourceLocation(),
+                     /*Params=*/0, /*NumParams=*/0,
+                     /*TypeQuals=*/0,
+                     /*RefQualifierIsLValueRef=*/true,
+                     /*RefQualifierLoc=*/SourceLocation(),
+                     /*ConstQualifierLoc=*/SourceLocation(),
+                     /*VolatileQualifierLoc=*/SourceLocation(),
+                     MutableLoc,
+                     EST_None, 
+                     /*ESpecLoc=*/SourceLocation(),
+                     /*Exceptions=*/0,
+                     /*ExceptionRanges=*/0,
+                     /*NumExceptions=*/0,
+                     /*NoexceptExpr=*/0,
+                     DeclLoc, DeclEndLoc, D,
+                     TrailingReturnType),
+                  Attr, DeclEndLoc);
   }
+  
 
   // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
   // it.
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index aa2a9cf..a25116b 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -20,6 +20,8 @@
     [&,foo] () {}; 
     [this] () {}; 
 
+    [] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
+    [] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
     return 1;
   }