diff options
author | Jordan Rose <jordan_rose@apple.com> | 2013-01-30 18:16:06 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2013-01-30 18:16:06 +0000 |
commit | baa7ca1142990e1ad6d4e9d2c73adb749ff50789 (patch) | |
tree | 453101a8e843fd9be1ec32b0ac255dcd7f3a834d /test/Analysis/ctor-inlining.mm | |
parent | 74149595de064572661d10f736c6cb2eda78db8d (diff) |
[analyzer] Model trivial copy/move ctors with an aggregate bind.
This is faster for the analyzer to process than inlining the constructor
and performing a member-wise copy, and it also solves the problem of
warning when a partially-initialized POD struct is copied.
Before:
CGPoint p;
p.x = 0;
CGPoint p2 = p; <-- assigned value is garbage or undefined
After:
CGPoint p;
p.x = 0;
CGPoint p2 = p; // no-warning
This matches our behavior in C, where we don't see a field-by-field copy.
<rdar://problem/12305288>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173951 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Analysis/ctor-inlining.mm')
-rw-r--r-- | test/Analysis/ctor-inlining.mm | 102 |
1 files changed, 101 insertions, 1 deletions
diff --git a/test/Analysis/ctor-inlining.mm b/test/Analysis/ctor-inlining.mm index be5d81a58e..1603ff3893 100644 --- a/test/Analysis/ctor-inlining.mm +++ b/test/Analysis/ctor-inlining.mm @@ -1,8 +1,15 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s void clang_analyzer_eval(bool); void clang_analyzer_checkInlined(bool); +// A simplified version of std::move. +template <typename T> +T &&move(T &obj) { + return static_cast<T &&>(obj); +} + + struct Wrapper { __strong id obj; }; @@ -117,3 +124,96 @@ namespace ConstructorUsedAsRValue { clang_analyzer_eval(result); // expected-warning{{TRUE}} } } + +namespace PODUninitialized { + class POD { + public: + int x, y; + }; + + class PODWrapper { + public: + POD p; + }; + + class NonPOD { + public: + int x, y; + + NonPOD() {} + NonPOD(const NonPOD &Other) + : x(Other.x), y(Other.y) // expected-warning {{undefined}} + { + } + NonPOD(NonPOD &&Other) + : x(Other.x), y(Other.y) // expected-warning {{undefined}} + { + } + }; + + class NonPODWrapper { + public: + class Inner { + public: + int x, y; + + Inner() {} + Inner(const Inner &Other) + : x(Other.x), y(Other.y) // expected-warning {{undefined}} + { + } + Inner(Inner &&Other) + : x(Other.x), y(Other.y) // expected-warning {{undefined}} + { + } + }; + + Inner p; + }; + + void testPOD() { + POD p; + p.x = 1; + POD p2 = p; // no-warning + clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} + POD p3 = move(p); // no-warning + clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} + + // Use rvalues as well. + clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}} + + PODWrapper w; + w.p.y = 1; + PODWrapper w2 = w; // no-warning + clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} + PODWrapper w3 = move(w); // no-warning + clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} + + // Use rvalues as well. + clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}} + } + + void testNonPOD() { + NonPOD p; + p.x = 1; + NonPOD p2 = p; + } + + void testNonPODMove() { + NonPOD p; + p.x = 1; + NonPOD p2 = move(p); + } + + void testNonPODWrapper() { + NonPODWrapper w; + w.p.y = 1; + NonPODWrapper w2 = w; + } + + void testNonPODWrapperMove() { + NonPODWrapper w; + w.p.y = 1; + NonPODWrapper w2 = move(w); + } +} |