diff options
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 20 | ||||
-rw-r--r-- | clang/test/Analysis/ctor-inlining.mm | 34 |
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}} + } +} |