diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -132,10 +132,20 @@ case ConstructionContext::SimpleConstructorInitializerKind: { const auto *ICC = cast(CC); const auto *Init = ICC->getCXXCtorInitializer(); - assert(Init->isAnyMemberInitializer()); const CXXMethodDecl *CurCtor = cast(LCtx->getDecl()); Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); + if (Init->isBaseInitializer()) { + const auto *ThisReg = cast(ThisVal.getAsRegion()); + const CXXRecordDecl *BaseClass = + Init->getBaseClass()->getAsCXXRecordDecl(); + const auto *BaseReg = + MRMgr.getCXXBaseObjectRegion(BaseClass, ThisReg, + Init->isBaseVirtual()); + return SVB.makeLoc(BaseReg); + } + if (Init->isDelegatingInitializer()) + return ThisVal; const ValueDecl *Field; SVal FieldVal; @@ -364,6 +374,11 @@ case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: case ConstructionContext::SimpleConstructorInitializerKind: { const auto *ICC = cast(CC); + const auto *Init = ICC->getCXXCtorInitializer(); + // Base and delegating initializers handled above + assert(Init->isAnyMemberInitializer() && + "Base and delegating initializers should have been handled by" + "computeObjectUnderConstruction()"); return addObjectUnderConstruction(State, ICC->getCXXCtorInitializer(), LCtx, V); } diff --git a/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp b/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp --- a/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp +++ b/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp @@ -23,8 +23,8 @@ : public Checker { public: void checkPostCall(const CallEvent &Call, CheckerContext &C) const { - // Only calls with origin expression are checked. These are `returnC()` - // and C::C(). + // Only calls with origin expression are checked. These are `returnC()`, + // `returnD()`, C::C() and D::D(). if (!Call.getOriginExpr()) return; @@ -35,6 +35,10 @@ Optional RetVal = Call.getReturnValueUnderConstruction(); ASSERT_TRUE(RetVal); ASSERT_TRUE(RetVal->getAsRegion()); + + const auto *RetReg = cast(RetVal->getAsRegion()); + const Expr *OrigExpr = Call.getOriginExpr(); + ASSERT_EQ(OrigExpr->getType(), RetReg->getValueType()); } }; @@ -51,22 +55,65 @@ TEST(TestReturnValueUnderConstructionChecker, ReturnValueUnderConstructionChecker) { EXPECT_TRUE(runCheckerOnCode( - R"(class C { - public: - C(int nn): n(nn) {} - virtual ~C() {} - private: - int n; - }; - - C returnC(int m) { - C c(m); - return c; - } - - void foo() { - C c = returnC(1); - })")); + R"(class C { + public: + C(int nn): n(nn) {} + virtual ~C() {} + private: + int n; + }; + + C returnC(int m) { + C c(m); + return c; + } + + void foo() { + C c = returnC(1); + })")); + + EXPECT_TRUE(runCheckerOnCode( + R"(class C { + public: + C(int nn): n(nn) {} + explicit C(): C(0) {} + virtual ~C() {} + private: + int n; + }; + + C returnC() { + C c; + return c; + } + + void foo() { + C c = returnC(); + })")); + + EXPECT_TRUE(runCheckerOnCode( + R"(class C { + public: + C(int nn): n(nn) {} + virtual ~C() {} + private: + int n; + }; + + class D: public C { + public: + D(int nn): C(nn) {} + virtual ~D() {} + }; + + D returnD(int m) { + D d(m); + return d; + } + + void foo() { + D d = returnD(1); + })")); } } // namespace