<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Feb 20, 2013 at 10:50 AM, Jordan Rose <span dir="ltr"><<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>></span> wrote:<br>


<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Thanks, David!<br>
<br>
Is it all right if I add Optional to clang/Basic/LLVM.h, so that it doesn't have to appear everywhere?<br></blockquote><div><br></div><div>Oh, sure - can't see any reason why not. I realized it's already 'using' in a few of the files I touched & I meant to go back & remove unnecessary qualifications before committing. </div>
<div><br></div><div style>Did this in r175679 after removing an old & crufty version of Optional found in lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp in r175678</div><div> </div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
A few comments inline.<br>
<div><div><br>
<br>
On Feb 19, 2013, at 21:52 , David Blaikie <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> wrote:<br>
<br>
> Author: dblaikie<br>
> Date: Tue Feb 19 23:52:05 2013<br>
> New Revision: 175594<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=175594&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=175594&view=rev</a><br>
> Log:<br>
> Replace SVal llvm::cast support to be well-defined.<br>
><br>
> See r175462 for another example/more details.<br>
><br>
> Modified:<br>
>    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h<br>
>    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h<br>
>    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h<br>
>    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/StreamChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/MemRegion.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/SValBuilder.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/SVals.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp<br>
>    cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp<br>
><br>
<br>
<br>
</div></div><div><div>> Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h?rev=175594&r1=175593&r2=175594&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h?rev=175594&r1=175593&r2=175594&view=diff</a><br>



> ==============================================================================<br>
> --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (original)<br>
> +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h Tue Feb 19 23:52:05 2013<br>
> @@ -69,6 +69,25 @@ protected:<br>
> public:<br>
>   explicit SVal() : Data(0), Kind(0) {}<br>
><br>
> +  template<typename T><br>
> +  T castAs() const {<br>
> +    assert(T::isType(*this));<br>
> +    T t;<br>
> +    SVal& sv = t;<br>
> +    sv = *this;<br>
> +    return t;<br>
> +  }<br>
> +<br>
> +  template<typename T><br>
> +  llvm::Optional<T> getAs() const {<br>
> +    if (!T::isType(*this))<br>
> +      return llvm::Optional<T>();<br>
> +    T t;<br>
> +    SVal& sv = t;<br>
> +    sv = *this;<br>
> +    return t;<br>
> +  }<br>
<br>
</div></div>Bikeshedding to isKind, instead of isType, since "type" is such an overloaded word in Clang already.<br></blockquote><div><br></div><div>Sounds OK to me - just wanted to make sure it wasn't "classof" to ensure it would not be accidentally compatible with llvm::cast (even being private/friended to base could mean llvm::casts could be used in the implementation of SVals which has a fair few casts that could easily have been missed).</div>
<div><br></div><div style>Renamed in r175676</div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Also, capital variable names, and ampersand on the variable name rather than the type.<br>

<br>
I guess Val->SVal::operator=(*this) isn't really cleaner than the reference trick, huh.</blockquote><div><br></div><div>Yeah - if we had an implicit_cast template I'd consider using that: implicit_cast<SVal&>(t) = *this;<br>


<br>But any/all of those options are welcome, none seem terribly much better than others.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
 A bunch of these types didn't have default constructors, though, so I'm wondering if adding T(const SVal &) constructors makes more sense. Eh.<br>

</blockquote><div><br></div><div>It was easier to add default constructors than forwarding constructors - but, yeah, not by much. I'm open to the alternative (that's actually what I'd originally considered, before Richard Smith thought up the base op= method (which, admittedly, worked better in the TypeLoc hierarchy where types were all already default constructible)</div>


<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div>> -  bool isExpression() {<br>
> +  bool isExpression() const {<br>
>     return !isa<SymbolData>(getSymbol());<br>
>   }<br>
<br>
</div>Heh, thanks.<br></blockquote><div><br></div><div>Turns out I didn't actually /need/ this once I fixed Optional's const correctness issues (didn't have non-const overloads for op*/op->) but seemed appropriate anyway.</div>


<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">>   if (originalRegion != R) {<br>
>     if (Optional<SVal> OV = B.getDefaultBinding(R)) {<br>
> -      if (const nonloc::LazyCompoundVal *V =<br>
> -            dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))<br>
> +      if (llvm::Optional<nonloc::LazyCompoundVal> V =<br>
> +              OV.getPointer()->getAs<nonloc::LazyCompoundVal>())<br>
<br>
This is going through another Optional, so you should be able to just use OV->getAs now.<br></blockquote><div><br></div><div>Oh, handy - didn't notice. (I hesitate to suggest it: should we make llvm::cast machinery able to treat Optional like a pointer? (I wonder if we already do this for OwningPtr & whatever other smart pointers we have in LLVM))<br>

<br>The transformation would've been a bit more natural/obvious if this code had used op* in the first place.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">> @@ -1669,9 +1670,8 @@ NonLoc RegionStoreManager::createLazyBin<br>

>   // If we already have a lazy binding, and it's for the whole structure,<br>
>   // don't create a new lazy binding.<br>
>   if (Optional<SVal> V = B.getDefaultBinding(R)) {<br>
> -    const nonloc::LazyCompoundVal *LCV =<br>
> -      dyn_cast<nonloc::LazyCompoundVal>(V.getPointer());<br>
> -    if (LCV) {<br>
> +    if (llvm::Optional<nonloc::LazyCompoundVal> LCV =<br>
> +            V.getPointer()->getAs<nonloc::LazyCompoundVal>()) {<br>
<br>
Ditto.<br></blockquote><div><br></div><div style> Fixed both of these in r175677.</div><div style><br></div><div style>Thanks,</div><div style>- David</div></div></div></div>