diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2011-12-03 17:47:53 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2011-12-03 17:47:53 +0000 |
commit | 0586520acb2f368c874943353a222be7f00c3068 (patch) | |
tree | 911cefdbb13174380fcbbcaf49a285de44bee01c | |
parent | 4d604d6f1d413864e7dad8e368ba9a69a3f478c7 (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.h | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 2 | ||||
-rw-r--r-- | test/Sema/block-explicit-noreturn-type.c | 15 | ||||
-rw-r--r-- | test/Sema/block-return.c | 6 | ||||
-rw-r--r-- | test/SemaCXX/instantiate-blocks.cpp | 13 |
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}} } |