================
Comment at: lib/Analysis/UninitializedValues.cpp:571
@@ +570,3 @@
+ if (ME == findLeftmostMemberExpr(ME) &&
+ ME->getMemberDecl()->getType()->isReferenceType()) {
+ classify(ME, Use);
----------------
Richard Smith wrote:
> Enrico Pertoso wrote:
> > Richard Smith wrote:
> > > Seems this case should apply if any of the `FieldDecls` in the chain are
> > > of reference type, not just if the last one is.
> > I'm not sure I understand:
> >
> > lang=c++
> > struct A {
> > int &a;
> > };
> > struct B {
> > A &a;
> > B(int) {}
> > };
> > struct C {
> > B &ref;
> > B b;
> > C() : b(ref.a.a) {}
> > C(B &o) : b(o.a.a) {}
> > };
> >
> > The only thing we know here is that "ref" is uninitialized.
> > Do you have anything specific in mind?
> Suppose we had:
>
> struct A { int n; };
> struct B { A &a; };
> struct C {
> int n;
> B b;
> C(A &a) : b{a}, n(b.a.n = 0) {}
> };
>
> Here (because the `n` initializer runs before the `b` initializer), `b` is
> uninitialized in the `b.a.n = 0` expression. Because `b.a` is a reference,
> that expression is a use of `b`, not an initialization of it. So we should
> diagnose this.
Thanks, you helped me diagnose a bigger problem here (record access wasn't
being counted as use in general).
I did this because when you have
lang=c++
struct A {
int &a;
int &b;
int n;
A() : a(b), n(b) {}
};
the use of ##b## in ##n(b)## will be detected because of the lvalue-to-rvalue
cast, but there's no such cast on references.
Each ##MemberExpr## is visited, so the code warns on your example. I've added a
test case.
================
Comment at: lib/Analysis/UninitializedValues.cpp:581-586
@@ -426,1 +580,8 @@
+void ClassifyRefs::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
+ if (DIE->getExpr() == 0)
+ return;
+ CXXDefaultInitExprVisitor<ClassifyRefs> V(*this);
+ V.Visit((Stmt*) DIE->getExpr());
+}
+
----------------
Richard Smith wrote:
> Enrico Pertoso wrote:
> > Richard Smith wrote:
> > > This looks suspicious. If we're visiting a `CXXDefaultInitExpr` for an
> > > object other than `this`, and that initializer references `this`, we'll
> > > think that we have a reference to one of our subobjects, but we don't.
> > ##isTrackedField## verifies that the specified field has the same parent of
> > the constructor. A ##CXXDefaultInitExpr## appears either in a
> > ##CtorInitializer## or within the context of (c++1y) aggregate
> > initialization, in which case the record of the current constructor and
> > that of any ##MemberExpr## in the aggregate can't be the same.
> I don't think that is the case. For instance:
>
> struct A {
> int a;
> int b;
> int c;
> struct B;
> A();
> };
> struct A::B : A {
> int d = (c = 0);
> };
> A::A() : a(B{}.d), b(c) {} // B{} should not mark our `c` as initialized.
>
> As I alluded to in another comment, I think we could handle this correctly by
> not walking into a `CXXDefaultInitExpr` in aggregate initialization (perhaps
> only walk into them when they appear at the top level in a `CtorInitializer`,
> and do that in the CFG builder).
In that case ##B{}## is a ##CXXConstructExpr##. You can't use aggregate
initialization for ##B## because it has a base class.
Unless there's a change in the aggregate definition after n3653.
================
Comment at: lib/Analysis/UninitializedValues.cpp:555
@@ +554,3 @@
+ case CK_ArrayToPointerDecay:
+ classify(CE->getSubExpr(), Ignore);
+ break;
----------------
Richard Smith wrote:
> Enrico Pertoso wrote:
> > Richard Smith wrote:
> > > This looks curious. Treating this case as `Init` seems appropriate to me:
> > > we don't track how the resulting pointer is used, and it might be used to
> > > initialize the object. Is the idea to ignore all array subobjects of
> > > class type in the analysis? That is:
> > >
> > > struct X {
> > > int a[3];
> > > int b;
> > > };
> > > struct Y {
> > > X x;
> > > Y() {
> > > x.a[0] = 1; // don't treat 'x' as initialized
> > > x.a[1] = x.b; // warning: 'x' used uninitialized
> > > }
> > > };
> > >
> > > If so, this really deserves a comment.
> > This is actually another case in which ##x## is treated as initialized
> > because the default constructor is called, hence ##x## is immediately
> > treated as initialized.
> > The analysis could potentially be made smarter for aggregates, but I'm not
> > sure this patch is the best place to do it.
> >
> > This was intended for:
> >
> > lang=c++
> > void foo(int *a);
> > struct X {
> > int a[3];
> > int b;
> > X() {
> > foo(a);
> > b = a[1]; // do not warn on 'a' here.
> > }
> > };
> >
> > But actually it's not necessary because the current code is not classifying
> > ##ArraySubscriptExprs##.
> > Should I try to deal with ##ArraySubscriptExpr## it in this same patch?
> My preference would be to keep this patch as small as possible while adding
> the new constructor-handling functionality. I'd prefer for
> `ArraySubscriptExpr` support to be added separately if that's practical.
Acknowledged.
================
Comment at: lib/Analysis/UninitializedValues.cpp:795-796
@@ +794,4 @@
+ E = UO->getSubExpr()->IgnoreParenCasts();
+ else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E))
+ E = ASE->getLHS()->IgnoreParenCasts();
+ } while (OE != E);
----------------
Richard Smith wrote:
> Enrico Pertoso wrote:
> > Richard Smith wrote:
> > > I assume you're trying to cope with `this[0].blah` here? This doesn't
> > > look quite right: it'll also find `this[-1].blah` (which might sometimes
> > > be valid) and will do the wrong thing on `0[this].blah`. Maybe just drop
> > > the array indexing support here -- it's a corner case and not worth the
> > > cost of getting all the details right.
> > Actually no. This just detects things like
> >
> > lang=c++
> > struct X {
> > int x, y;
> > X(int f) {
> > reinterpret_cast<int*>(this)[0] = f;
> > y = x;
> > }
> > };
> >
> > Warning on ##y = x## is wrong. On the other hand, I'm simply doing as if
> > ##this## escaped analysis here, and yes, it won't work on
> > ##0[reinterpret_cast<int*>(this)] = f##.
> > It's still seems to be a corner case, though, plus it's not warning on
> > member access via ##this[0]##.
> >
> > Should I still drop this?
> Unless you have real-world examples of bugs the extra accuracy catches here,
> I'd prefer to drop this for simplicity's sake.
Actually, it prevents a false warning, but it's still not common. I'll get rid
of it.
And I've realized that this function could get into an infinite loop. Fixed
that.
================
Comment at: test/SemaCXX/uninitialized.cpp:444
@@ +443,3 @@
+ J() : a(1) {
+ float f = b;
+ b = -f;
----------------
Richard Smith wrote:
> Enrico Pertoso wrote:
> > Richard Smith wrote:
> > > We should really warn on this. A FIXME for that would be nice.
> > I don't think we should. ##J## is a union, and one of its fields (##a##)
> > has been initialized.
> > If you're really sure that a warning should still be issued here, it's
> > actually easier to do so rather than not.
> Well, it's undefined behavior to write to field `a` then read from field `b`.
> The "uninitialized" warning isn't really the right one to issue, though, so I
> think your approach in this patch is fine.
Acknowledged.
================
Comment at: lib/Analysis/UninitializedValues.cpp:317-323
@@ +316,9 @@
+ void VisitStmt(Stmt* S) {
+ llvm::SmallVector<Stmt*, 12> children;
+ for (Stmt::child_range I = S->children(); I; ++I) {
+ children.push_back(*I);
+ }
+ for (std::size_t i = children.size(); i > 0; --i) {
+ Visit(children[i - 1]);
+ }
+ }
----------------
Richard Smith wrote:
> Enrico Pertoso wrote:
> > Richard Smith wrote:
> > > Why do you need the extra complexity of building a list and iterating
> > > backwards here, rather than just visiting the children inside the first
> > > loop?
> > That's the way statements are appended to the CFG in the base case.
> > But it doesn't seem to cause problems if I don't do it here (##classify##
> > is always called when there's enough context).
> >
> Hmm, does this do good things if there is control flow in the
> `CXXDefaultInitExpr`?
>
> struct S {
> enum Kind { Foo, Bar } K;
> int FooVal;
> int BarVal;
> int Value = K == Foo ? FooVal : BarVal;
> S() : K(Foo), FooVal(0) {} // warning about uninitialized use of BarVal?
> };
>
> Maybe we should teach the CFG builder to inline `CXXDefaultInitExprs` when
> they appear as a `CXXCtorInitializer`? That should not break the CFG's
> invariants, and allow you to drop a lot (all?) of your special-case handling
> for them (since you don't actually want to walk into them when they occur
> within aggregate initialization).
The only difference I see is that, as there's no control flow information at
all, what's usually reported as sometimes uninitialized will be reported as
always uninitialized.
But I'll have a look at the ##CFGBuilder##.
================
Comment at: include/clang/Analysis/Analyses/UninitializedValues.h:51
@@ -49,1 +50,3 @@
+ /// If the use refers to a field, the use happens in this constructor.
+ const CXXConstructorDecl *Constructor;
----------------
Richard Smith wrote:
> Please extend the comment here: something like "If the use happens in a
> default initializer for a field, this is the constructor in which the default
> initializer was used."
Done.
================
Comment at: include/clang/Analysis/Analyses/UninitializedValues.h:73
@@ -67,2 +72,3 @@
const Expr *getUser() const { return User; }
+ const CXXConstructorDecl *getConstructor() const { return Constructor; }
----------------
Richard Smith wrote:
> Maybe `getConstructorForDefaultInit`?
Done.
================
Comment at: lib/Analysis/UninitializedValues.cpp:529
@@ +528,3 @@
+ Ex = stripCasts(DC->getParentASTContext(), UO->getSubExpr());
+ classify(Ex, (*I)->getType().isConstQualified() ? Ignore : Init);
+ }
----------------
Enrico Pertoso wrote:
> Richard Smith wrote:
> > Did you mean to use `IsPointerToConst` here?
> Done.
I've changed this a bit to make sure that #IsPointerToConst()## is only called
if ##(*I)->isGLValue()## is false. This is to avoid a regression for cases like:
lang=c++
int foo(const int *&a) { a = &some_global_int_; }
void bar() {
const int *j;
foo(j); // don't classify the DeclRefExpr for j as Ignore here, just let it
escape
int a = *j;
}
http://llvm-reviews.chandlerc.com/D2181
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits