]> granicus.if.org Git - clang/commitdiff
Implement return type deduction for lambdas per C++11
authorDouglas Gregor <dgregor@apple.com>
Thu, 9 Feb 2012 10:18:50 +0000 (10:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 9 Feb 2012 10:18:50 +0000 (10:18 +0000)
[expr.prim.lambda]p4, including the current suggested resolution of
core isue 975, which allows multiple return statements so long as the
types match. ExtWarn when user code is actually making use of this
extension.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150168 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaChecking.cpp
lib/Sema/SemaLambda.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp [new file with mode: 0644]
test/SemaCXX/lambda-expressions.cpp

index 94798d0084fc41a642054ddcf9937fe3c2bb8644..aff79a6cda0b210f4c19c23eea69518e3322760d 100644 (file)
@@ -4126,6 +4126,10 @@ def err_lambda_impcap : Error<
 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_operator_arrow_circular : Error<
   "circular pointer delegation detected">;
index 69731e45eff0c1fb99d4a9c61a21b41c045306fb..a44633d5d7ce1634bd00f3eeab5cb10a43e3daab 100644 (file)
@@ -4185,7 +4185,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
   BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
   bool IsLogicalOperator = BO && BO->isLogicalOp();
   for (Stmt::child_range I = E->children(); I; ++I) {
-    Expr *ChildExpr = dyn_cast<Expr>(*I);
+    Expr *ChildExpr = dyn_cast_or_null<Expr>(*I);
     if (!ChildExpr)
       continue;
 
index 6d8e6a1029a432a7a8369c03e468755a347adfd5..73ef229a6bd4281e9a855e2cdab4e2c96bf181b1 100644 (file)
@@ -294,6 +294,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
   bool LambdaExprNeedsCleanups;
   {
     LambdaScopeInfo *LSI = getCurLambda();
+    CXXMethodDecl *CallOperator = LSI->CallOperator;
     Class = LSI->Lambda;
     IntroducerRange = LSI->IntroducerRange;
     ExplicitParams = LSI->ExplicitParams;
@@ -342,6 +343,51 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
       break;
     }
 
+    // C++11 [expr.prim.lambda]p4:
+    //   If a lambda-expression does not include a
+    //   trailing-return-type, it is as if the trailing-return-type
+    //   denotes the following type:
+    // FIXME: Assumes current resolution to core issue 975.
+    if (LSI->HasImplicitReturnType) {
+      //   - if there are no return statements in the
+      //     compound-statement, or all return statements return
+      //     either an expression of type void or no expression or
+      //     braced-init-list, the type void;
+      if (LSI->ReturnType.isNull()) {
+        LSI->ReturnType = Context.VoidTy;
+      } else {
+        // C++11 [expr.prim.lambda]p4:
+        //   - if the compound-statement is of the form
+        //
+        //       { attribute-specifier-seq[opt] return expression ; }
+        //
+        //     the type of the returned expression after
+        //     lvalue-to-rvalue conversion (4.1), array-to-pointer
+        //     conver- sion (4.2), and function-to-pointer conversion
+        //     (4.3);
+        //
+        // Since we're accepting the resolution to a post-C++11 core
+        // issue with a non-trivial extension, provide a warning (by
+        // default).
+        CompoundStmt *CompoundBody = cast<CompoundStmt>(Body);
+        if (!(CompoundBody->size() == 1 &&
+              isa<ReturnStmt>(*CompoundBody->body_begin())) &&
+            !Context.hasSameType(LSI->ReturnType, Context.VoidTy))
+          Diag(IntroducerRange.getBegin(), 
+               diag::ext_lambda_implies_void_return);
+      }
+
+      // Create a function type with the inferred return type.
+      const FunctionProtoType *Proto
+        = CallOperator->getType()->getAs<FunctionProtoType>();
+      QualType FunctionTy
+        = Context.getFunctionType(LSI->ReturnType,
+                                  Proto->arg_type_begin(),
+                                  Proto->getNumArgs(),
+                                  Proto->getExtProtoInfo());
+      CallOperator->setType(FunctionTy);
+    }
+
     // Finalize the lambda class.
     SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
     ActOnFields(0, Class->getLocation(), Class, Fields, 
@@ -351,7 +397,6 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
     // C++ [expr.prim.lambda]p7:
     //   The lambda-expression's compound-statement yields the
     //   function-body (8.4) of the function call operator [...].
-    CXXMethodDecl *CallOperator = LSI->CallOperator;
     ActOnFinishFunctionBody(CallOperator, Body, /*IsInstantation=*/false);
     CallOperator->setLexicalDeclContext(Class);
   }
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
new file mode 100644 (file)
index 0000000..a3a29c0
--- /dev/null
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void missing_lambda_declarator() {
+  [](){}();
+}
+
+template<typename T> T get();
+
+void infer_void_return_type(int i) {
+  if (i > 17)
+    return []() { }();
+
+  if (i > 11)
+    return []() { return; }();
+
+  return [](int x) {
+    switch (x) {
+    case 0: return get<void>();
+    case 1: return;
+    }
+  }(7);
+}
+
+struct X { };
+
+X infer_X_return_type(X x) {
+  return [&x](int y) { // expected-warning{{omitted result type}}
+    if (y > 0)
+      return X();
+    else
+      return x;
+  }(5);
+}
+
+X infer_X_return_type_fail(X x) { 
+  return [x](int y) { // expected-warning{{omitted result type}}
+    if (y > 0)
+      return X();
+    else // FIXME: shouldn't mention blocks
+      return x; // expected-error{{return type 'const X' must match previous return type 'X' when block literal has unspecified explicit return type}}
+  }(5);
+}
index afdff999d44ed006f3aea6413bc5c7a19ed05636..1da57c6c726982a67f764f27e8341b1ff4442f39 100644 (file)
@@ -34,12 +34,12 @@ namespace ReturnDeduction {
     [](){ return 1; }; 
     [](){ return 1; }; 
     [](){ return ({return 1; 1;}); }; 
-    [](){ return ({return 'c'; 1;}); }; // expected-error {{must match previous return type}}
+    [](){ return ({return 'c'; 1;}); }; // expected-error {{must match previous return type}} \
+    // expected-warning{{omitted result type}}
     []()->int{ return 'c'; return 1; }; 
     [](){ return 'c'; return 1; };  // expected-error {{must match previous return type}}
     []() { return; return (void)0; }; 
-    // FIXME: Need to check structure of lambda body 
-    [](){ return 1; return 1; }; 
+    [](){ return 1; return 1; }; // expected-warning{{omitted result type}}
   }
 }
 
@@ -76,9 +76,11 @@ namespace ImplicitCapture {
 
     struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}}
     G g;
-    [=]() { const G* gg = &g; return gg->a; }; 
-    [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'const ImplicitCapture::G'}} 
-    (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const ImplicitCapture::G'}} 
+    [=]() { const G* gg = &g; return gg->a; }; // expected-warning{{omitted result type}}
+    [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'const ImplicitCapture::G'}}  \
+    // expected-warning{{omitted result type}}
+    (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const ImplicitCapture::G'}}  \
+    // expected-warning{{omitted result type}}
 
     const int h = a; // expected-note {{declared}}
     []() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}