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
diff --git a/clang/test/Analysis/operator-calls.cpp b/clang/test/Analysis/operator-calls.cpp
index 7461d75..4bd7c12 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 @@
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}}
+ }
+}