[PATCH] Make -Wuninitialized warn on pointer-to-member and comma operators.
Enrico Pertoso
epertoso at google.com
Thu Dec 12 06:05:49 PST 2013
Yes, it does.
`DeclRefExpr`s are visited only by `TransferFunctions`, while `ClassifyRefs` relies mostly on binary operators, casts and unary operators to determine whether a variable is used or initialized.
For statements like `c = (a, a)` we need to classify the `DeclRefExpr` on the LHS of the comma operator as `Ignore`, or `TransferFunctions` will treat is as an initialization.
In the case of `(foo(a), b)`, the LHS is a `CallExpr` and `ClassifyRefs::classify` has no effect on it, while `a` is the sub-expression of an lvalue-to-rvalue cast, and will be correctly classified as `Use`.
I added two lines to the test.
Hi rsmith,
http://llvm-reviews.chandlerc.com/D2387
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D2387?vs=6033&id=6057#toc
Files:
lib/Analysis/UninitializedValues.cpp
test/SemaCXX/uninitialized.cpp
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<ConditionalOperator>(E)) {
- const Expr *TrueExpr = CO->getTrueExpr();
+ if (const AbstractConditionalOperator *ACO =
+ dyn_cast<AbstractConditionalOperator>(E)) {
+ if (isa<BinaryConditionalOperator>(ACO))
+ classify(cast<BinaryConditionalOperator>(ACO)->getCommon(), Use);
+ const Expr *TrueExpr = ACO->getTrueExpr();
if (!isa<OpaqueValueExpr>(TrueExpr))
classify(TrueExpr, C);
- classify(CO->getFalseExpr(), C);
+ classify(ACO->getFalseExpr(), C);
return;
}
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(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<UnaryOperator>(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,27 @@
}
}
+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}}
+}
+}
+
// Test self-references with record types.
class A {
// Non-POD class.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2387.2.patch
Type: text/x-patch
Size: 4416 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131212/dc5e82b9/attachment.bin>
More information about the cfe-commits
mailing list