NoQ created this revision. NoQ added reviewers: dcoughlin, xazax.hun, a.sidorin, george.karpenkov, szepet, rnkovacs. Herald added subscribers: cfe-commits, mikhail.ramalho, baloghadamsoftware.
`CXXTemporaryObjectExpr` is a sub-class of `CXXConstructExpr` that represents a construct-expression written as `T(Arg1, ..., ArgN)`, where `N` is not equal to 1. If `N` is equal to 1, such expression is parsed as a construction conversion from type of `Arg1` to type `T` instead. Not every temporary object is represented by `CXXTemporaryObjectExpr` (for instance, implicit temporary copies aren't), and `CXXTemporaryObjectExpr` doesn't necessarily represent a temporary object (constructor written as a `CXXTemporaryObjectExpr` may construct a pretty much arbitrary object if copy elision kicks in). If any of `Arg1`, ..., `ArgN` requires construction, give it a construction context of an argument. For now it only works for `CXXConstructExpr`s that aren't `CXXTemporaryObjectExpr`s. I forgot to add it when i was adding stubs for `CXXConstructExpr` argument constructors in https://reviews.llvm.org/D48249. I thought i had a test for it (`passArgumentIntoAnotherConstructor()`), but in fact in this test `N` was equal to 1, so it wasn't really testing a `CXXTemporaryObjectExpr`. Repository: rC Clang https://reviews.llvm.org/D50487 Files: lib/Analysis/CFG.cpp test/Analysis/cfg-rich-constructors.cpp Index: test/Analysis/cfg-rich-constructors.cpp =================================================================== --- test/Analysis/cfg-rich-constructors.cpp +++ test/Analysis/cfg-rich-constructors.cpp @@ -820,6 +820,7 @@ class E { public: E(D d); + E(D d1, D d2); }; void useC(C c); @@ -939,6 +940,38 @@ void passArgumentIntoAnotherConstructor() { E e = E(D()); } + + +// CHECK: void passTwoArgumentsIntoAnotherConstructor() +// CXX11-ELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class argument_constructors::D) +// CXX11-NOELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], class argument_constructors::D) +// CXX11-NEXT: 2: [B1.1] (BindTemporary) +// CXX11-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 4: [B1.3] +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], [B1.13]+0, class argument_constructors::D) +// CXX11-NEXT: 6: [B1.5] (BindTemporary) +// CXX11-ELIDE-NEXT: 7: argument_constructors::D() (CXXConstructExpr, [B1.8], [B1.10], [B1.11], class argument_constructors::D) +// CXX11-NOELIDE-NEXT: 7: argument_constructors::D() (CXXConstructExpr, [B1.8], [B1.10], class argument_constructors::D) +// CXX11-NEXT: 8: [B1.7] (BindTemporary) +// CXX11-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 10: [B1.9] +// CXX11-NEXT: 11: [B1.10] (CXXConstructExpr, [B1.12], [B1.13]+1, class argument_constructors::D) +// CXX11-NEXT: 12: [B1.11] (BindTemporary) +// CXX11-NEXT: 13: argument_constructors::E([B1.6], [B1.12]) (CXXConstructExpr, class argument_constructors::E) +// CXX11-NEXT: 14: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 15: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 16: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 17: ~argument_constructors::D() (Temporary object destructor) +// CXX17: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.5]+0, class argument_constructors::D) +// CXX17-NEXT: 2: [B1.1] (BindTemporary) +// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.5]+1, class argument_constructors::D) +// CXX17-NEXT: 4: [B1.3] (BindTemporary) +// CXX17-NEXT: 5: argument_constructors::E([B1.2], [B1.4]) (CXXConstructExpr, class argument_constructors::E) +// CXX17-NEXT: 6: ~argument_constructors::D() (Temporary object destructor) +// CXX17-NEXT: 7: ~argument_constructors::D() (Temporary object destructor) +void passTwoArgumentsIntoAnotherConstructor() { + E(D(), D()); +} } // end namespace argument_constructors namespace copy_elision_with_extra_arguments { Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -4352,6 +4352,11 @@ CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, AddStmtChoice asc) { + // If the constructor takes objects as arguments by value, we need to properly + // construct these objects. Construction contexts we find here aren't for the + // constructor C, they're for its arguments only. + findConstructionContextsForArguments(C); + autoCreateBlock(); appendConstructor(Block, C); return VisitChildren(C);
Index: test/Analysis/cfg-rich-constructors.cpp =================================================================== --- test/Analysis/cfg-rich-constructors.cpp +++ test/Analysis/cfg-rich-constructors.cpp @@ -820,6 +820,7 @@ class E { public: E(D d); + E(D d1, D d2); }; void useC(C c); @@ -939,6 +940,38 @@ void passArgumentIntoAnotherConstructor() { E e = E(D()); } + + +// CHECK: void passTwoArgumentsIntoAnotherConstructor() +// CXX11-ELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class argument_constructors::D) +// CXX11-NOELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], class argument_constructors::D) +// CXX11-NEXT: 2: [B1.1] (BindTemporary) +// CXX11-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 4: [B1.3] +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], [B1.13]+0, class argument_constructors::D) +// CXX11-NEXT: 6: [B1.5] (BindTemporary) +// CXX11-ELIDE-NEXT: 7: argument_constructors::D() (CXXConstructExpr, [B1.8], [B1.10], [B1.11], class argument_constructors::D) +// CXX11-NOELIDE-NEXT: 7: argument_constructors::D() (CXXConstructExpr, [B1.8], [B1.10], class argument_constructors::D) +// CXX11-NEXT: 8: [B1.7] (BindTemporary) +// CXX11-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 10: [B1.9] +// CXX11-NEXT: 11: [B1.10] (CXXConstructExpr, [B1.12], [B1.13]+1, class argument_constructors::D) +// CXX11-NEXT: 12: [B1.11] (BindTemporary) +// CXX11-NEXT: 13: argument_constructors::E([B1.6], [B1.12]) (CXXConstructExpr, class argument_constructors::E) +// CXX11-NEXT: 14: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 15: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 16: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 17: ~argument_constructors::D() (Temporary object destructor) +// CXX17: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.5]+0, class argument_constructors::D) +// CXX17-NEXT: 2: [B1.1] (BindTemporary) +// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.5]+1, class argument_constructors::D) +// CXX17-NEXT: 4: [B1.3] (BindTemporary) +// CXX17-NEXT: 5: argument_constructors::E([B1.2], [B1.4]) (CXXConstructExpr, class argument_constructors::E) +// CXX17-NEXT: 6: ~argument_constructors::D() (Temporary object destructor) +// CXX17-NEXT: 7: ~argument_constructors::D() (Temporary object destructor) +void passTwoArgumentsIntoAnotherConstructor() { + E(D(), D()); +} } // end namespace argument_constructors namespace copy_elision_with_extra_arguments { Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -4352,6 +4352,11 @@ CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, AddStmtChoice asc) { + // If the constructor takes objects as arguments by value, we need to properly + // construct these objects. Construction contexts we find here aren't for the + // constructor C, they're for its arguments only. + findConstructionContextsForArguments(C); + autoCreateBlock(); appendConstructor(Block, C); return VisitChildren(C);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits