Index: lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -51,17 +51,20 @@ if (!N) return; - const char *str = "Assigned value is garbage or undefined"; - + static const char *const DefaultMsg = + "Assigned value is garbage or undefined"; if (!BT) - BT.reset(new BuiltinBug(this, str)); + BT.reset(new BuiltinBug(this, DefaultMsg)); // Generate a report for this bug. + std::string Str; + llvm::raw_string_ostream OS(Str); + const Expr *ex = nullptr; while (StoreE) { if (const UnaryOperator *U = dyn_cast(StoreE)) { - str = "The expression is an uninitialized value. " + OS << "The expression is an uninitialized value. " "The computed value will also be garbage"; ex = U->getSubExpr(); @@ -71,7 +74,7 @@ if (const BinaryOperator *B = dyn_cast(StoreE)) { if (B->isCompoundAssignmentOp()) { if (C.getSVal(B->getLHS()).isUndef()) { - str = "The left expression of the compound assignment is an " + OS << "The left expression of the compound assignment is an " "uninitialized value. The computed value will also be garbage"; ex = B->getLHS(); break; @@ -87,10 +90,26 @@ ex = VD->getInit(); } + if (const auto *CD = + dyn_cast(C.getStackFrame()->getDecl())) { + if (CD->isImplicit()) { + for (auto I : CD->inits()) { + if (I->getInit()->IgnoreImpCasts() == StoreE) { + OS << "Value assigned to field '" << I->getMember()->getName() + << "' is garbage or undefined"; + break; + } + } + } + } + break; } - auto R = llvm::make_unique(*BT, str, N); + if (OS.str().empty()) + OS << DefaultMsg; + + auto R = llvm::make_unique(*BT, OS.str(), N); if (ex) { R->addRange(ex->getSourceRange()); bugreporter::trackNullOrUndefValue(N, ex, *R); Index: test/Analysis/implicit-ctor-undef-value.cpp =================================================================== --- /dev/null +++ test/Analysis/implicit-ctor-undef-value.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s + +namespace implicit_constructor { +struct S { +public: + S() {} + S(const S &) {} +}; + +// Warning is in a weird position because the body of the constructor is +// missing. Specify which field is being assigned. +class C { // expected-warning{{Value assigned to field 'y' is garbage or undefined}} + // expected-note@-1{{Value assigned to field 'y' is garbage or undefined}} + int x, y; + S s; + +public: + C(): x(0) {} +}; + +void test() { + C c1; + C c2(c1); // expected-note{{Calling implicit copy constructor for 'C'}} +} +} // end namespace implicit_constructor + + +namespace explicit_constructor { +class C { + int x, y; + +public: + C(): x(0) {} + // It is not necessary to specify which field is being assigned to. + C(const C &c): + x(c.x), + y(c.y) // expected-warning{{Assigned value is garbage or undefined}} + // expected-note@-1{{Assigned value is garbage or undefined}} + {} +}; + +void test() { + C c1; + C c2(c1); // expected-note{{Calling copy constructor for 'C'}} +} +} // end namespace explicit_constructor