Check the return type of lambda expressions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150503 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ba7e63a..f76dcc2 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3999,44 +3999,51 @@
 def err_return_in_constructor_handler : Error<
   "return in the catch of a function try block of a constructor is illegal">;
 
-def err_capture_more_than_once : Error<
-  "%0 can appear only once in a capture list">;
-def err_reference_capture_with_reference_default : Error<
-  "'&' cannot precede a capture when the capture default is '&'">;
-def err_this_capture_with_copy_default : Error<
-  "'this' cannot be explicitly captured when the capture default is '='">;
-def err_copy_capture_with_copy_default : Error<
-  "'&' must precede a capture when the capture default is '='">;
-def err_capture_does_not_name_variable : Error<
-  "%0 in capture list does not name a variable">;
-def err_capture_non_automatic_variable : Error<
-  "%0 cannot be captured because it does not have automatic storage duration">;
-def err_this_capture : Error<
-  "'this' cannot be %select{implicitly |}0captured in this context">;
-def err_lambda_capture_block : Error<
-  "__block variable %0 cannot be captured in a lambda expression">;
-def err_lambda_capture_anonymous_var : Error<
-  "unnamed variable cannot be implicitly captured in a lambda expression">;
-def err_lambda_capture_vm_type : Error<
-  "variable %0 with variably modified type cannot be captured in "
-  "a lambda expression">;
-def err_lambda_impcap : Error<
-  "variable %0 cannot be implicitly captured in a lambda with no "
-  "capture-default specified">;
-def note_lambda_decl : Note<"lambda expression begins here">;
-def err_lambda_unevaluated_operand : Error<
-  "lambda expression in an unevaluated operand">;
-def ext_lambda_implies_void_return : ExtWarn<
-  "C++11 requires lambda with omitted result type to consist of a single "
-  "return statement">,
-  InGroup<DiagGroup<"lambda-return">>;
-def err_lambda_return_init_list : Error<
-  "cannot deduce lambda return type from initializer list">;
-def err_lambda_capture_default_arg : Error<
-  "lambda expression in default argument cannot capture any entity">;
-def err_lambda_unexpanded_pack : Error<
-  "unexpanded function parameter pack capture is unsupported">;
-  
+let CategoryName = "Lambda Issue" in {
+  def err_capture_more_than_once : Error<
+    "%0 can appear only once in a capture list">;
+  def err_reference_capture_with_reference_default : Error<
+    "'&' cannot precede a capture when the capture default is '&'">;
+  def err_this_capture_with_copy_default : Error<
+    "'this' cannot be explicitly captured when the capture default is '='">;
+  def err_copy_capture_with_copy_default : Error<
+    "'&' must precede a capture when the capture default is '='">;
+  def err_capture_does_not_name_variable : Error<
+    "%0 in capture list does not name a variable">;
+  def err_capture_non_automatic_variable : Error<
+    "%0 cannot be captured because it does not have automatic storage "
+    "duration">;
+  def err_this_capture : Error<
+    "'this' cannot be %select{implicitly |}0captured in this context">;
+  def err_lambda_capture_block : Error<
+    "__block variable %0 cannot be captured in a lambda expression">;
+  def err_lambda_capture_anonymous_var : Error<
+    "unnamed variable cannot be implicitly captured in a lambda expression">;
+  def err_lambda_capture_vm_type : Error<
+    "variable %0 with variably modified type cannot be captured in "
+    "a lambda expression">;
+  def err_lambda_impcap : Error<
+    "variable %0 cannot be implicitly captured in a lambda with no "
+    "capture-default specified">;
+  def note_lambda_decl : Note<"lambda expression begins here">;
+  def err_lambda_unevaluated_operand : Error<
+    "lambda expression in an unevaluated operand">;
+  def ext_lambda_implies_void_return : ExtWarn<
+    "C++11 requires lambda with omitted result type to consist of a single "
+    "return statement">,
+    InGroup<DiagGroup<"lambda-return">>;
+  def err_lambda_return_init_list : Error<
+    "cannot deduce lambda return type from initializer list">;
+  def err_lambda_capture_default_arg : Error<
+    "lambda expression in default argument cannot capture any entity">;
+  def err_lambda_unexpanded_pack : Error<
+    "unexpanded function parameter pack capture is unsupported">;
+  def err_lambda_incomplete_result : Error<
+    "incomplete result type %0 in lambda expression">;
+  def err_lambda_objc_object_result : Error<
+    "non-pointer Objective-C class type %0 in lambda expression result">;
+}
+
 def err_operator_arrow_circular : Error<
   "circular pointer delegation detected">;
 def err_pseudo_dtor_base_not_scalar : Error<
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index c75c3c5..8b8a083 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -87,6 +87,17 @@
 
   if (ExplicitResultType) {
     LSI->ReturnType = CallOperator->getResultType();
+    
+    if (!LSI->ReturnType->isDependentType() &&
+        !LSI->ReturnType->isVoidType()) {
+      if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType,
+                              diag::err_lambda_incomplete_result)) {
+        // Do nothing.
+      } else if (LSI->ReturnType->isObjCObjectOrInterfaceType()) {
+        Diag(CallOperator->getLocStart(), diag::err_lambda_objc_object_result)
+          << LSI->ReturnType;
+      }
+    }
   } else {
     LSI->HasImplicitReturnType = true;
   }
@@ -161,7 +172,6 @@
     CheckExtraCXXDefaultArguments(ParamInfo);
     
     MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
-    // FIXME: Can these asserts actually fail?
     assert(MethodTyInfo && "no type from lambda-declarator");
     EndLoc = ParamInfo.getSourceRange().getEnd();
     
@@ -266,7 +276,8 @@
     //   for unqualified name lookup (3.4.1); each such lookup shall find a 
     //   variable with automatic storage duration declared in the reaching 
     //   scope of the local lambda expression.
-    // FIXME: Check reaching scope. 
+    // 
+    // Note that the 'reaching scope' check happens in TryCaptureVar.
     VarDecl *Var = R.getAsSingle<VarDecl>();
     if (!Var) {
       Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
@@ -321,8 +332,6 @@
     addLambdaParameters(Method, CurScope, Proto.getParams());
   }
 
-  // FIXME: Check return type is complete, !isObjCObjectType
-  
   // Enter a new evaluation context to insulate the lambda from any
   // cleanups from the enclosing full-expression.
   PushExpressionEvaluationContext(PotentiallyEvaluated);  
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
index cff0c09..586825f 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -41,3 +41,11 @@
       return x; // expected-error{{return type 'const X' must match previous return type 'X' when block literal has unspecified explicit return type}}
   }(5);
 }
+
+struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}}
+void test_result_type(int N) {
+  auto l1 = [] () -> Incomplete { }; // expected-error{{incomplete result type 'Incomplete' in lambda expression}}
+
+  typedef int vla[N];
+  auto l2 = [] () -> vla { }; // expected-error{{function cannot return array type 'vla' (aka 'int [N]')}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
new file mode 100644
index 0000000..0126e23
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+@interface A
+@end
+
+void test_result_type() {
+  auto l1 = [] () -> A { }; // expected-error{{non-pointer Objective-C class type 'A' in lambda expression result}}
+}