aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2011-12-03 17:47:53 +0000
committerFariborz Jahanian <fjahanian@apple.com>2011-12-03 17:47:53 +0000
commit0586520acb2f368c874943353a222be7f00c3068 (patch)
tree911cefdbb13174380fcbbcaf49a285de44bee01c
parent4d604d6f1d413864e7dad8e368ba9a69a3f478c7 (diff)
If block literal return type is not specified, return type of the block is
inferred from return types. All the return statements have to agree about the type. // rdar://10466373 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145774 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--lib/Sema/SemaExpr.cpp4
-rw-r--r--lib/Sema/SemaStmt.cpp12
-rw-r--r--lib/Sema/TreeTransform.h2
-rw-r--r--test/Sema/block-explicit-noreturn-type.c15
-rw-r--r--test/Sema/block-return.c6
-rw-r--r--test/SemaCXX/instantiate-blocks.cpp13
8 files changed, 54 insertions, 5 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index adb06cda51..28a01cf04e 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2981,6 +2981,7 @@ private:
// FIXME: This can be packed into the bitfields in Decl.
bool IsVariadic : 1;
bool CapturesCXXThis : 1;
+ bool BlockMissingReturnType : 1;
/// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal
/// parameters of this function. This is null if a prototype or if there are
/// no formals.
@@ -2997,6 +2998,7 @@ protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block),
IsVariadic(false), CapturesCXXThis(false),
+ BlockMissingReturnType(true),
ParamInfo(0), NumParams(0), Body(0),
SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
@@ -3054,6 +3056,8 @@ public:
capture_const_iterator capture_end() const { return Captures + NumCaptures; }
bool capturesCXXThis() const { return CapturesCXXThis; }
+ bool blockMissingReturnType() const { return BlockMissingReturnType; }
+ void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; }
bool capturesVariable(const VarDecl *var) const;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index d3b7687e9b..4243091291 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4061,6 +4061,9 @@ def err_typecheck_convert_incompatible : Error<
"volatile and restrict|const, volatile, and restrict}5 vs "
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
"volatile and restrict|const, volatile, and restrict}6)}4">;
+def err_typecheck_missing_return_type_incompatible : Error<
+ "return type %0 must match previous return type %1 when block"
+ " literal has unspecified explicit return type">;
def warn_incompatible_qualified_id : Warning<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 1e9f319d4f..cc94050a6f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -8715,8 +8715,10 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// return type. TODO: what should we do with declarators like:
// ^ * { ... }
// If the answer is "apply template argument deduction"....
- if (RetTy != Context.DependentTy)
+ if (RetTy != Context.DependentTy) {
CurBlock->ReturnType = RetTy;
+ CurBlock->TheDecl->setBlockMissingReturnType(false);
+ }
// Push block parameters from the declarator if we had them.
SmallVector<ParmVarDecl*, 8> Params;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index e8a61044b5..1255695016 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1809,6 +1809,16 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
} else if (!RetValExp) {
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
} else if (!RetValExp->isTypeDependent()) {
+ if (CurBlock->TheDecl->blockMissingReturnType()) {
+ // when block's return type is not specified, all return types
+ // must strictly match.
+ if (Context.getCanonicalType(FnRetType) !=
+ Context.getCanonicalType(RetValExp->getType())) {
+ Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
+ << RetValExp->getType() << FnRetType;
+ return StmtError();
+ }
+ }
// we have a non-void block with an expression, continue checking
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
@@ -1820,7 +1830,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
FnRetType,
- NRVOCandidate != 0);
+ NRVOCandidate != 0);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
FnRetType, RetValExp);
if (Res.isInvalid()) {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index d7bdbafaba..3dc8136b78 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -8118,6 +8118,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// in above, CapturesCXXThis need be set here from the block
// expression.
blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
+ blockScope->TheDecl->setBlockMissingReturnType(
+ oldBlock->blockMissingReturnType());
SmallVector<ParmVarDecl*, 4> params;
SmallVector<QualType, 4> paramTypes;
diff --git a/test/Sema/block-explicit-noreturn-type.c b/test/Sema/block-explicit-noreturn-type.c
new file mode 100644
index 0000000000..12f4f4f340
--- /dev/null
+++ b/test/Sema/block-explicit-noreturn-type.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks
+// rdar://10466373
+
+typedef short SHORT;
+
+void f0() {
+ (void) ^{
+ if (1)
+ return (float)1.0;
+ else if (2)
+ return (double)2.0; // expected-error {{return type 'double' must match previous return type 'float' when block literal has}}
+ else
+ return (SHORT)3; // expected-error {{return type 'SHORT' (aka 'short') must match previous return type 'float' when}}
+ };
+}
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index c6e1e9dc54..293967fea1 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -31,14 +31,14 @@ CL foo() {
return (float)1.0;
else
if (2)
- return (double)2.0;
- return 1;
+ return (double)2.0; // expected-error {{return type 'double' must match previous return type 'float' when block literal has unspecified explicit return type}}
+ return 1; // expected-error {{return type 'int' must match previous return type 'float' when block literal has unspecified explicit return type}}
};
char *(^B)(void) = ^{
if (3)
return "";
else
- return 2; // expected-warning {{incompatible integer to pointer conversion returning 'int' from a function with result type 'char *'}}
+ return 2; // expected-error {{return type 'int' must match previous return type 'char *' when block literal has unspecified explicit return type}}
};
return ^{ return 1; }; // expected-error {{incompatible block pointer types returning 'int (^)(void)' from a function with result type 'CL' (aka 'void (^)(void)')}}
diff --git a/test/SemaCXX/instantiate-blocks.cpp b/test/SemaCXX/instantiate-blocks.cpp
index a4001a75fa..799951a0ae 100644
--- a/test/SemaCXX/instantiate-blocks.cpp
+++ b/test/SemaCXX/instantiate-blocks.cpp
@@ -12,8 +12,21 @@ template <typename T, typename T1> void foo(T t, T1 r)
return block_arg+arg; };
}
+// rdar://10466373
+template <typename T, typename T1> void noret(T t, T1 r)
+{
+ (void) ^{
+ if (1)
+ return t;
+ else if (2)
+ return r; // expected-error {{return type 'const double' must match previous return type 'float' when block literal has unspecified explicit return type}}
+ };
+}
+
int main(void)
{
foo(100, 'a'); // expected-note {{in instantiation of function template specialization 'foo<int, char>' requested here}}
+
+ noret((float)0.0, double(0.0)); // expected-note {{in instantiation of function template specialization 'noret<float, double>' requested here}}
}