diff options
| author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-07-31 20:45:53 +0000 |
|---|---|---|
| committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-07-31 20:45:53 +0000 |
| commit | a657a32cc8fe05cd6fdb1578834a719c169493ae (patch) | |
| tree | 1ce53125b4393b867acb0f5adbfa80e4b21ee364 /clang/test/Analysis | |
| parent | 118c47b6d19acfaed0405773ff00ccd690dfd179 (diff) | |
| download | bcm5719-llvm-a657a32cc8fe05cd6fdb1578834a719c169493ae.tar.gz bcm5719-llvm-a657a32cc8fe05cd6fdb1578834a719c169493ae.zip | |
[CFG] [analyzer] Implement function argument construction contexts.
In r330377 and r338425 we have already identified what constitutes function
argument constructors and added stubs in order to prevent confusing them
with other temporary object constructors.
Now we implement a ConstructionContext sub-class to carry all the necessary
information about the construction site, namely call expression and argument
index.
On the analyzer side, the patch interacts with the recently implemented
pre-C++17 copy elision support in an interesting manner. If on the CFG side we
didn't find a construction context for the elidable constructor, we build
the CFG as if the elidable constructor is not elided, and the non-elided
constructor within it is a simple temporary. But the same problem may occur
in the analyzer: if the elidable constructor has a construction context but
the analyzer doesn't implement such context yet, the analyzer should also
try to skip copy elision and still inline the non-elided temporary constructor.
This was implemented by adding a "roll back" mechanism: when elision fails,
roll back the changes and proceed as if it's a simple temporary. The approach
is wonky, but i'm fine with that as long as it's merely a defensive mechanism
that should eventually go away once all construction contexts become supported.
Differential Revision: https://reviews.llvm.org/D48681.
llvm-svn: 338436
Diffstat (limited to 'clang/test/Analysis')
| -rw-r--r-- | clang/test/Analysis/cfg-rich-constructors.cpp | 52 | ||||
| -rw-r--r-- | clang/test/Analysis/cfg-rich-constructors.mm | 8 |
2 files changed, 44 insertions, 16 deletions
diff --git a/clang/test/Analysis/cfg-rich-constructors.cpp b/clang/test/Analysis/cfg-rich-constructors.cpp index d66c9d31185..88b03788da4 100644 --- a/clang/test/Analysis/cfg-rich-constructors.cpp +++ b/clang/test/Analysis/cfg-rich-constructors.cpp @@ -826,21 +826,49 @@ void useC(C c); void useCByReference(const C &c); void useD(D d); void useDByReference(const D &d); +void useCAndD(C c, D d); -// FIXME: Find construction context for the argument. // CHECK: void passArgument() // CHECK: 1: useC // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class C)) -// CXX11-NEXT: 3: C() (CXXConstructExpr, [B1.4], class C) +// CXX11-ELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], [B1.5], class C) +// CXX11-NOELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], class C) // CXX11-NEXT: 4: [B1.3] -// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, class C) +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6]+0, class C) // CXX11-NEXT: 6: [B1.2]([B1.5]) -// CXX17-NEXT: 3: C() (CXXConstructExpr, class C) +// CXX17-NEXT: 3: C() (CXXConstructExpr, [B1.4]+0, class C) // CXX17-NEXT: 4: [B1.2]([B1.3]) void passArgument() { useC(C()); } +// CHECK: void passTwoArguments() +// CHECK: [B1] +// CHECK-NEXT: 1: useCAndD +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class C, class argument_constructors::D)) +// CXX11-ELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], [B1.5], class C) +// CXX11-NOELIDE-NEXT: 3: C() (CXXConstructExpr, [B1.4], class C) +// CXX11-NEXT: 4: [B1.3] +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.12]+0, class C) +// CXX11-ELIDE-NEXT: 6: argument_constructors::D() (CXXConstructExpr, [B1.7], [B1.9], [B1.10], class argument_constructors::D) +// CXX11-NOELIDE-NEXT: 6: argument_constructors::D() (CXXConstructExpr, [B1.7], [B1.9], class argument_constructors::D) +// CXX11-NEXT: 7: [B1.6] (BindTemporary) +// CXX11-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 9: [B1.8] +// CXX11-NEXT: 10: [B1.9] (CXXConstructExpr, [B1.11], [B1.12]+1, class argument_constructors::D) +// CXX11-NEXT: 11: [B1.10] (BindTemporary) +// CXX11-NEXT: 12: [B1.2]([B1.5], [B1.11]) +// CXX11-NEXT: 13: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 14: ~argument_constructors::D() (Temporary object destructor) +// CXX17-NEXT: 3: C() (CXXConstructExpr, [B1.6]+0, class C) +// CXX17-NEXT: 4: argument_constructors::D() (CXXConstructExpr, [B1.5], [B1.6]+1, class argument_co +// CXX17-NEXT: 5: [B1.4] (BindTemporary) +// CXX17-NEXT: 6: [B1.2]([B1.3], [B1.5]) +// CXX17-NEXT: 7: ~argument_constructors::D() (Temporary object destructor) +void passTwoArguments() { + useCAndD(C(), D()); +} + // CHECK: void passArgumentByReference() // CHECK: 1: useCByReference // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class C &)) @@ -852,20 +880,20 @@ void passArgumentByReference() { useCByReference(C()); } -// FIXME: Find construction context for the argument. // CHECK: void passArgumentWithDestructor() // CHECK: 1: useD // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class argument_constructors::D)) -// CXX11-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], class argument_constructors::D) +// CXX11-ELIDE-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], [B1.7], class argument_constructors::D) +// CXX11-NOELIDE-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], class argument_constructors::D) // CXX11-NEXT: 4: [B1.3] (BindTemporary) // CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class argument_constructors::D) // CXX11-NEXT: 6: [B1.5] -// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, class argument_constructors::D) +// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], [B1.9]+0, class argument_constructors::D) // CXX11-NEXT: 8: [B1.7] (BindTemporary) // CXX11-NEXT: 9: [B1.2]([B1.8]) // CXX11-NEXT: 10: ~argument_constructors::D() (Temporary object destructor) // CXX11-NEXT: 11: ~argument_constructors::D() (Temporary object destructor) -// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, class argument_constructors::D) +// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.5]+0, class argument_constructors::D) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // CXX17-NEXT: 5: [B1.2]([B1.4]) // CXX17-NEXT: 6: ~argument_constructors::D() (Temporary object destructor) @@ -886,13 +914,13 @@ void passArgumentWithDestructorByReference() { useDByReference(D()); } -// FIXME: Find construction context for the argument. // CHECK: void passArgumentIntoAnotherConstructor() -// CXX11: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], class argument_constructors::D) +// 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, class argument_constructors::D) +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], [B1.7]+0, class argument_constructors::D) // CXX11-NEXT: 6: [B1.5] (BindTemporary) // CXX11-ELIDE-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.9], [B1.10], class argument_constructors::E) // CXX11-NOELIDE-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.9], class argument_constructors::E) @@ -902,7 +930,7 @@ void passArgumentWithDestructorByReference() { // CXX11-NEXT: 11: argument_constructors::E e = argument_constructors::E(argument_constructors::D()); // CXX11-NEXT: 12: ~argument_constructors::D() (Temporary object destructor) // CXX11-NEXT: 13: ~argument_constructors::D() (Temporary object destructor) -// CXX17: 1: argument_constructors::D() (CXXConstructExpr, class argument_constructors::D) +// CXX17: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.3]+0, class argument_constructors::D) // CXX17-NEXT: 2: [B1.1] (BindTemporary) // CXX17-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class argument_constructors::E) // CXX17-NEXT: 4: argument_constructors::E([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class argument_constructors::E) diff --git a/clang/test/Analysis/cfg-rich-constructors.mm b/clang/test/Analysis/cfg-rich-constructors.mm index 0b81e274e96..289094293eb 100644 --- a/clang/test/Analysis/cfg-rich-constructors.mm +++ b/clang/test/Analysis/cfg-rich-constructors.mm @@ -18,21 +18,21 @@ public: -(D) bar; @end -// FIXME: Find construction context for the argument. // CHECK: void passArgumentIntoMessage(E *e) // CHECK: 1: e // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, E *) -// CXX11-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.6], class D) +// CXX11-ELIDE-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.6], [B1.7], class D) +// CXX11-NOELIDE-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.6], class D) // CXX11-NEXT: 4: [B1.3] (BindTemporary) // CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class D) // CXX11-NEXT: 6: [B1.5] -// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, class D) +// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], [B1.9]+0, class D) // CXX11-NEXT: 8: [B1.7] (BindTemporary) // Double brackets trigger FileCheck variables, escape. // CXX11-NEXT: 9: {{\[}}[B1.2] foo:[B1.8]] // CXX11-NEXT: 10: ~D() (Temporary object destructor) // CXX11-NEXT: 11: ~D() (Temporary object destructor) -// CXX17-NEXT: 3: D() (CXXConstructExpr, class D) +// CXX17-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.5]+0, class D) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // Double brackets trigger FileCheck variables, escape. // CXX17-NEXT: 5: {{\[}}[B1.2] foo:[B1.4]] |

