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.
+ llvm::SmallString<128> Str;
+ llvm::raw_svector_ostream OS(Str);
+
const Expr *ex = nullptr;
while (StoreE) {
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(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();
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(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;
ex = VD->getInit();
}
+ if (const auto *CD =
+ dyn_cast<CXXConstructorDecl>(C.getStackFrame()->getDecl())) {
+ if (CD->isImplicit()) {
+ for (auto I : CD->inits()) {
+ if (I->getInit()->IgnoreImpCasts() == StoreE) {
+ OS << "Value assigned to field '" << I->getMember()->getName()
+ << "' in implicit constructor is garbage or undefined";
+ break;
+ }
+ }
+ }
+ }
+
break;
}
- auto R = llvm::make_unique<BugReport>(*BT, str, N);
+ if (OS.str().empty())
+ OS << DefaultMsg;
+
+ auto R = llvm::make_unique<BugReport>(*BT, OS.str(), N);
if (ex) {
R->addRange(ex->getSourceRange());
bugreporter::trackNullOrUndefValue(N, ex, *R);
--- /dev/null
+// 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' in implicit constructor is garbage or undefined}}
+ // expected-note@-1{{Value assigned to field 'y' in implicit constructor 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
+
+
+namespace base_class_constructor {
+struct S {
+public:
+ S() {}
+ S(const S &) {}
+};
+
+class C { // expected-warning{{Value assigned to field 'y' in implicit constructor is garbage or undefined}}
+ // expected-note@-1{{Value assigned to field 'y' in implicit constructor is garbage or undefined}}
+ int x, y;
+ S s;
+
+public:
+ C(): x(0) {}
+};
+
+class D: public C {
+public:
+ D(): C() {}
+};
+
+void test() {
+ D d1;
+ D d2(d1); // expected-note {{Calling implicit copy constructor for 'D'}}
+ // expected-note@-1{{Calling implicit copy constructor for 'C'}}
+}
+} // end namespace base_class_constructor