From 7e9f8af453598292cb57ba8e4dd63b9a5814b9ac Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Wed, 9 May 2012 00:21:34 +0000 Subject: [PATCH] Update the SelfReferenceChecker. Refactored some of the visitor methods. Added support for conditional operators and tightened the exclusion of the unary operator from all operators to only the address of operator. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156450 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDecl.cpp | 80 +++++++++++++++++++++------------- 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(*E)) return; - if (isRecordType) { - Expr *expr = E; - if (MemberExpr *ME = dyn_cast(E)) { - ValueDecl *VD = ME->getMemberDecl(); - if (isa(VD) || isa(VD)) return; - expr = ME->getBase(); - } - if (DeclRefExpr *DRE = dyn_cast(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(E)) HandleDeclRefExpr(DRE); - return; - } + + if (ConditionalOperator *CO = dyn_cast(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(E)) { + HandleDeclRefExpr(DRE); + return; + } + + if (ConditionalOperator *CO = dyn_cast(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(VD) || isa(VD)) + CXXMethodDecl *MD = dyn_cast(VD); + if (isa(VD) || (MD && !MD->isStatic())) if (DeclRefExpr *DRE = dyn_cast(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(SubExpr)) - SubExpr = ME->getBase()->IgnoreParenImpCasts(); - if (DeclRefExpr *DRE = dyn_cast(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(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. -- 2.40.0