summaryrefslogtreecommitdiffstats
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
commitdd5eb9df0cd248bc20fdca01f007f7119633a7d7 (patch)
treec356b1607c20723349636ca119cae1a3dd635681
parent71ba18c1e08ea0a323974be32bebffeaa60808da (diff)
downloadbcm5719-llvm-dd5eb9df0cd248bc20fdca01f007f7119633a7d7.tar.gz
bcm5719-llvm-dd5eb9df0cd248bc20fdca01f007f7119633a7d7.zip
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 llvm-svn: 145774
-rw-r--r--clang/include/clang/AST/Decl.h4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--clang/lib/Sema/SemaExpr.cpp4
-rw-r--r--clang/lib/Sema/SemaStmt.cpp12
-rw-r--r--clang/lib/Sema/TreeTransform.h2
-rw-r--r--clang/test/Sema/block-explicit-noreturn-type.c15
-rw-r--r--clang/test/Sema/block-return.c6
-rw-r--r--clang/test/SemaCXX/instantiate-blocks.cpp13
8 files changed, 54 insertions, 5 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index adb06cda51f..28a01cf04e9 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/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/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d3b7687e9bf..42430912913 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 1e9f319d4f7..cc94050a6f9 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/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/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index e8a61044b5d..1255695016d 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/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/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index d7bdbafaba1..3dc8136b787 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/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/clang/test/Sema/block-explicit-noreturn-type.c b/clang/test/Sema/block-explicit-noreturn-type.c
new file mode 100644
index 00000000000..12f4f4f3401
--- /dev/null
+++ b/clang/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/clang/test/Sema/block-return.c b/clang/test/Sema/block-return.c
index c6e1e9dc542..293967fea17 100644
--- a/clang/test/Sema/block-return.c
+++ b/clang/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/clang/test/SemaCXX/instantiate-blocks.cpp b/clang/test/SemaCXX/instantiate-blocks.cpp
index a4001a75fa5..799951a0aea 100644
--- a/clang/test/SemaCXX/instantiate-blocks.cpp
+++ b/clang/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}}
}
OpenPOWER on IntegriCloud