[cfe-dev] fix for Clang PR 8419

Zhongxing Xu xuzhongxing at gmail.com
Fri Nov 19 19:45:40 PST 2010


2010/11/20 Zhanyong Wan (λx.x x) <wan at google.com>

> Hi Ted,
>
> Thanks for the quick feedback!  I'll respond to your comments about
> the code comments later, as they are less important.
>
> On Fri, Nov 19, 2010 at 2:09 PM, Ted Kremenek <kremenek at apple.com> wrote:
> > On Nov 19, 2010, at 10:38 AM, Zhanyong Wan (λx.x x) wrote:
> >
> > I think the motivation behind this change is right, but not the change
> > itself.
> > The problem with VisitChildren() is that it has no context of whether
> > 'Terminator' (which is misnamed) expects the subexpression to be
> evaluated
> > as an lvalue.  Since your logic is specific to CallExpr, it really could
> > just be sunk into processing of CallExpr itself.  When the caller passses
> > down 'AsLValue', it is indicating that the parent expects that the child
> is
> > evaluated as an lvalue, but that's based on the parent's context.  There
> is
> > no such information here.
>
> Thanks for explaining.  It's a revelation to me to learn that:
>
> 1. The "AsLValue" bit encodes whether the *consumer* of an expression
>   uses it as an LValue, not whether the expression itself is an LValue.
>

This is right.


>
> 2. The caller of Visit*() must provide this bit accurately.  It's not
>   OK for the caller to be "conservative" (i.e. say "AsLValue" when
>   the consumer of the expression only needs an RValue).
>

I don't quite understand this point.

Just like Ted said, the first step of the fix is:

when the 'foo()' is added as the block-level expr in CFG construction, its
kind should be StatementAsLValue, and this should be confined in the unary
operator case.


>
> I suspected #1 was the case, but wasn't certain.  I wasn't sure about
> #2 at all (hence my patch is the way it is).  The fact that all tests
> passed with the patch led me to think that it's fine for the caller of
> Visit*() to say AsLValue when only an RValue is needed.  Now I see
> that it's just inadequate test coverage.
>
> I'll document this in my new patch.  Also, how would you suggest to
> add a test to catch violation of #2?
>
> > Further, I think it's no technically correct.  Consider:
> > const int &foo();
> > int i = foo();
> > This is what the AST looks like for the second line:
> >   (DeclStmt 0x101842c18 <line:3:3, col:16>
> >     0x101818510 "int i =
> >       (CallExpr 0x1018185d8 <col:11, col:15> 'const int' lvalue
> >         (ImplicitCastExpr 0x1018185b8 <col:11> 'const int &(*)(void)'
> > <FunctionToPointerDecay>
> >           (DeclRefExpr 0x101818560 <col:11> 'const int &(void)' lvalue
> > FunctionDecl='foo' 0x101818450)))"))
> > In this example, CallExpr does indeed return an lvalue.  The problem is
> that
> > there is an implicit lvalue-to-rvalue conversion.  So the semantics
> really
> > are:
> >   (DeclStmt 0x101842c18 <line:3:3, col:16>
> >     0x101818510 "int i =
> >       (RValueConversion <--- I made this up
> >         (CallExpr 0x1018185d8 <col:11, col:15> 'const int' lvalue
> >           (ImplicitCastExpr 0x1018185b8 <col:11> 'const int &(*)(void)'
> > <FunctionToPointerDecay>
> >             (DeclRefExpr 0x101818560 <col:11> 'const int &(void)' lvalue
> > FunctionDecl='foo' 0x101818450)))"))
> > Currently we don't represent lvalue-to-rvalue conversions explicitly in
> the
> > AST, although in my conversations with John McCall there is interest in
> > doing this.  The problem with your patch is that the parent expression
> may
> > actually expect that there is an rvalue, even though the subexpression
> > returns an lvalue.  Your patch doesn't actually address this problem at
> all,
> > but actually papers over it.
> > Codegen goes through some histrionics to infer these semantics from the
> AST,
> > but they analyzer mostly goes off the AST itself for semantics.  As you
> can
> > see this is a problem, since we really have no "sequence point" for the
> > analyzer to do the lvalue-to-rvalue conversion.  We get around this
> > limitation in various places when it comes to C-style constructs, but
> there
> > are many corner cases for C++.
>
> This is really unfortunate. :-(
>
> > In this particular case, I think we need to add special support in the
> CFG
> > builder for UnaryOperator.  Specifically, we need to add a
> > 'VisitUnaryOperator' to the CFGBuilder class, and have it determine, base
> on
> > the opcode, whether or not the operation requires the subexpression to be
> an
> > lvalue or rvalue.  It then passes the appropriate value for
> AddStmtChoice.
>
> I'll try that.
>
> One question: for the purpose of the CFG builder, does an LValue have
> to be mutable?  For example, given
>
>  void Foo(const Bar& x) { ... }
>  Bar& GetBar() { ... }
>
> when the analyzer sees "Foo(GetBar());", should it treat "GetBar()" as
> an LValue or RValue?  What if the implementation of Foo() actually
> cares about the identity of the input, e.g.
>
>  void Foo(const Bar& x) {
>    if (&x == &someGlobalBarVairalbe)
>      ...;
>  }
>
> ?  Thanks.
>

In this context, we evaluate GetBar() to its l-value, i.e., a MemRegion.


>
> > Similarly, for CallExprs, any CallExpr that returns a reference needs to
> be
> > treated as returning an lvalue.  The problem here is that we don't have a
> > sequence point for doing arbitrary lvalue-to-rvalue conversion in the
> AST,
> > but this is something we can possibly model in GRExprEngine given enough
> > breadcrumbs in the CFG.
>
> --
> Zhanyong
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20101120/c354b64b/attachment.html>


More information about the cfe-dev mailing list