[cfe-commits] r149031 - in /cfe/trunk: include/clang/Sema/ScopeInfo.h include/clang/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h test/Parser/objcxx0x-lambda-expressions.mm test/SemaCXX/lambda-expressions.cpp

Eli Friedman eli.friedman at gmail.com
Wed Jan 25 19:00:15 PST 2012


Author: efriedma
Date: Wed Jan 25 21:00:14 2012
New Revision: 149031

URL: http://llvm.org/viewvc/llvm-project?rev=149031&view=rev
Log:
Refactor to share code for handling return statements between lambda expressions and block literals.  As it turns out, almost all the logic can be shared.


Modified:
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm
    cfe/trunk/test/SemaCXX/lambda-expressions.cpp

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=149031&r1=149030&r2=149031&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Wed Jan 25 21:00:14 2012
@@ -166,7 +166,8 @@
   };
 
   CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style)
-    : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0)
+    : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0),
+      HasImplicitReturnType(false)
      {}
 
   /// CaptureMap - A map of captured variables to (index+1) into Captures.
@@ -179,6 +180,14 @@
   /// Captures - The captures.
   SmallVector<Capture, 4> Captures;
 
+  /// \brief - Whether the target type of return statements in this context
+  /// is deduced (e.g. a lambda or block with omitted return type).
+  bool HasImplicitReturnType;
+
+  /// ReturnType - The target type of return statements in this context,
+  /// or null if unknown.
+  QualType ReturnType;
+
   void AddCapture(VarDecl *Var, bool isByref, bool isNested, Expr *Cpy) {
     Captures.push_back(Capture(Var, isByref, isNested, Cpy));
     CaptureMap[Var] = Captures.size();
@@ -204,10 +213,6 @@
   /// arguments etc.
   Scope *TheScope;
 
-  /// ReturnType - The return type of the block, or null if the block
-  /// signature didn't provide an explicit return type.
-  QualType ReturnType;
-
   /// BlockType - The function type of the block, if one was given.
   /// Its return type may be BuiltinType::Dependent.
   QualType FunctionType;
@@ -236,15 +241,9 @@
   /// explicit captures.
   unsigned NumExplicitCaptures;
 
-  /// \brief - Whether the return type of the lambda is implicit
-  bool HasImplicitReturnType;
-
-  /// ReturnType - The return type of the lambda, or null if unknown.
-  QualType ReturnType;
-
   LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda)
     : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
-      NumExplicitCaptures(0), HasImplicitReturnType(false)
+      NumExplicitCaptures(0)
   {
     Kind = SK_Lambda;
   }

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=149031&r1=149030&r2=149031&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 25 21:00:14 2012
@@ -2137,7 +2137,7 @@
                                          bool AllowFunctionParameters);
 
   StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
-  StmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
+  StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
 
   StmtResult ActOnAsmStmt(SourceLocation AsmLoc,
                           bool IsSimple, bool IsVolatile,

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=149031&r1=149030&r2=149031&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jan 25 21:00:14 2012
@@ -8769,6 +8769,8 @@
   else
     CurContext = Block;
 
+  getCurBlock()->HasImplicitReturnType = true;
+
   // Enter a new evaluation context to insulate the block from any
   // cleanups from the enclosing full-expression.
   PushExpressionEvaluationContext(PotentiallyEvaluated);  
@@ -8835,6 +8837,7 @@
   if (RetTy != Context.DependentTy) {
     CurBlock->ReturnType = RetTy;
     CurBlock->TheDecl->setBlockMissingReturnType(false);
+    CurBlock->HasImplicitReturnType = false;
   }
 
   // Push block parameters from the declarator if we had them.

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=149031&r1=149030&r2=149031&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Jan 25 21:00:14 2012
@@ -1781,53 +1781,51 @@
   return Res;
 }
 
-/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
+/// ActOnCapScopeReturnStmt - Utility routine to type-check return statements
+/// for capturing scopes.
 ///
 StmtResult
-Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
-  // If this is the first return we've seen in the block, infer the type of
-  // the block from it.
-  BlockScopeInfo *CurBlock = getCurBlock();
-  if (CurBlock->TheDecl->blockMissingReturnType()) {
-    QualType BlockReturnT;
+Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+  // If this is the first return we've seen, infer the return type.
+  // [expr.prim.lambda]p4 in C++11; block literals follow a superset of those
+  // rules which allows multiple return statements.
+  CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
+  if (CurCap->HasImplicitReturnType) {
+    QualType ReturnT;
     if (RetValExp) {
-      // Don't call UsualUnaryConversions(), since we don't want to do
-      // integer promotions here.
       ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
       if (Result.isInvalid())
         return StmtError();
       RetValExp = Result.take();
 
-      if (!RetValExp->isTypeDependent()) {
-        BlockReturnT = RetValExp->getType();
-        if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
-          // We have to remove a 'const' added to copied-in variable which was
-          // part of the implementation spec. and not the actual qualifier for
-          // the variable.
-          if (CDRE->isConstQualAdded())
-            CurBlock->ReturnType.removeLocalConst(); // FIXME: local???
-        }
-      } else
-        BlockReturnT = Context.DependentTy;
-    } else
-        BlockReturnT = Context.VoidTy;
-    if (!CurBlock->ReturnType.isNull() && !CurBlock->ReturnType->isDependentType()
-        && !BlockReturnT->isDependentType() 
-        // when block's return type is not specified, all return types
-        // must strictly match.
-        && !Context.hasSameType(BlockReturnT, CurBlock->ReturnType)) { 
-        Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) 
-            << BlockReturnT << CurBlock->ReturnType;
-        return StmtError();
+      if (!RetValExp->isTypeDependent())
+        ReturnT = RetValExp->getType();
+      else
+        ReturnT = Context.DependentTy;
+    } else {
+      ReturnT = Context.VoidTy;
+    }
+    // We require the return types to strictly match here.
+    if (!CurCap->ReturnType.isNull() &&
+        !CurCap->ReturnType->isDependentType() &&
+        !ReturnT->isDependentType() &&
+        !Context.hasSameType(ReturnT, CurCap->ReturnType)) { 
+      // FIXME: Adapt diagnostic for lambdas.
+      Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) 
+          << ReturnT << CurCap->ReturnType;
+      return StmtError();
     }
