<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Dec 3, 2011, at 9:47 AM, Fariborz Jahanian wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>Author: fjahanian<br>Date: Sat Dec  3 11:47:53 2011<br>New Revision: 145774<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=145774&view=rev">http://llvm.org/viewvc/llvm-project?rev=145774&view=rev</a><br>Log:<br>If block literal return type is not specified, return type of the block is <br>inferred from return types. All the return statements have to agree about the type.<br>// <a href="rdar://10466373">rdar://10466373</a><br><br>Added:<br>    cfe/trunk/test/Sema/block-explicit-noreturn-type.c<br>Modified:<br>    cfe/trunk/include/clang/AST/Decl.h<br>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>    cfe/trunk/lib/Sema/SemaExpr.cpp<br>    cfe/trunk/lib/Sema/SemaStmt.cpp<br>    cfe/trunk/lib/Sema/TreeTransform.h<br>    cfe/trunk/test/Sema/block-return.c<br>    cfe/trunk/test/SemaCXX/instantiate-blocks.cpp<br><br>Modified: cfe/trunk/include/clang/AST/Decl.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=145774&r1=145773&r2=145774&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=145774&r1=145773&r2=145774&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/AST/Decl.h (original)<br>+++ cfe/trunk/include/clang/AST/Decl.h Sat Dec  3 11:47:53 2011<br>@@ -2981,6 +2981,7 @@<br>   // FIXME: This can be packed into the bitfields in Decl.<br>   bool IsVariadic : 1;<br>   bool CapturesCXXThis : 1;<br>+  bool BlockMissingReturnType : 1;<br>   /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal<br>   /// parameters of this function.  This is null if a prototype or if there are<br>   /// no formals.<br>@@ -2997,6 +2998,7 @@<br>   BlockDecl(DeclContext *DC, SourceLocation CaretLoc)<br>     : Decl(Block, DC, CaretLoc), DeclContext(Block),<br>       IsVariadic(false), CapturesCXXThis(false),<br>+      BlockMissingReturnType(true),<br>       ParamInfo(0), NumParams(0), Body(0),<br>       SignatureAsWritten(0), Captures(0), NumCaptures(0) {}<br><br>@@ -3054,6 +3056,8 @@<br>   capture_const_iterator capture_end() const { return Captures + NumCaptures; }<br><br>   bool capturesCXXThis() const { return CapturesCXXThis; }<br>+  bool blockMissingReturnType() const { return BlockMissingReturnType; }<br>+  void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; }<br><br>   bool capturesVariable(const VarDecl *var) const;<br><br><br>Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=145774&r1=145773&r2=145774&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=145774&r1=145773&r2=145774&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Dec  3 11:47:53 2011<br>@@ -4061,6 +4061,9 @@<br>   "volatile and restrict|const, volatile, and restrict}5 vs "<br>   "%select{none|const|restrict|const and restrict|volatile|const and volatile|"<br>   "volatile and restrict|const, volatile, and restrict}6)}4">;<br>+def err_typecheck_missing_return_type_incompatible : Error<<br>+  "return type %0 must match previous return type %1 when block"<br>+  " literal has unspecified explicit return type">;<br><br> def warn_incompatible_qualified_id : Warning<<br>   "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"<br><br>Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=145774&r1=145773&r2=145774&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=145774&r1=145773&r2=145774&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Dec  3 11:47:53 2011<br>@@ -8715,8 +8715,10 @@<br>   // return type.  TODO:  what should we do with declarators like:<br>   //   ^ * { ... }<br>   // If the answer is "apply template argument deduction"....<br>-  if (RetTy != Context.DependentTy)<br>+  if (RetTy != Context.DependentTy) {<br>     CurBlock->ReturnType = RetTy;<br>+    CurBlock->TheDecl->setBlockMissingReturnType(false);<br>+  }<br><br>   // Push block parameters from the declarator if we had them.<br>   SmallVector<ParmVarDecl*, 8> Params;<br><br>Modified: cfe/trunk/lib/Sema/SemaStmt.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=145774&r1=145773&r2=145774&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=145774&r1=145773&r2=145774&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaStmt.cpp Sat Dec  3 11:47:53 2011<br>@@ -1809,6 +1809,16 @@<br>   } else if (!RetValExp) {<br>     return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));<br>   } else if (!RetValExp->isTypeDependent()) {<br>+    if (CurBlock->TheDecl->blockMissingReturnType()) {<br>+      // when block's return type is not specified, all return types<br>+      // must strictly match.<br>+      if (Context.getCanonicalType(FnRetType) != <br>+          Context.getCanonicalType(RetValExp->getType())) {<br></div></blockquote><div><br></div><div>Context.hasSameType(FnRetType, RetValExp->getType()) would be a little cleaner. </div><br></div><div>More importantly, I think this is the wrong place for this check, because the code isn't performing function or array lvalue conversions before checking the type of the return expression. I suggest making sure that blocks with inferred return types always go into this code:</div><div><br></div><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  <span style="color: #b930a1">if</span> (CurBlock-><span style="color: #518187">ReturnType</span>.<span style="color: #33595d">isNull</span>()) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    <span style="color: #b930a1">if</span> (RetValExp) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(0, 131, 17); "><span style="color: #000000">      </span>// Don't call UsualUnaryConversions(), since we don't want to do</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(0, 131, 17); "><span style="color: #000000">      </span>// integer promotions here.</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(51, 89, 93); "><span style="color: #000000">      </span><span style="color: #518187">ExprResult</span><span style="color: #000000"> Result = </span>DefaultFunctionArrayLvalueConversion<span style="color: #000000">(RetValExp);</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #b930a1">if</span> (Result.<span style="color: #33595d">isInvalid</span>())</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        <span style="color: #b930a1">return</span> <span style="color: #33595d">StmtError</span>();</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      RetValExp = Result.<span style="color: #33595d">take</span>();</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #b930a1">if</span> (!RetValExp-><span style="color: #33595d">isTypeDependent</span>()) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        CurBlock-><span style="color: #518187">ReturnType</span> = RetValExp-><span style="color: #33595d">getType</span>();</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        <span style="color: #b930a1">if</span> (<span style="color: #518187">BlockDeclRefExpr</span> *CDRE = <span style="color: #3e217f">dyn_cast</span><<span style="color: #518187">BlockDeclRefExpr</span>>(RetValExp)) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(0, 131, 17); "><span style="color: #000000">          </span>// We have to remove a 'const' added to copied-in variable which was</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(0, 131, 17); "><span style="color: #000000">          </span>// part of the implementation spec. and not the actual qualifier for</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(0, 131, 17); "><span style="color: #000000">          </span>// the variable.</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">          <span style="color: #b930a1">if</span> (CDRE-><span style="color: #33595d">isConstQualAdded</span>())</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">            CurBlock-><span style="color: #518187">ReturnType</span>.<span style="color: #33595d">removeLocalConst</span>(); <span style="color: #008311">// FIXME: local???</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      } <span style="color: #b930a1">else</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        CurBlock-><span style="color: #518187">ReturnType</span> = <span style="color: #33595d">Context</span>.<span style="color: #33595d">DependentTy</span>;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    } <span style="color: #b930a1">else</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      CurBlock-><span style="color: #518187">ReturnType</span> = <span style="color: #33595d">Context</span>.<span style="color: #33595d">VoidTy</span>;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  }</div><div><br></div><div>so they all get the same adjustments before checking against previously-deduced return types.</div></div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">      </span>- Doug</div><br></body></html>