Index: lib/Analysis/UninitializedValues.cpp =================================================================== --- lib/Analysis/UninitializedValues.cpp +++ lib/Analysis/UninitializedValues.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/UninitializedValues.h" @@ -37,7 +38,7 @@ !vd->isExceptionVariable() && !vd->isInitCapture() && vd->getDeclContext() == dc) { QualType ty = vd->getType(); - return ty->isScalarType() || ty->isVectorType(); + return ty->isScalarType() || ty->isVectorType() || ty->isRecordType(); } return false; } @@ -347,6 +348,7 @@ } static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) { + if (VD->getType()->isRecordType()) return nullptr; if (Expr *Init = VD->getInit()) { const DeclRefExpr *DRE = dyn_cast(stripCasts(VD->getASTContext(), Init)); @@ -376,10 +378,26 @@ return; } + if (const MemberExpr *ME = dyn_cast(E)) { + if (VarDecl *VD = dyn_cast(ME->getMemberDecl())) { + if (!VD->isStaticDataMember()) + classify(ME->getBase(), C); + } + return; + } + if (const BinaryOperator *BO = dyn_cast(E)) { - if (BO->getOpcode() == BO_Comma) + switch (BO->getOpcode()) { + case BO_PtrMemD: + case BO_PtrMemI: + classify(BO->getLHS(), C); + return; + case BO_Comma: classify(BO->getRHS(), C); - return; + return; + default: + return; + } } FindVarResult Var = findVar(E, DC); @@ -404,7 +422,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); } @@ -415,25 +433,40 @@ classify(UO->getSubExpr(), Use); } +static bool isPointerToConst(const QualType &QT) { + return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified(); +} + void ClassifyRefs::VisitCallExpr(CallExpr *CE) { // Classify arguments to std::move as used. if (CE->getNumArgs() == 1) { if (FunctionDecl *FD = CE->getDirectCallee()) { if (FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move")) { - classify(CE->getArg(0), Use); + // RecordTypes are handled in SemaDeclCXX.cpp. + if (!CE->getArg(0)->getType()->isRecordType()) + classify(CE->getArg(0), Use); return; } } } - // 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. + // 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)->getType().isConstQualified() && (*I)->isGLValue()) - classify(*I, Ignore); + I != E; ++I) { + if ((*I)->isGLValue()) { + if ((*I)->getType().isConstQualified()) + classify((*I), Ignore); + } 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: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8602,8 +8602,13 @@ diag = diag::warn_uninit_self_reference_in_reference_init; } else if (cast(OrigDecl)->isStaticLocal()) { diag = diag::warn_static_self_reference_in_init; - } else { + } else if (isa(OrigDecl->getDeclContext()) || + isa(OrigDecl->getDeclContext()) || + DRE->getDecl()->getType()->isRecordType()) { diag = diag::warn_uninit_self_reference_in_init; + } else { + // Local variables will be handled by the CFG analysis. + return; } S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, Index: test/SemaCXX/uninitialized.cpp =================================================================== --- test/SemaCXX/uninitialized.cpp +++ test/SemaCXX/uninitialized.cpp @@ -86,7 +86,6 @@ int aa = (ref(aa) += 10); // expected-warning {{variable 'aa' is uninitialized when used within its own initialization}} int bb = bb ? x : y; // expected-warning {{variable 'bb' is uninitialized when used within its own initialization}} - for (;;) { int a = a; // no-warning: used to signal intended lack of initialization. int b = b + 1; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}} @@ -124,6 +123,50 @@ } } +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}} + int f; // expected-note {{initialize the variable 'f' to silence this warning}} + f = f + 1, 2; // expected-warning {{variable 'f' is uninitialized when used here}} + int h; + int g = (h, g, 2); // no-warning: h, g are evaluated but not used. +} + +namespace member_ptr { +struct A { + int x; + int y; + A(int x) : x{x} {} +}; + +void test_member_ptr() { + int A::* px = &A::x; + A a{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); +} +} + // Also test similar constructs in a field's initializer. struct S { int x;