<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Looking through the ‘StarterBug’ tag, I started looking into &lt;<a href="https://bugs.swift.org/browse/SR-580" class="">https://bugs.swift.org/browse/SR-580</a>&gt;, in which:<br class=""><br class="">func foo(x: Int) -&gt; Int {<br class="">&nbsp;var result = x + 1<br class="">#if NOT_ENABLED<br class="">&nbsp;_ = result<br class="">#endif<br class="">&nbsp;return result<br class="">}<br class=""><br class="">does not warn that “result" was never written to.<br class=""><br class="">The immediate cause seems to be in lib/Sema/MiscDiagnostics.cpp, in VarDeclUsageChecker::handleIfConfig(). This code walks the inactive #if blocks and does:<br class=""><br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// If we see a bound reference to a decl in an inactive #if block, then<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// conservatively mark it read and written. &nbsp;This will silence "variable<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// unused" and "could be marked let" warnings for it.<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (auto *DRE = dyn_cast&lt;DeclRefExpr&gt;(E)) {<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VDUC.addMark(DRE-&gt;getDecl(), RK_Read|RK_Written);<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br class=""><br class="">In trying to replace that with something that really walks the Expr (by calling VDUC.walkToExprPre() instead or something of the like), I run into a bunch of checks like this:<br class=""><br class="">&nbsp;// Sema leaves some subexpressions null, which seems really unfortunate. &nbsp;It<br class="">&nbsp;// should replace them with ErrorExpr.<br class="">&nbsp;if (E == nullptr || !E-&gt;getType() || E-&gt;getType()-&gt;is&lt;ErrorType&gt;()) {<br class="">&nbsp;&nbsp;&nbsp;sawError = true;<br class="">&nbsp;&nbsp;&nbsp;return;<br class="">&nbsp;}<br class=""><br class="">And, if I dump the AST for the test case, it has this section with all sorts of nulls:<br class=""><br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(#if_stmt<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(#if:<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(unresolved_decl_ref_expr type='&lt;null&gt;' name=NOT_ENABLED specialized=no)<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(elements<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sequence_expr type='&lt;null&gt;'<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(discard_assignment_expr type='&lt;null&gt;')<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assign_expr<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(**NULL EXPRESSION**)<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(**NULL EXPRESSION**))<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(declref_expr type='&lt;null&gt;' decl=main.(file).func decl.qqq@/Users/bungi/Desktop/SR-580.swift:2:7 specialized=yes))))<br class=""><br class="">Presumably VarDeclUsageChecker::handleIfConfig() could pass the right subset of RK_Read|RK_Written if the declref_expr had its accessType set, or maybe a more complete AST that could be walked.<br class=""><br class="">So, then I started looking into places that look for IfConfig{Stmt,Decl} and bail, and found ASTWalker.cpp’s Traversal::visitIfConfigStmt(), and TypeCheckStmt.cpp’s visitIfConfigStmt(). I hacked in a walk() call in the Traversal case and broke all sorts of stuff (maybe since I didn’t do something similar in TypeCheckStmt.cpp). That was about the point that I thought I’d ask if I’m digging in the wrong spot =)<br class=""><br class="">Presumably making more work get done for inactive #if branches will slow down the compiler some (hopefully the percentage of existing code inside a #if block at all is pretty low). But, worse, I can imaging there is a ton of other stuff in them that will cause errors if more of the compiler runs on them (whole missing types, selectors, …).<br class=""><br class="">Is this direction even worth pursuing? Maybe I should look into whether there is a quicker way to get the access type of the declref_expr set when it is being created during the inactive #if parsing?<br class=""><br class="">Thanks!<br class=""><br class="">-tim<div class=""><br class=""></div></body></html>