diff options
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 80 | ||||
-rw-r--r-- | test/SemaCXX/uninitialized.cpp | 9 |
2 files changed, 57 insertions, 32 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 500de928bf..fc37a25d8b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6083,55 +6083,73 @@ namespace { } } - void VisitExpr(Expr *E) { - if (isa<ObjCMessageExpr>(*E)) return; - if (isRecordType) { - Expr *expr = E; - if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - ValueDecl *VD = ME->getMemberDecl(); - if (isa<EnumConstantDecl>(VD) || isa<VarDecl>(VD)) return; - expr = ME->getBase(); - } - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(expr)) { + // Sometimes, the expression passed in lacks the casts that are used + // to determine which DeclRefExpr's to check. Assume that the casts + // are present and continue visiting the expression. + void HandleExpr(Expr *E) { + // Skip checking T a = a where T is not a record type. Doing so is a + // way to silence uninitialized warnings. + if (isRecordType) + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) HandleDeclRefExpr(DRE); - return; - } + + if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + HandleValue(CO->getTrueExpr()); + HandleValue(CO->getFalseExpr()); } - Inherited::VisitExpr(E); + + Visit(E); + } + + // For most expressions, the cast is directly above the DeclRefExpr. + // For conditional operators, the cast can be outside the conditional + // operator if both expressions are DeclRefExpr's. + void HandleValue(Expr *E) { + E = E->IgnoreParenImpCasts(); + if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) { + HandleDeclRefExpr(DRE); + return; + } + + if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + HandleValue(CO->getTrueExpr()); + HandleValue(CO->getFalseExpr()); + } + } + + void VisitImplicitCastExpr(ImplicitCastExpr *E) { + if ((!isRecordType && E->getCastKind() == CK_LValueToRValue) || + (isRecordType && E->getCastKind() == CK_NoOp)) + HandleValue(E->getSubExpr()); + + Inherited::VisitImplicitCastExpr(E); } void VisitMemberExpr(MemberExpr *E) { + // Don't warn on arrays since they can be treated as pointers. if (E->getType()->canDecayToPointerType()) return; + ValueDecl *VD = E->getMemberDecl(); - if (isa<FieldDecl>(VD) || isa<CXXMethodDecl>(VD)) + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(VD); + if (isa<FieldDecl>(VD) || (MD && !MD->isStatic())) if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) { HandleDeclRefExpr(DRE); return; } - Inherited::VisitMemberExpr(E); - } - void VisitImplicitCastExpr(ImplicitCastExpr *E) { - if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) || - (isRecordType && E->getCastKind() == CK_NoOp)) { - Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts(); - if (MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr)) - SubExpr = ME->getBase()->IgnoreParenImpCasts(); - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) { - HandleDeclRefExpr(DRE); - return; - } - } - Inherited::VisitImplicitCastExpr(E); + Inherited::VisitMemberExpr(E); } void VisitUnaryOperator(UnaryOperator *E) { // For POD record types, addresses of its own members are well-defined. - if (isRecordType && isPODType) return; + if (E->getOpcode() == UO_AddrOf && isRecordType && isPODType && + isa<MemberExpr>(E->getSubExpr())) return; Inherited::VisitUnaryOperator(E); } - + + void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; } + void HandleDeclRefExpr(DeclRefExpr *DRE) { Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; @@ -6148,7 +6166,7 @@ namespace { /// CheckSelfReference - Warns if OrigDecl is used in expression E. void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) { - SelfReferenceChecker(*this, OrigDecl).VisitExpr(E); + SelfReferenceChecker(*this, OrigDecl).HandleExpr(E); } /// AddInitializerToDecl - Adds the initializer Init to the diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp index 7879e7c753..b3283c221d 100644 --- a/test/SemaCXX/uninitialized.cpp +++ b/test/SemaCXX/uninitialized.cpp @@ -24,6 +24,9 @@ int i = boo(i); int j = far(j); int k = __alignof__(k); +int l = k ? l : l; // expected-warning 2{{variable 'l' is uninitialized when used within its own initialization}} +int m = 1 + (k ? m : m); // expected-warning 2{{variable 'm' is uninitialized when used within its own initialization}} +int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}} // Test self-references with record types. class A { @@ -48,8 +51,9 @@ class A { A getA() { return A(); } A getA(int x) { return A(); } A getA(A* a) { return A(); } +A getA(A a) { return A(); } -void setupA() { +void setupA(bool x) { A a1; a1.set(a1.get()); A a2(a1.get()); @@ -69,6 +73,8 @@ void setupA() { A a15 = getA(a15.num); // expected-warning {{variable 'a15' is uninitialized when used within its own initialization}} A a16(&a16.num); // expected-warning {{variable 'a16' is uninitialized when used within its own initialization}} A a17(a17.get2()); // expected-warning {{variable 'a17' is uninitialized when used within its own initialization}} + A a18 = x ? a18 : a17; // expected-warning {{variable 'a18' is uninitialized when used within its own initialization}} + A a19 = getA(x ? a19 : a17); // expected-warning {{variable 'a19' is uninitialized when used within its own initialization}} } struct B { @@ -97,6 +103,7 @@ void setupB() { B b7(b7); // expected-warning {{variable 'b7' is uninitialized when used within its own initialization}} B b8 = getB(b8.x); // expected-warning {{variable 'b8' is uninitialized when used within its own initialization}} B b9 = getB(b9.y); // expected-warning {{variable 'b9' is uninitialized when used within its own initialization}} + B b10 = getB(-b10.x); // expected-warning {{variable 'b10' is uninitialized when used within its own initialization}} } // Also test similar constructs in a field's initializer. |