-    CurBlock->ReturnType = BlockReturnT;
+    CurCap->ReturnType = ReturnT;
   }
-  QualType FnRetType = CurBlock->ReturnType;
+  QualType FnRetType = CurCap->ReturnType;
+  assert(!FnRetType.isNull());
 
-  if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
-    Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
-    return StmtError();
-  }
+  if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap))
+    if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
+      Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
+      return StmtError();
+    }
+  // FIXME: [[noreturn]] for lambdas!
 
   // Otherwise, verify that this result type matches the previous one.  We are
   // pickier with blocks than for normal functions because we don't have GCC
@@ -1891,8 +1889,8 @@
   if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
     return StmtError();
   
-  if (getCurBlock())
-    return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
+  if (isa<CapturingScopeInfo>(getCurFunction()))
+    return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
 
   QualType FnRetType;
   QualType DeclaredRetType;

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=149031&r1=149030&r2=149031&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Jan 25 21:00:14 2012
@@ -8142,30 +8142,20 @@
   }
 
   const FunctionType *exprFunctionType = E->getFunctionType();
-  QualType exprResultType = exprFunctionType->getResultType();
-  if (!exprResultType.isNull()) {
-    if (!exprResultType->isDependentType())
-      blockScope->ReturnType = exprResultType;
-    else if (exprResultType != getSema().Context.DependentTy)
-      blockScope->ReturnType = getDerived().TransformType(exprResultType);
-  }
-  
-  // If the return type has not been determined yet, leave it as a dependent
-  // type; it'll get set when we process the body.
-  if (blockScope->ReturnType.isNull())
-    blockScope->ReturnType = getSema().Context.DependentTy;
+  QualType exprResultType =
+      getDerived().TransformType(exprFunctionType->getResultType());
 
   // Don't allow returning a objc interface by value.
-  if (blockScope->ReturnType->isObjCObjectType()) {
+  if (exprResultType->isObjCObjectType()) {
     getSema().Diag(E->getCaretLocation(), 
                    diag::err_object_cannot_be_passed_returned_by_value) 
-      << 0 << blockScope->ReturnType;
+      << 0 << exprResultType;
     getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
     return ExprError();
   }
 
   QualType functionType = getDerived().RebuildFunctionProtoType(
-                                                        blockScope->ReturnType,
+                                                        exprResultType,
                                                         paramTypes.data(),
                                                         paramTypes.size(),
                                                         oldBlock->isVariadic(),
@@ -8176,12 +8166,11 @@
   // Set the parameters on the block decl.
   if (!params.empty())
     blockScope->TheDecl->setParams(params);
-  
-  // If the return type wasn't explicitly set, it will have been marked as a 
-  // dependent type (DependentTy); clear out the return type setting so 
-  // we will deduce the return type when type-checking the block's body.
-  if (blockScope->ReturnType == getSema().Context.DependentTy)
-    blockScope->ReturnType = QualType();
+
+  if (!oldBlock->blockMissingReturnType()) {
+    blockScope->HasImplicitReturnType = false;
+    blockScope->ReturnType = exprResultType;
+  }
   
   // Transform the body
   StmtResult body = getDerived().TransformStmt(E->getBody());

Modified: cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm?rev=149031&r1=149030&r2=149031&view=diff
==============================================================================
--- cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm (original)
+++ cfe/trunk/test/Parser/objcxx0x-lambda-expressions.mm Wed Jan 25 21:00:14 2012
@@ -14,8 +14,7 @@
     [] {}; // 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: Implicit return type deduction doesn't work yet.
-    [foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}} 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}}
     [this] () {}; // expected-error {{lambda expressions are not supported yet}}
   }

Modified: cfe/trunk/test/SemaCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lambda-expressions.cpp?rev=149031&r1=149030&r2=149031&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/SemaCXX/lambda-expressions.cpp Wed Jan 25 21:00:14 2012
@@ -52,3 +52,16 @@
     [this] () {}; // expected-error {{invalid use of 'this'}} expected-error {{not supported yet}}
   }
 }
+
+namespace ReturnDeduction {
+  void test() {
+    [](){ return 1; }; // expected-error {{not supported yet}}
+    [](){ return 1; }; // expected-error {{not supported yet}}
+    [](){ return ({return 1; 1;}); }; // expected-error {{not supported yet}}
+    [](){ return ({return 'c'; 1;}); }; // expected-error {{not supported yet}} expected-error {{must match previous return type}}
+    []()->int{ return 'c'; return 1; }; // expected-error {{not supported yet}}
+    [](){ return 'c'; return 1; }; // expected-error {{not supported yet}} expected-error {{must match previous return type}}
+    // FIXME: Need to check structure of lambda body 
+    [](){ return 1; return 1; }; // expected-error {{not supported yet}}
+  }
+}





More information about the cfe-commits mailing list