This is an archive of the discontinued LLVM Phabricator instance.

Add new diagnostic to check for bad member function calls in mem-initializer-lists.
Needs ReviewPublic

Authored by em-bellows on Dec 6 2014, 4:14 AM.

Details

Reviewers
rtrieu
Summary

Hi,

This patch adds a new diagnostic that checks for member function calls before all base classes in a mem-initializer-list are initialized, which is undefined behavior. (C++03 12.6.2p8; C++11 12.6.2p13.)

The added code looks for member call expressions which use implicit or explicit 'this' inside of the arguments of a base class initializer to signal the warning.

Diff Detail

Event Timeline

em-bellows updated this revision to Diff 17020.Dec 6 2014, 4:14 AM
em-bellows retitled this revision from to Add new diagnostic to check for bad member function calls in mem-initializer-lists..
em-bellows updated this object.
em-bellows edited the test plan for this revision. (Show Details)
em-bellows added a reviewer: rsmith.
em-bellows added a subscriber: Unknown Object (MLST).
em-bellows updated this revision to Diff 17061.Dec 8 2014, 4:54 PM

Test suite passes now, didn't realize it wasn't before.

rsmith edited reviewers, added: rtrieu; removed: rsmith.Dec 8 2014, 5:35 PM
rtrieu edited edge metadata.Dec 9 2014, 6:42 PM

Besides the comments above, see http://llvm.org/docs/Phabricator.html#requesting-a-review-via-the-web-interface on how to get a full diff. Giving Phabricator a full diff makes reviewing easier.

lib/Sema/SemaDeclCXX.cpp
2643

There's multiple visitors in Clang. The RecursiveASTVisitor will visit every AST node, including unevaluated contexts such as sizeof expressions. It would be better to use an EvaluatedExprVisitor which ignores unevaluated expressions. Since there already is an EvaluatedExprVisitor for member initializers, it would be a better idea to try to add to that visitor instead of writing your own to minimize how often these expressions are traversed.

The best place to look is HandleMemberExpr inside UninitializedFieldVisitor. This is were all MemberExpr's that need to be checked are funneled into.

test/SemaCXX/member-call-before-bases-init.cpp
1

Merge this test case with uninitalized.cpp. The warnings here and in uninitalized.cpp come from the same warning group and should be kept together in test cases.

31

f() is from class B, which is fully initialized when class C is being constructed. There is no need for a warning here.

33

Add a test case using an unevaluated context to check that no warning is emitted. For example, sizeof(f()) in an initializer.

test/SemaCXX/uninitialized.cpp
1326

Don't trigger the warning here. The existing warning is good enough and the new warning doesn't add anything new here.

1342

Same as above.

Regarding my test case, it is taken almost directly from the C++11 standard I have, and it says the call to the member function 'f' on line 31 of my test case is undefined behavior. Though I'd imagine it would work fine on any reasonable compiler, as it is from the base class B which at that point is initialized as you mentioned.

12.6.2p13 However, if these operations [member function calls as far as this patch considers] are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result of the operation is undefined.

class D : public B, C {
  int i;
  public:
    D() : C(f()), //undefined: calls member function
                  //but base C not yet initialized
    i(f()) { }    //well-defined: bases are all initialized
};

I was hoping to keep this warning as strict as possible, though I realize it is a little surprising. I apologize for not including that context in my summary. I'm new to all of this!

Thank you for the comments and review. I will get to work on everything you mentioned, and I'll make sure to include the full diff next time.