aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2012-01-26 03:00:14 +0000
committerEli Friedman <eli.friedman@gmail.com>2012-01-26 03:00:14 +0000
commit84b007fae6c0cd30fa07074d34fbe2bf61fa44f9 (patch)
tree0dea52c0e79905f26bfa3bd92e6123688142daaa
parent61d679ab2831b161c857cf3f974312fbd4ef1efd (diff)
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149031 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Sema/ScopeInfo.h23
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaExpr.cpp3
-rw-r--r--lib/Sema/SemaStmt.cpp74
-rw-r--r--lib/Sema/TreeTransform.h31
-rw-r--r--test/Parser/objcxx0x-lambda-expressions.mm3
-rw-r--r--test/SemaCXX/lambda-expressions.cpp13
7 files changed, 75 insertions, 74 deletions
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<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 @@ 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<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;
}
- 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<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 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
return StmtError();
- if (getCurBlock())
- return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
+ if (isa<CapturingScopeInfo>(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<Derived>::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<Derived>::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}}
+ }
+}