зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
61d679ab28
Коммит
84b007fae6
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче