Add support for blocks with explicit return types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63784 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4879ac8..975c5e1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1209,7 +1209,7 @@
/// ActOnBlockArguments - This callback allows processing of block arguments.
/// If there are no arguments, this is still invoked.
- virtual void ActOnBlockArguments(Declarator &ParamInfo);
+ virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope);
/// ActOnBlockError - If there is an error parsing a block, this callback
/// is invoked to pop the information about the block from the action impl.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6671037..3ee6e52 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4179,12 +4179,36 @@
PushDeclContext(BlockScope, BSI->TheDecl);
}
-void Sema::ActOnBlockArguments(Declarator &ParamInfo) {
+void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+ assert(ParamInfo.getIdentifier() == 0 && "block-id should have no identifier!");
+
+ if (ParamInfo.getNumTypeObjects() == 0
+ || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
+ QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
+
+ // The type is entirely optional as well, if none, use DependentTy.
+ if (T.isNull())
+ T = Context.DependentTy;
+
+ // The parameter list is optional, if there was none, assume ().
+ if (!T->isFunctionType())
+ T = Context.getFunctionType(T, NULL, 0, 0, 0);
+
+ CurBlock->hasPrototype = true;
+ CurBlock->isVariadic = false;
+ Type *RetTy = T.getTypePtr()->getAsFunctionType()->getResultType()
+ .getTypePtr();
+
+ if (!RetTy->isDependentType())
+ CurBlock->ReturnType = RetTy;
+ return;
+ }
+
// Analyze arguments to block.
assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function &&
"Not a function declarator!");
DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun;
-
+
CurBlock->hasPrototype = FTI.hasPrototype;
CurBlock->isVariadic = true;
@@ -4200,6 +4224,13 @@
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
CurBlock->Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
CurBlock->isVariadic = FTI.isVariadic;
+ QualType T = GetTypeForDeclarator (ParamInfo, CurScope);
+
+ Type* RetTy = T.getTypePtr()->getAsFunctionType()->getResultType()
+ .getTypePtr();
+
+ if (!RetTy->isDependentType())
+ CurBlock->ReturnType = RetTy;
}
CurBlock->TheDecl->setArgs(&CurBlock->Params[0], CurBlock->Params.size());
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index cf26b90..7697dbd 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -731,8 +731,8 @@
CurBlock->ReturnType = RetValExp->getType().getTypePtr();
} else
CurBlock->ReturnType = Context.VoidTy.getTypePtr();
- return Owned(new ReturnStmt(ReturnLoc, RetValExp));
}
+ QualType FnRetType = QualType(CurBlock->ReturnType, 0);
// 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
@@ -749,22 +749,23 @@
if (!RetValExp)
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
- // we have a non-void block with an expression, continue checking
- QualType RetValType = RetValExp->getType();
+ if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+ // we have a non-void block with an expression, continue checking
+ QualType RetValType = RetValExp->getType();
- // For now, restrict multiple return statements in a block to have
- // strict compatible types only.
- QualType BlockQT = QualType(CurBlock->ReturnType, 0);
- if (Context.getCanonicalType(BlockQT).getTypePtr()
- != Context.getCanonicalType(RetValType).getTypePtr()) {
- // FIXME: non-localizable string in diagnostic
- DiagnoseAssignmentResult(Incompatible, ReturnLoc, BlockQT,
- RetValType, RetValExp, "returning");
- return StmtError();
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // function return.
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ // FIXME: Leaks RetValExp.
+ if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
+ return StmtError();
+
+ if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
- if (RetValExp) CheckReturnStackAddr(RetValExp, BlockQT, ReturnLoc);
-
return Owned(new ReturnStmt(ReturnLoc, RetValExp));
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 9d78d0a..e6d1833 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -251,9 +251,20 @@
return Result;
}
-/// GetTypeForDeclarator - Convert the type for the specified declarator to Type
-/// instances. Skip the outermost Skip type objects.
+/// GetTypeForDeclarator - Convert the type for the specified
+/// declarator to Type instances. Skip the outermost Skip type
+/// objects.
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
+ bool OmittedReturnType = false;
+
+ if (D.getContext() == Declarator::BlockLiteralContext
+ && Skip == 0
+ && !D.getDeclSpec().hasTypeSpecifier()
+ && (D.getNumTypeObjects() == 0
+ || (D.getNumTypeObjects() == 1
+ && D.getTypeObject(0).Kind == DeclaratorChunk::Function)))
+ OmittedReturnType = true;
+
// long long is a C99 feature.
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
@@ -265,9 +276,16 @@
switch (D.getKind()) {
case Declarator::DK_Abstract:
case Declarator::DK_Normal:
- case Declarator::DK_Operator:
- T = ConvertDeclSpecToType(D.getDeclSpec());
+ case Declarator::DK_Operator: {
+ const DeclSpec& DS = D.getDeclSpec();
+ if (OmittedReturnType)
+ // We default to a dependent type initially. Can be modified by
+ // the first return statement.
+ T = Context.DependentTy;
+ else
+ T = ConvertDeclSpecToType(DS);
break;
+ }
case Declarator::DK_Constructor:
case Declarator::DK_Destructor:
@@ -279,8 +297,9 @@
break;
}
- // Walk the DeclTypeInfo, building the recursive type as we go. DeclTypeInfos
- // are ordered from the identifier out, which is opposite of what we want :).
+ // Walk the DeclTypeInfo, building the recursive type as we go.
+ // DeclTypeInfos are ordered from the identifier out, which is
+ // opposite of what we want :).
for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip);
switch (DeclType.Kind) {