summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-06-25 01:55:59 +0000
committerJordan Rose <jordan_rose@apple.com>2013-06-25 01:55:59 +0000
commitb3b976f0615db228547bb4e538b876722e090552 (patch)
tree870dc5c21c2c978ab54bf2074e366fa2ae00b5b1 /clang
parent5a8738ffe0170e2ffd9f08fa3c9fb93288070c2f (diff)
downloadbcm5719-llvm-b3b976f0615db228547bb4e538b876722e090552.tar.gz
bcm5719-llvm-b3b976f0615db228547bb4e538b876722e090552.zip
[analyzer] Don't initialize virtual base classes more than once.
In order to make sure virtual base classes are always initialized once, the AST contains initializers for the base class in /all/ of its descendents, not just the immediate descendents. However, at runtime, the most-derived object is responsible for initializing all the virtual base classes; all the other initializers will be ignored. The analyzer now checks to see if it's being called from another base constructor, and if so does not perform virtual base initialization. <rdar://problem/14236851> llvm-svn: 184814
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp20
-rw-r--r--clang/test/Analysis/ctor-inlining.mm34
2 files changed, 53 insertions, 1 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index ed90dc58918..84f96349f74 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -187,8 +187,26 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
break;
}
- case CXXConstructExpr::CK_NonVirtualBase:
case CXXConstructExpr::CK_VirtualBase:
+ // Make sure we are not calling virtual base class initializers twice.
+ // Only the most-derived object should initialize virtual base classes.
+ if (const Stmt *Outer = LCtx->getCurrentStackFrame()->getCallSite()) {
+ const CXXConstructExpr *OuterCtor = dyn_cast<CXXConstructExpr>(Outer);
+ if (OuterCtor) {
+ switch (OuterCtor->getConstructionKind()) {
+ case CXXConstructExpr::CK_NonVirtualBase:
+ case CXXConstructExpr::CK_VirtualBase:
+ // Bail out!
+ destNodes.Add(Pred);
+ return;
+ case CXXConstructExpr::CK_Complete:
+ case CXXConstructExpr::CK_Delegating:
+ break;
+ }
+ }
+ }
+ // FALLTHROUGH
+ case CXXConstructExpr::CK_NonVirtualBase:
case CXXConstructExpr::CK_Delegating: {
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
diff --git a/clang/test/Analysis/ctor-inlining.mm b/clang/test/Analysis/ctor-inlining.mm
index 8cdb005968c..9eb9888e935 100644
--- a/clang/test/Analysis/ctor-inlining.mm
+++ b/clang/test/Analysis/ctor-inlining.mm
@@ -500,3 +500,37 @@ namespace ArrayMembers {
clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}}
}
};
+
+namespace VirtualInheritance {
+ int counter;
+
+ struct base {
+ base() {
+ ++counter;
+ }
+ };
+
+ struct virtual_subclass : public virtual base {
+ virtual_subclass() {}
+ };
+
+ struct double_subclass : public virtual_subclass {
+ double_subclass() {}
+ };
+
+ void test() {
+ counter = 0;
+ double_subclass obj;
+ clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}}
+ }
+
+ struct double_virtual_subclass : public virtual virtual_subclass {
+ double_virtual_subclass() {}
+ };
+
+ void testVirtual() {
+ counter = 0;
+ double_virtual_subclass obj;
+ clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}}
+ }
+}
OpenPOWER on IntegriCloud