Index: lib/Analysis/UninitializedValues.cpp =================================================================== --- lib/Analysis/UninitializedValues.cpp +++ lib/Analysis/UninitializedValues.cpp @@ -37,7 +37,7 @@ !vd->isExceptionVariable() && vd->getDeclContext() == dc) { QualType ty = vd->getType(); - return ty->isScalarType() || ty->isVectorType(); + return ty->isScalarType() || ty->isVectorType() || ty->isRecordType(); } return false; } @@ -359,14 +359,31 @@ void ClassifyRefs::classify(const Expr *E, Class C) { // The result of a ?: could also be an lvalue. E = E->IgnoreParens(); - if (const ConditionalOperator *CO = dyn_cast(E)) { - const Expr *TrueExpr = CO->getTrueExpr(); + if (const AbstractConditionalOperator *ACO = + dyn_cast(E)) { + if (isa(ACO)) + classify(cast(ACO)->getCommon(), Use); + const Expr *TrueExpr = ACO->getTrueExpr(); if (!isa(TrueExpr)) classify(TrueExpr, C); - classify(CO->getFalseExpr(), C); + classify(ACO->getFalseExpr(), C); return; } + if (const BinaryOperator *BO = dyn_cast(E)) { + switch (BO->getOpcode()) { + case BO_PtrMemD: + case BO_PtrMemI: + classify(BO->getLHS(), C); + return; + case BO_Comma: + classify(BO->getRHS(), C); + return; + default: + return; + } + } + FindVarResult Var = findVar(E, DC); if (const DeclRefExpr *DRE = Var.getDeclRefExpr()) Classification[DRE] = std::max(Classification[DRE], C); @@ -390,7 +407,7 @@ // use. if (BO->isCompoundAssignmentOp()) classify(BO->getLHS(), Use); - else if (BO->getOpcode() == BO_Assign) + else if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma) classify(BO->getLHS(), Ignore); } @@ -401,14 +418,28 @@ classify(UO->getSubExpr(), Use); } +static bool IsPointerToConst(const QualType &QT) { + return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified(); +} + void ClassifyRefs::VisitCallExpr(CallExpr *CE) { - // If a value is passed by const reference to a function, we should not assume - // that it is initialized by the call, and we conservatively do not assume - // that it is used. - for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) - if ((*I)->getType().isConstQualified() && (*I)->isGLValue()) - classify(*I, Ignore); + // If a value is passed by const pointer or by const reference to a function, + // we should not assume that it is initialized by the call, and we + // conservatively do not assume that it is used. + for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + if ((*I)->isGLValue()) { + if ((*I)->getType().isConstQualified()) + classify((*I), Ignore); + continue; + } else if (IsPointerToConst((*I)->getType())) { + const Expr *Ex = stripCasts(DC->getParentASTContext(), *I); + const UnaryOperator *UO = dyn_cast(Ex); + if (UO && UO->getOpcode() == UO_AddrOf) + Ex = UO->getSubExpr(); + classify(Ex, Ignore); + } + } } void ClassifyRefs::VisitCastExpr(CastExpr *CE) { Index: test/SemaCXX/uninitialized.cpp =================================================================== --- test/SemaCXX/uninitialized.cpp +++ test/SemaCXX/uninitialized.cpp @@ -67,6 +67,45 @@ } } +void test_comma () { + int a; // expected-note {{initialize the variable 'a' to silence this warning}} + int b = (a, a ?: 2); // expected-warning {{variable 'a' is uninitialized when used here}} + int c = (a, a, b, c); // expected-warning {{variable 'c' is uninitialized when used within its own initialization}} + int d; // expected-note {{initialize the variable 'd' to silence this warning}} + int e = (foo(d), e, b); // expected-warning {{variable 'd' is uninitialized when used here}} +} + +namespace mem_ptr { +struct A { + int x; + int y; +}; + +void foo() { + int A::* px = &A::x; + A a{ 1, a.*px }; // expected-warning {{variable 'a' is uninitialized when used within its own initialization}} + A b = b; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}} +} +} + +namespace const_ptr { +void foo(int *a); +void bar(const int *a); +void foobar(const int **a); + +void test_const_ptr() { + int a; + int b; // expected-note {{initialize the variable 'b' to silence this warning}} + foo(&a); + bar(&b); + b = a + b; // expected-warning {{variable 'b' is uninitialized when used here}} + int *ptr; //expected-note {{initialize the variable 'ptr' to silence this warning}} + const int *ptr2; + foo(ptr); // expected-warning {{variable 'ptr' is uninitialized when used here}} + foobar(&ptr2); +} +} + // Test self-references with record types. class A { // Non-POD class.