diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 3b3bc5caf2..7ffc3bcfb9 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -166,7 +166,8 @@ public: }; 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 @@ public: /// Captures - The captures. SmallVector 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 @@ public: /// 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 @@ public: /// 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; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 12096f5fcb..97e09cfd01 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2137,7 +2137,7 @@ public: 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, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8a53ece6b3..018aadf8b9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8769,6 +8769,8 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { 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 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { if (RetTy != Context.DependentTy) { CurBlock->ReturnType = RetTy; CurBlock->TheDecl->setBlockMissingReturnType(false); + CurBlock->HasImplicitReturnType = false; } // Push block parameters from the declarator if we had them. diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index fdcad08b5e..f847e2e2e0 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1781,53 +1781,51 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, 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(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(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; } - CurBlock->ReturnType = BlockReturnT; + // 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(); + } + CurCap->ReturnType = ReturnT; } - QualType FnRetType = CurBlock->ReturnType; + QualType FnRetType = CurCap->ReturnType; + assert(!FnRetType.isNull()); - if (CurBlock->FunctionType->getAs()->getNoReturnAttr()) { - Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr); - return StmtError(); - } + if (BlockScopeInfo *CurBlock = dyn_cast(CurCap)) + if (CurBlock->FunctionType->getAs()->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 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); - if (getCurBlock()) - return ActOnBlockReturnStmt(ReturnLoc, RetValExp); + if (isa(getCurFunction())) + return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); QualType FnRetType; QualType DeclaredRetType; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 240445190b..284371b7de 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -8142,30 +8142,20 @@ TreeTransform::TransformBlockExpr(BlockExpr *E) { } 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 @@ TreeTransform::TransformBlockExpr(BlockExpr *E) { // 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()); diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm index 06573b9446..5cfb4f8c5a 100644 --- a/test/Parser/objcxx0x-lambda-expressions.mm +++ b/test/Parser/objcxx0x-lambda-expressions.mm @@ -14,8 +14,7 @@ class C { [] {}; // 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}} } diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp index 9411c34ec8..db934c3ab7 100644 --- a/test/SemaCXX/lambda-expressions.cpp +++ b/test/SemaCXX/lambda-expressions.cpp @@ -52,3 +52,16 @@ namespace ExplicitCapture { [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}} + } +}