diff options
author | Pavel Labath <labath@google.com> | 2013-08-30 08:52:28 +0000 |
---|---|---|
committer | Pavel Labath <labath@google.com> | 2013-08-30 08:52:28 +0000 |
commit | 58934986f220dec8b75a76c2de03db029b65f336 (patch) | |
tree | 06f1d9b9f31d9df0ed3252de7f56cad54c187c62 /clang/test/Analysis/operator-calls.cpp | |
parent | f79b0b15623a9138d629dac7f7928fa9630d83bc (diff) | |
download | bcm5719-llvm-58934986f220dec8b75a76c2de03db029b65f336.tar.gz bcm5719-llvm-58934986f220dec8b75a76c2de03db029b65f336.zip |
Sema: avoid reuse of Exprs when synthesizing operator=
Summary:
Previously, Sema was reusing parts of the AST when synthesizing an assignment
operator, turning it into a AS-dag. This caused problems for the static
analyzer, which assumed an expression appears in the tree only once.
Here I make sure to always create a fresh Expr, when inserting something into
the AST, fixing PR16745 in the process.
Reviewers: doug.gregor
CC: cfe-commits, jordan_rose
Differential Revision: http://llvm-reviews.chandlerc.com/D1425
llvm-svn: 189659
Diffstat (limited to 'clang/test/Analysis/operator-calls.cpp')
-rw-r--r-- | clang/test/Analysis/operator-calls.cpp | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/clang/test/Analysis/operator-calls.cpp b/clang/test/Analysis/operator-calls.cpp index 7461d75f673..4bd7c12fad3 100644 --- a/clang/test/Analysis/operator-calls.cpp +++ b/clang/test/Analysis/operator-calls.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s +// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s void clang_analyzer_eval(bool); struct X0 { }; @@ -85,3 +85,48 @@ namespace RValues { clang_analyzer_eval(+(coin ? getLargeOpaque() : getLargeOpaque())); // expected-warning{{UNKNOWN}} } } + +namespace SynthesizedAssignment { + struct A { + int a; + A& operator=(A& other) { a = -other.a; return *this; } + A& operator=(A&& other) { a = other.a+1; return *this; } + }; + + struct B { + int x; + A a[3]; + B& operator=(B&) = default; + B& operator=(B&&) = default; + }; + + // This used to produce a warning about the iteration variable in the + // synthesized assignment operator being undefined. + void testNoWarning() { + B v, u; + u = v; + } + + void testNoWarningMove() { + B v, u; + u = static_cast<B &&>(v); + } + + void testConsistency() { + B v, u; + v.a[1].a = 47; + v.a[2].a = 42; + u = v; + clang_analyzer_eval(u.a[1].a == -47); // expected-warning{{TRUE}} + clang_analyzer_eval(u.a[2].a == -42); // expected-warning{{TRUE}} + } + + void testConsistencyMove() { + B v, u; + v.a[1].a = 47; + v.a[2].a = 42; + u = static_cast<B &&>(v); + clang_analyzer_eval(u.a[1].a == 48); // expected-warning{{TRUE}} + clang_analyzer_eval(u.a[2].a == 43); // expected-warning{{TRUE}} + } +} |