Szelethus updated this revision to Diff 152105.
Szelethus added a comment.
Fixes according to inline comments.
https://reviews.llvm.org/D48291
Files:
lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
test/Analysis/cxx-uninitialized-object.cpp
Index: test/Analysis/cxx-uninitialized-object.cpp
===================================================================
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -737,6 +737,22 @@
//===----------------------------------------------------------------------===//
template <class Callable>
+struct LambdaThisTest {
+ Callable functor;
+
+ LambdaThisTest(const Callable &functor, int) : functor(functor) {
+ // All good!
+ }
+};
+
+struct HasCapturableThis {
+ void fLambdaThisTest() {
+ auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash
+ LambdaThisTest<decltype(isEven)>(isEven, int());
+ }
+};
+
+template <class Callable>
struct LambdaTest1 {
Callable functor;
@@ -760,7 +776,7 @@
void fLambdaTest2() {
int b;
- auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
+ auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}}
LambdaTest2<decltype(equals)>(equals, int());
}
#else
@@ -782,8 +798,8 @@
namespace LT3Detail {
struct RecordType {
- int x; // expected-note{{uninitialized field 'this->functor..x'}}
- int y; // expected-note{{uninitialized field 'this->functor..y'}}
+ int x; // expected-note{{uninitialized field 'this->functor.rec1.x'}}
+ int y; // expected-note{{uninitialized field 'this->functor.rec1.y'}}
};
} // namespace LT3Detail
@@ -826,6 +842,35 @@
}
#endif //PEDANTIC
+template <class Callable>
+struct MultipleLambdaCapturesTest1 {
+ Callable functor;
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ MultipleLambdaCapturesTest1(const Callable &functor, int) : functor(functor) {} // expected-warning{{2 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest1() {
+ int b1, b2 = 3, b3;
+ auto equals = [&b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b1'}}
+ // expected-note@-1{{uninitialized field 'this->functor.b3'}}
+ MultipleLambdaCapturesTest1<decltype(equals)>(equals, int());
+}
+
+template <class Callable>
+struct MultipleLambdaCapturesTest2 {
+ Callable functor;
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ MultipleLambdaCapturesTest2(const Callable &functor, int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fMultipleLambdaCapturesTest2() {
+ int b1, b2 = 3, b3;
+ auto equals = [b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b3'}}
+ MultipleLambdaCapturesTest2<decltype(equals)>(equals, int());
+}
+
//===----------------------------------------------------------------------===//
// System header tests.
//===----------------------------------------------------------------------===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -230,6 +230,10 @@
/// Constructs a note message for a given FieldChainInfo object.
void printNoteMessage(llvm::raw_ostream &Out, const FieldChainInfo &Chain);
+/// Returns with Field's name. This is a helper function to get the correct name
+/// even if Field is a captured lambda variable.
+StringRef getVariableName(const FieldDecl *Field);
+
} // end of anonymous namespace
//===----------------------------------------------------------------------===//
@@ -604,30 +608,14 @@
// "uninitialized field 'this->x'", but we can't refer to 'x' directly,
// we need an explicit namespace resolution whether the uninit field was
// 'D1::x' or 'D2::x'.
-//
-// TODO: If a field in the fieldchain is a captured lambda parameter, this
-// function constructs an empty string for it:
-//
-// template <class Callable> struct A {
-// Callable c;
-// A(const Callable &c, int) : c(c) {}
-// };
-//
-// int b; // say that this isn't zero initialized
-// auto alwaysTrue = [&b](int a) { return true; };
-//
-// A call with these parameters: A<decltype(alwaysTrue)>::A(alwaysTrue, int())
-// will emit a note with the message "uninitialized field: 'this->c.'". If
-// possible, the lambda parameter name should be retrieved or be replaced with a
-// "<lambda parameter>" or something similar.
void FieldChainInfo::print(llvm::raw_ostream &Out) const {
if (Chain.isEmpty())
return;
const llvm::ImmutableListImpl<const FieldRegion *> *L =
Chain.getInternalPointer();
printTail(Out, L->getTail());
- Out << L->getHead()->getDecl()->getNameAsString();
+ Out << getVariableName(L->getHead()->getDecl());
}
void FieldChainInfo::printTail(
@@ -638,7 +626,7 @@
printTail(Out, L->getTail());
const FieldDecl *Field = L->getHead()->getDecl();
- Out << Field->getNameAsString();
+ Out << getVariableName(Field);
Out << (Field->getType()->isPointerType() ? "->" : ".");
}
@@ -700,6 +688,23 @@
Out << "'";
}
+StringRef getVariableName(const FieldDecl *Field) {
+ // If \p Field is a captured lambda variable, Field->getName() will return
+ // with an empty string. We can however acquire it's name by iterating over
+ // the lambda object's captures to find the corresponding variable.
+ const auto *CXXParent = dyn_cast<CXXRecordDecl>(Field->getParent());
+
+ if (CXXParent && CXXParent->isLambda()) {
+ for (const LambdaCapture &L : CXXParent->captures()) {
+ if (L.getLocation() == Field->getLocation())
+ return L.getCapturedVar()->getName();
+ }
+ llvm_unreachable("Failed to find the captured lambda variable!");
+ }
+
+ return Field->getName();
+}
+
} // end of anonymous namespace
void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits