summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorManuel Klimek <klimek@google.com>2015-03-03 14:54:25 +0000
committerManuel Klimek <klimek@google.com>2015-03-03 14:54:25 +0000
commit27ee25f73856ffa904d87f0fe1b49ae934e6b4bb (patch)
tree2b4016b96e7e0d46945cb0adeb271c1d65adfaf8 /clang
parent2d293400950ac0c72c18d31e54f70716830b6e67 (diff)
downloadbcm5719-llvm-27ee25f73856ffa904d87f0fe1b49ae934e6b4bb.tar.gz
bcm5719-llvm-27ee25f73856ffa904d87f0fe1b49ae934e6b4bb.zip
Make -Wuninitialized warn on pointer-to-member and comma operators.
`isTrackedVar` has been updated to also track records. `DeclRefExpr`s appearing on the left side of a comma operator are ignored, while those appearing on the right side are classified as `Use`. Patch by Enrico Pertoso. llvm-svn: 231068
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/Analysis/UninitializedValues.cpp55
-rw-r--r--clang/lib/Sema/SemaDecl.cpp7
-rw-r--r--clang/test/SemaCXX/uninitialized.cpp45
3 files changed, 94 insertions, 13 deletions
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 61a259217d7..8a6870ffa4d 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/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 @@ static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
!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 @@ public:
}
static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
+ if (VD->getType()->isRecordType()) return nullptr;
if (Expr *Init = VD->getInit()) {
const DeclRefExpr *DRE
= dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init));
@@ -376,10 +378,26 @@ void ClassifyRefs::classify(const Expr *E, Class C) {
return;
}
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
+ if (!VD->isStaticDataMember())
+ classify(ME->getBase(), C);
+ }
+ return;
+ }
+
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(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 @@ void ClassifyRefs::VisitBinaryOperator(BinaryOperator *BO) {
// 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 @@ void ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) {
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<UnaryOperator>(Ex);
+ if (UO && UO->getOpcode() == UO_AddrOf)
+ Ex = UO->getSubExpr();
+ classify(Ex, Ignore);
+ }
+ }
}
void ClassifyRefs::VisitCastExpr(CastExpr *CE) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index eb5b7154936..b1268cc2336 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8582,8 +8582,13 @@ namespace {
diag = diag::warn_uninit_self_reference_in_reference_init;
} else if (cast<VarDecl>(OrigDecl)->isStaticLocal()) {
diag = diag::warn_static_self_reference_in_init;
- } else {
+ } else if (isa<TranslationUnitDecl>(OrigDecl->getDeclContext()) ||
+ isa<NamespaceDecl>(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,
diff --git a/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp
index 018b1feba96..f02357419f5 100644
--- a/clang/test/SemaCXX/uninitialized.cpp
+++ b/clang/test/SemaCXX/uninitialized.cpp
@@ -86,7 +86,6 @@ void test_stuff () {
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_stuff () {
}
}
+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;
OpenPOWER on IntegriCloud