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
This commit is contained in:
Eli Friedman 2012-01-26 03:00:14 +00:00
Родитель 61d679ab28
Коммит 84b007fae6
7 изменённых файлов: 75 добавлений и 74 удалений

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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,

Просмотреть файл

@ -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.

Просмотреть файл

@ -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;

Просмотреть файл

@ -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());

Просмотреть файл

@ -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}}
}

Просмотреть файл

@ -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}}
}
}