summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Umann <dkszelethus@gmail.com>2018-06-18 11:50:17 +0000
committerKristof Umann <dkszelethus@gmail.com>2018-06-18 11:50:17 +0000
commit6402a97d5b74108b300f5833af0b85b3d4c5d6b6 (patch)
treed8cbd3c62fb05b37fada65472a1f9b6d48507eb4
parent07caa7f2a1dae8d2569ec59a2f6785ad5d4ea3d9 (diff)
downloadclang-6402a97d5b74108b300f5833af0b85b3d4c5d6b6.tar.gz
[analyzer] Checker for uninitialized C++ objects
This checker analyzes C++ constructor calls, and reports uninitialized fields. Due to the nature of this problem (uninitialized fields after an object construction), this checker doesn't search for bugs, but rather is a tool to enforce a specific programming model where every field needs to be initialized. This checker lands in alpha for now, and a number of followup patches will be made to reduce false negatives and to make it easier for the user to understand what rules the checker relies on, eg. whether a derived class' constructor is responsible for initializing inherited data members or whether it should be handled in the base class' constructor. Differential Revision: https://reviews.llvm.org/D45532 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@334935 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/StaticAnalyzer/Checkers/Checkers.td4
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp669
-rw-r--r--test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h18
-rw-r--r--test/Analysis/cxx-uninitialized-object-inheritance.cpp775
-rw-r--r--test/Analysis/cxx-uninitialized-object-ptr-ref.cpp699
-rw-r--r--test/Analysis/cxx-uninitialized-object.cpp1058
7 files changed, 3224 insertions, 0 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 7887780945..5e450bdb4a 100644
--- a/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -319,6 +319,10 @@ def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
"object will be reported">,
DescFile<"MisusedMovedObjectChecker.cpp">;
+def UninitializedObjectChecker: Checker<"UninitializedObject">,
+ HelpText<"Reports uninitialized fields after object construction">,
+ DescFile<"UninitializedObjectChecker.cpp">;
+
} // end: "alpha.cplusplus"
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index c615ad8a4c..af88c0bfd3 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -92,6 +92,7 @@ add_clang_library(clangStaticAnalyzerCheckers
UndefResultChecker.cpp
UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
+ UninitializedObjectChecker.cpp
UnixAPIChecker.cpp
UnreachableCodeChecker.cpp
VforkChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp b/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
new file mode 100644
index 0000000000..63e4b817da
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -0,0 +1,669 @@
+//===----- UninitializedObjectChecker.cpp ------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a checker that reports uninitialized fields in objects
+// created after a constructor call.
+//
+// This checker has an option "Pedantic" (boolean). If its not set or is set to
+// false, the checker won't emit warnings for objects that don't have at least
+// one initialized field. This may be set with
+// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <algorithm>
+
+using namespace clang;
+using namespace clang::ento;
+
+namespace {
+
+class UninitializedObjectChecker : public Checker<check::EndFunction> {
+ std::unique_ptr<BuiltinBug> BT_uninitField;
+
+public:
+ bool IsPedantic; // Will be initialized when registering the checker.
+
+ UninitializedObjectChecker()
+ : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
+ void checkEndFunction(CheckerContext &C) const;
+};
+
+llvm::ImmutableListFactory<const FieldRegion *> Factory;
+
+/// Represents a field chain. A field chain is a vector of fields where the
+/// first element of the chain is the object under checking (not stored), and
+/// every other element is a field, and the element that precedes it is the
+/// object that contains it.
+///
+/// Note that this class is immutable, and new fields may only be added through
+/// constructor calls.
+class FieldChainInfo {
+ using FieldChain = llvm::ImmutableList<const FieldRegion *>;
+
+ FieldChain Chain;
+
+ const bool IsDereferenced = false;
+
+public:
+ FieldChainInfo() = default;
+
+ FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
+ : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
+
+ FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
+ const bool IsDereferenced = false);
+
+ bool contains(const FieldRegion *FR) const { return Chain.contains(FR); }
+ bool isPointer() const;
+
+ /// If this is a fieldchain whose last element is an uninitialized region of a
+ /// pointer type, `IsDereferenced` will store whether the pointer itself or
+ /// the pointee is uninitialized.
+ bool isDereferenced() const;
+ const FieldDecl *getEndOfChain() const;
+ void print(llvm::raw_ostream &Out) const;
+
+private:
+ /// Prints every element except the last to `Out`. Since ImmutableLists store
+ /// elements in reverse order, and have no reverse iterators, we use a
+ /// recursive function to print the fieldchain correctly. The last element in
+ /// the chain is to be printed by `print`.
+ static void printTail(llvm::raw_ostream &Out,
+ const llvm::ImmutableListImpl<const FieldRegion *> *L);
+ friend struct FieldChainInfoComparator;
+};
+
+struct FieldChainInfoComparator {
+ bool operator()(const FieldChainInfo &lhs, const FieldChainInfo &rhs) {
+ assert(!lhs.Chain.isEmpty() && !rhs.Chain.isEmpty() &&
+ "Attempted to store an empty fieldchain!");
+ return *lhs.Chain.begin() < *rhs.Chain.begin();
+ }
+};
+
+using UninitFieldSet = std::set<FieldChainInfo, FieldChainInfoComparator>;
+
+/// Searches for and stores uninitialized fields in a non-union object.
+class FindUninitializedFields {
+ ProgramStateRef State;
+ const TypedValueRegion *const ObjectR;
+
+ const bool IsPedantic;
+ bool IsAnyFieldInitialized = false;
+
+ UninitFieldSet UninitFields;
+
+public:
+ FindUninitializedFields(ProgramStateRef State,
+ const TypedValueRegion *const R, bool IsPedantic);
+ const UninitFieldSet &getUninitFields();
+
+private:
+ /// Adds a FieldChainInfo object to UninitFields. Return true if an insertion
+ /// took place.
+ bool addFieldToUninits(FieldChainInfo LocalChain);
+
+ // For the purposes of this checker, we'll regard the object under checking as
+ // a directed tree, where
+ // * the root is the object under checking
+ // * every node is an object that is
+ // - a union
+ // - a non-union record
+ // - a pointer/reference
+ // - an array
+ // - of a member pointer type
+ // - of a primitive type, which we'll define as either a BuiltinType or
+ // EnumeralType.
+ // * the parent of each node is the object that contains it
+ // * every leaf is an array, a primitive object, a member pointer, a nullptr
+ // or an undefined pointer.
+ //
+ // Example:
+ //
+ // struct A {
+ // struct B {
+ // int x, y = 0;
+ // };
+ // B b;
+ // int *iptr = new int;
+ // B* bptr;
+ //
+ // A() {}
+ // };
+ //
+ // The directed tree:
+ //
+ // ->x
+ // /
+ // ->b--->y
+ // /
+ // A-->iptr->(int value)
+ // \
+ // ->bptr
+ //
+ // From this we'll construct a vector of fieldchains, where each fieldchain
+ // represents an uninitialized field. An uninitialized field may be a
+ // primitive object, a member pointer, a pointer, a pointee or a union without
+ // a single initialized field.
+ // In the above example, for the default constructor call we'll end up with
+ // these fieldchains:
+ //
+ // this->b.x
+ // this->iptr (pointee uninit)
+ // this->bptr (pointer uninit)
+ //
+ // We'll traverse each node of the above graph with the appropiate one of
+ // these methods:
+
+ /// This method checks a region of a union object, and returns true if no
+ /// field is initialized within the region.
+ bool isUnionUninit(const TypedValueRegion *R);
+
+ /// This method checks a region of a non-union object, and returns true if
+ /// an uninitialized field is found within the region.
+ bool isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain);
+
+ /// This method checks a region of a pointer or reference object, and returns
+ /// true if the ptr/ref object itself or any field within the pointee's region
+ /// is uninitialized.
+ bool isPointerOrReferenceUninit(const FieldRegion *FR,
+ FieldChainInfo LocalChain);
+
+ /// This method checks a region of MemberPointerType, and returns true if the
+ /// the pointer is uninitialized.
+ bool isMemberPointerUninit(const FieldRegion *FR, FieldChainInfo LocalChain);
+
+ /// This method returns true if the value of a primitive object is
+ /// uninitialized.
+ bool isPrimitiveUninit(const SVal &V);
+
+ // Note that we don't have a method for arrays -- the elements of an array are
+ // often left uninitialized intentionally even when it is of a C++ record
+ // type, so we'll assume that an array is always initialized.
+ // TODO: Add a support for nonloc::LocAsInteger.
+};
+
+// Utility function declarations.
+
+/// Returns the object that was constructed by CtorDecl, or None if that isn't
+/// possible.
+Optional<nonloc::LazyCompoundVal>
+getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
+
+/// Checks whether the constructor under checking is called by another
+/// constructor.
+bool isCalledByConstructor(const CheckerContext &Context);
+
+/// Returns whether FD can be (transitively) dereferenced to a void pointer type
+/// (void*, void**, ...). The type of the region behind a void pointer isn't
+/// known, and thus FD can not be analyzed.
+bool isVoidPointer(const FieldDecl *FD);
+
+/// Returns true if T is a primitive type. We'll call a type primitive if it's
+/// either a BuiltinType or an EnumeralType.
+bool isPrimitiveType(const QualType &T) {
+ return T->isBuiltinType() || T->isEnumeralType();
+}
+
+} // end of anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Methods for UninitializedObjectChecker.
+//===----------------------------------------------------------------------===//
+
+void UninitializedObjectChecker::checkEndFunction(
+ CheckerContext &Context) const {
+
+ const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
+ Context.getLocationContext()->getDecl());
+ if (!CtorDecl)
+ return;
+
+ if (!CtorDecl->isUserProvided())
+ return;
+
+ if (CtorDecl->getParent()->isUnion())
+ return;
+
+ // This avoids essentially the same error being reported multiple times.
+ if (isCalledByConstructor(Context))
+ return;
+
+ Optional<nonloc::LazyCompoundVal> Object = getObjectVal(CtorDecl, Context);
+ if (!Object)
+ return;
+
+ FindUninitializedFields F(Context.getState(), Object->getRegion(),
+ IsPedantic);
+
+ const UninitFieldSet &UninitFields = F.getUninitFields();
+
+ if (UninitFields.empty())
+ return;
+
+ // There are uninitialized fields in the record.
+
+ ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
+ if (!Node)
+ return;
+
+ PathDiagnosticLocation LocUsedForUniqueing;
+ const Stmt *CallSite = Context.getStackFrame()->getCallSite();
+ if (CallSite)
+ LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
+ CallSite, Context.getSourceManager(), Node->getLocationContext());
+
+ SmallString<100> WarningBuf;
+ llvm::raw_svector_ostream WarningOS(WarningBuf);
+ WarningOS << UninitFields.size() << " uninitialized field"
+ << (UninitFields.size() == 1 ? "" : "s")
+ << " at the end of the constructor call";
+
+ auto Report = llvm::make_unique<BugReport>(
+ *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
+ Node->getLocationContext()->getDecl());
+
+ // TODO: As of now, one warning is emitted per constructor call, and the
+ // uninitialized fields are listed in notes. Until there's a better support
+ // for notes avaible, a note-less version of this checker should be
+ // implemented.
+ for (const auto &FieldChain : UninitFields) {
+ SmallString<200> NoteBuf;
+ llvm::raw_svector_ostream NoteOS(NoteBuf);
+
+ if (FieldChain.isPointer()) {
+ if (FieldChain.isDereferenced())
+ NoteOS << "uninitialized pointee 'this->";
+ else
+ NoteOS << "uninitialized pointer 'this->";
+ } else
+ NoteOS << "uninitialized field 'this->";
+ FieldChain.print(NoteOS);
+ NoteOS << "'";
+
+ Report->addNote(NoteOS.str(),
+ PathDiagnosticLocation::create(FieldChain.getEndOfChain(),
+ Context.getSourceManager()));
+ }
+
+ Context.emitReport(std::move(Report));
+}
+
+//===----------------------------------------------------------------------===//
+// Methods for FindUninitializedFields.
+//===----------------------------------------------------------------------===//
+
+FindUninitializedFields::FindUninitializedFields(
+ ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic)
+ : State(State), ObjectR(R), IsPedantic(IsPedantic) {}
+
+const UninitFieldSet &FindUninitializedFields::getUninitFields() {
+ isNonUnionUninit(ObjectR, FieldChainInfo());
+
+ if (!IsPedantic && !IsAnyFieldInitialized)
+ UninitFields.clear();
+
+ return UninitFields;
+}
+
+bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
+ if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
+ Chain.getEndOfChain()->getLocation()))
+ return false;
+
+ return UninitFields.insert(Chain).second;
+}
+
+bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
+ FieldChainInfo LocalChain) {
+ assert(R->getValueType()->isRecordType() &&
+ !R->getValueType()->isUnionType() &&
+ "This method only checks non-union record objects!");
+
+ const RecordDecl *RD =
+ R->getValueType()->getAs<RecordType>()->getDecl()->getDefinition();
+ assert(RD && "Referred record has no definition");
+
+ bool ContainsUninitField = false;
+
+ // Are all of this non-union's fields initialized?
+ for (const FieldDecl *I : RD->fields()) {
+
+ const auto FieldVal =
+ State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
+ const auto *FR = FieldVal.getRegionAs<FieldRegion>();
+ QualType T = I->getType();
+
+ // If LocalChain already contains FR, then we encountered a cyclic
+ // reference. In this case, region FR is already under checking at an
+ // earlier node in the directed tree.
+ if (LocalChain.contains(FR))
+ return false;
+
+ if (T->isStructureOrClassType()) {
+ if (isNonUnionUninit(FR, {LocalChain, FR}))
+ ContainsUninitField = true;
+ continue;
+ }
+
+ if (T->isUnionType()) {
+ if (isUnionUninit(FR)) {
+ if (addFieldToUninits({LocalChain, FR}))
+ ContainsUninitField = true;
+ } else
+ IsAnyFieldInitialized = true;
+ continue;
+ }
+
+ if (T->isArrayType()) {
+ IsAnyFieldInitialized = true;
+ continue;
+ }
+
+ if (T->isMemberPointerType()) {
+ if (isMemberPointerUninit(FR, LocalChain))
+ ContainsUninitField = true;
+ continue;
+ }
+
+ // If this is a pointer or reference type.
+ if (T->isPointerType() || T->isReferenceType()) {
+ if (isPointerOrReferenceUninit(FR, LocalChain))
+ ContainsUninitField = true;
+ continue;
+ }
+
+ assert(isPrimitiveType(T) && "Non-primitive type! "
+ "At this point FR must be primitive!");
+
+ SVal V = State->getSVal(FieldVal);
+
+ if (isPrimitiveUninit(V)) {
+ if (addFieldToUninits({LocalChain, FR}))
+ ContainsUninitField = true;
+ }
+ }
+
+ // Checking bases.
+ // FIXME: As of now, because of `isCalledByConstructor`, objects whose type
+ // is a descendant of another type will emit warnings for uninitalized
+ // inherited members.
+ // This is not the only way to analyze bases of an object -- if we didn't
+ // filter them out, and didn't analyze the bases, this checker would run for
+ // each base of the object in order of base initailization and in theory would
+ // find every uninitalized field. This approach could also make handling
+ // diamond inheritances more easily.
+ //
+ // This rule (that a descendant type's cunstructor is responsible for
+ // initializing inherited data members) is not obvious, and should it should
+ // be.
+ const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+ if (!CXXRD)
+ return ContainsUninitField;
+
+ for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
+ const auto *BaseRegion = State->getLValue(BaseSpec, R)
+ .castAs<loc::MemRegionVal>()
+ .getRegionAs<TypedValueRegion>();
+
+ if (isNonUnionUninit(BaseRegion, LocalChain))
+ ContainsUninitField = true;
+ }
+
+ return ContainsUninitField;
+}
+
+bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
+ assert(R->getValueType()->isUnionType() &&
+ "This method only checks union objects!");
+ // TODO: Implement support for union fields.
+ return false;
+}
+
+// Note that pointers/references don't contain fields themselves, so in this
+// function we won't add anything to LocalChain.
+bool FindUninitializedFields::isPointerOrReferenceUninit(
+ const FieldRegion *FR, FieldChainInfo LocalChain) {
+
+ assert((FR->getDecl()->getType()->isPointerType() ||
+ FR->getDecl()->getType()->isReferenceType()) &&
+ "This method only checks pointer/reference objects!");
+
+ SVal V = State->getSVal(FR);
+
+ if (V.isUnknown() || V.isZeroConstant()) {
+ IsAnyFieldInitialized = true;
+ return false;
+ }
+
+ if (V.isUndef()) {
+ return addFieldToUninits({LocalChain, FR});
+ }
+
+ const FieldDecl *FD = FR->getDecl();
+
+ // TODO: The dynamic type of a void pointer may be retrieved with
+ // `getDynamicTypeInfo`.
+ if (isVoidPointer(FD)) {
+ IsAnyFieldInitialized = true;
+ return false;
+ }
+
+ assert(V.getAs<Loc>() && "V should be Loc at this point!");
+
+ // At this point the pointer itself is initialized and points to a valid
+ // location, we'll now check the pointee.
+ SVal DerefdV = State->getSVal(V.castAs<Loc>());
+
+ // TODO: Dereferencing should be done according to the dynamic type.
+ while (Optional<Loc> L = DerefdV.getAs<Loc>()) {
+ DerefdV = State->getSVal(*L);
+ }
+
+ // If V is a pointer pointing to a record type.
+ if (Optional<nonloc::LazyCompoundVal> RecordV =
+ DerefdV.getAs<nonloc::LazyCompoundVal>()) {
+
+ const TypedValueRegion *R = RecordV->getRegion();
+
+ // We can't reason about symbolic regions, assume its initialized.
+ // Note that this also avoids a potential infinite recursion, because
+ // constructors for list-like classes are checked without being called, and
+ // the Static Analyzer will construct a symbolic region for Node *next; or
+ // similar code snippets.
+ if (R->getSymbolicBase()) {
+ IsAnyFieldInitialized = true;
+ return false;
+ }
+
+ const QualType T = R->getValueType();
+
+ if (T->isStructureOrClassType())
+ return isNonUnionUninit(R, {LocalChain, FR});
+
+ if (T->isUnionType()) {
+ if (isUnionUninit(R)) {
+ return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
+ } else {
+ IsAnyFieldInitialized = true;
+ return false;
+ }
+ }
+
+ if (T->isArrayType()) {
+ IsAnyFieldInitialized = true;
+ return false;
+ }
+
+ llvm_unreachable("All cases are handled!");
+ }
+
+ // TODO: If possible, it should be asserted that the DerefdV at this point is
+ // primitive.
+
+ if (isPrimitiveUninit(DerefdV))
+ return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
+
+ IsAnyFieldInitialized = true;
+ return false;
+}
+
+bool FindUninitializedFields::isMemberPointerUninit(const FieldRegion *FR,
+ FieldChainInfo LocalChain) {
+ assert(FR->getDecl()->getType()->isMemberPointerType() &&
+ "This function only checks regions that hold MemberPointerTypes!");
+ // TODO: Implement support for MemberPointerTypes.
+ return false;
+}
+
+bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
+ if (V.isUndef())
+ return true;
+
+ IsAnyFieldInitialized = true;
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods for FieldChainInfo.
+//===----------------------------------------------------------------------===//
+
+FieldChainInfo::FieldChainInfo(const FieldChainInfo &Other,
+ const FieldRegion *FR, const bool IsDereferenced)
+ : FieldChainInfo(Other, IsDereferenced) {
+ assert(!contains(FR) && "Can't add a field that is already a part of the "
+ "fieldchain! Is this a cyclic reference?");
+ Chain = Factory.add(FR, Other.Chain);
+}
+
+bool FieldChainInfo::isPointer() const {
+ assert(!Chain.isEmpty() && "Empty fieldchain!");
+ return (*Chain.begin())->getDecl()->getType()->isPointerType();
+}
+
+bool FieldChainInfo::isDereferenced() const {
+ assert(isPointer() && "Only pointers may or may not be dereferenced!");
+ return IsDereferenced;
+}
+
+const FieldDecl *FieldChainInfo::getEndOfChain() const {
+ assert(!Chain.isEmpty() && "Empty fieldchain!");
+ return (*Chain.begin())->getDecl();
+}
+
+// TODO: This function constructs an incorrect fieldchain string in the
+// following case:
+//
+// struct Base { int x; };
+// struct D1 : Base {}; struct D2 : Base {};
+//
+// struct MostDerived : D1, D2 {
+// MostDerived() {}
+// }
+//
+// A call to MostDerived::MostDerived() will cause two notes that say
+// "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();
+}
+
+void FieldChainInfo::printTail(
+ llvm::raw_ostream &Out,
+ const llvm::ImmutableListImpl<const FieldRegion *> *L) {
+ if (!L)
+ return;
+
+ printTail(Out, L->getTail());
+ const FieldDecl *Field = L->getHead()->getDecl();
+ Out << Field->getNameAsString();
+ Out << (Field->getType()->isPointerType() ? "->" : ".");
+}
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+bool isVoidPointer(const FieldDecl *FD) {
+ QualType T = FD->getType();
+
+ while (!T.isNull()) {
+ if (T->isVoidPointerType())
+ return true;
+ T = T->getPointeeType();
+ }
+ return false;
+}
+
+Optional<nonloc::LazyCompoundVal>
+getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) {
+
+ Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
+ Context.getStackFrame());
+ // Getting the value for 'this'.
+ SVal This = Context.getState()->getSVal(ThisLoc);
+
+ // Getting the value for '*this'.
+ SVal Object = Context.getState()->getSVal(This.castAs<Loc>());
+
+ return Object.getAs<nonloc::LazyCompoundVal>();
+}
+
+// TODO: We should also check that if the constructor was called by another
+// constructor, whether those two are in any relation to one another. In it's
+// current state, this introduces some false negatives.
+bool isCalledByConstructor(const CheckerContext &Context) {
+ const LocationContext *LC = Context.getLocationContext()->getParent();
+
+ while (LC) {
+ if (isa<CXXConstructorDecl>(LC->getDecl()))
+ return true;
+
+ LC = LC->getParent();
+ }
+ return false;
+}
+
+} // end of anonymous namespace
+
+void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
+ auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
+ Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption(
+ "Pedantic", /*DefaultVal*/ false, Chk);
+}
diff --git a/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h b/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h
new file mode 100644
index 0000000000..2397824fc9
--- /dev/null
+++ b/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h
@@ -0,0 +1,18 @@
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, it is assumed that system
+// functions do not arbitrarily free() their parameters, and that some bugs
+// found in system headers cannot be fixed by the user and should be
+// suppressed.
+
+#pragma clang system_header
+
+struct RecordInSystemHeader {
+ int a;
+ int b;
+};
+
+template <class T>
+struct ContainerInSystemHeader {
+ T &t;
+ ContainerInSystemHeader(T& t) : t(t) {}
+};
diff --git a/test/Analysis/cxx-uninitialized-object-inheritance.cpp b/test/Analysis/cxx-uninitialized-object-inheritance.cpp
new file mode 100644
index 0000000000..3b048b759e
--- /dev/null
+++ b/test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -0,0 +1,775 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -verify %s
+
+//===----------------------------------------------------------------------===//
+// Non-polymorphic inheritance tests
+//===----------------------------------------------------------------------===//
+
+class NonPolymorphicLeft1 {
+ int x;
+
+protected:
+ int y;
+
+public:
+ NonPolymorphicLeft1() = default;
+ NonPolymorphicLeft1(int) : x(1) {}
+};
+
+class NonPolymorphicInheritanceTest1 : public NonPolymorphicLeft1 {
+ int z;
+
+public:
+ NonPolymorphicInheritanceTest1()
+ : NonPolymorphicLeft1(int{}) {
+ y = 2;
+ z = 3;
+ // All good!
+ }
+};
+
+void fNonPolymorphicInheritanceTest1() {
+ NonPolymorphicInheritanceTest1();
+}
+
+class NonPolymorphicBaseClass2 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+protected:
+ int y;
+
+public:
+ NonPolymorphicBaseClass2() = default;
+ NonPolymorphicBaseClass2(int) : x(4) {}
+};
+
+class NonPolymorphicInheritanceTest2 : public NonPolymorphicBaseClass2 {
+ int z;
+
+public:
+ NonPolymorphicInheritanceTest2() {
+ y = 5;
+ z = 6; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fNonPolymorphicInheritanceTest2() {
+ NonPolymorphicInheritanceTest2();
+}
+
+class NonPolymorphicBaseClass3 {
+ int x;
+
+protected:
+ int y; // expected-note{{uninitialized field 'this->y'}}
+public:
+ NonPolymorphicBaseClass3() = default;
+ NonPolymorphicBaseClass3(int) : x(7) {}
+};
+
+class NonPolymorphicInheritanceTest3 : public NonPolymorphicBaseClass3 {
+ int z;
+
+public:
+ NonPolymorphicInheritanceTest3()
+ : NonPolymorphicBaseClass3(int{}) {
+ z = 8; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fNonPolymorphicInheritanceTest3() {
+ NonPolymorphicInheritanceTest3();
+}
+
+class NonPolymorphicBaseClass4 {
+ int x;
+
+protected:
+ int y;
+
+public:
+ NonPolymorphicBaseClass4() = default;
+ NonPolymorphicBaseClass4(int) : x(9) {}
+};
+
+class NonPolymorphicInheritanceTest4 : public NonPolymorphicBaseClass4 {
+ int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+ NonPolymorphicInheritanceTest4()
+ : NonPolymorphicBaseClass4(int{}) {
+ y = 10; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fNonPolymorphicInheritanceTest4() {
+ NonPolymorphicInheritanceTest4();
+}
+
+//===----------------------------------------------------------------------===//
+// Polymorphic inheritance tests
+//===----------------------------------------------------------------------===//
+
+class PolymorphicLeft1 {
+ int x;
+
+protected:
+ int y;
+
+public:
+ virtual ~PolymorphicLeft1() = default;
+ PolymorphicLeft1() = default;
+ PolymorphicLeft1(int) : x(11) {}
+};
+
+class PolymorphicInheritanceTest1 : public PolymorphicLeft1 {
+ int z;
+
+public:
+ PolymorphicInheritanceTest1()
+ : PolymorphicLeft1(int{}) {
+ y = 12;
+ z = 13;
+ // All good!
+ }
+};
+
+void fPolymorphicInheritanceTest1() {
+ PolymorphicInheritanceTest1();
+}
+
+class PolymorphicRight1 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+protected:
+ int y;
+
+public:
+ virtual ~PolymorphicRight1() = default;
+ PolymorphicRight1() = default;
+ PolymorphicRight1(int) : x(14) {}
+};
+
+class PolymorphicInheritanceTest2 : public PolymorphicRight1 {
+ int z;
+
+public:
+ PolymorphicInheritanceTest2() {
+ y = 15;
+ z = 16; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fPolymorphicInheritanceTest2() {
+ PolymorphicInheritanceTest2();
+}
+
+class PolymorphicBaseClass3 {
+ int x;
+
+protected:
+ int y; // expected-note{{uninitialized field 'this->y'}}
+public:
+ virtual ~PolymorphicBaseClass3() = default;
+ PolymorphicBaseClass3() = default;
+ PolymorphicBaseClass3(int) : x(17) {}
+};
+
+class PolymorphicInheritanceTest3 : public PolymorphicBaseClass3 {
+ int z;
+
+public:
+ PolymorphicInheritanceTest3()
+ : PolymorphicBaseClass3(int{}) {
+ z = 18; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fPolymorphicInheritanceTest3() {
+ PolymorphicInheritanceTest3();
+}
+
+class PolymorphicBaseClass4 {
+ int x;
+
+protected:
+ int y;
+
+public:
+ virtual ~PolymorphicBaseClass4() = default;
+ PolymorphicBaseClass4() = default;
+ PolymorphicBaseClass4(int) : x(19) {}
+};
+
+class PolymorphicInheritanceTest4 : public PolymorphicBaseClass4 {
+ int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+ PolymorphicInheritanceTest4()
+ : PolymorphicBaseClass4(int{}) {
+ y = 20; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fPolymorphicInheritanceTest4() {
+ PolymorphicInheritanceTest4();
+}
+
+//===----------------------------------------------------------------------===//
+// Virtual inheritance tests
+//===----------------------------------------------------------------------===//
+
+class VirtualPolymorphicLeft1 {
+ int x;
+
+protected:
+ int y;
+
+public:
+ virtual ~VirtualPolymorphicLeft1() = default;
+ VirtualPolymorphicLeft1() = default;
+ VirtualPolymorphicLeft1(int) : x(21) {}
+};
+
+class VirtualInheritanceTest1 : virtual public VirtualPolymorphicLeft1 {
+ int z;
+
+public:
+ VirtualInheritanceTest1()
+ : VirtualPolymorphicLeft1(int()) {
+ y = 22;
+ z = 23;
+ // All good!
+ }
+};
+
+void fVirtualInheritanceTest1() {
+ VirtualInheritanceTest1();
+}
+
+class VirtualPolymorphicRight1 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+protected:
+ int y;
+
+public:
+ virtual ~VirtualPolymorphicRight1() = default;
+ VirtualPolymorphicRight1() = default;
+ VirtualPolymorphicRight1(int) : x(24) {}
+};
+
+class VirtualInheritanceTest2 : virtual public VirtualPolymorphicRight1 {
+ int z;
+
+public:
+ VirtualInheritanceTest2() {
+ y = 25;
+ z = 26; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fVirtualInheritanceTest2() {
+ VirtualInheritanceTest2();
+}
+
+class VirtualPolymorphicBaseClass3 {
+ int x;
+
+protected:
+ int y; // expected-note{{uninitialized field 'this->y'}}
+public:
+ virtual ~VirtualPolymorphicBaseClass3() = default;
+ VirtualPolymorphicBaseClass3() = default;
+ VirtualPolymorphicBaseClass3(int) : x(27) {}
+};
+
+class VirtualInheritanceTest3 : virtual public VirtualPolymorphicBaseClass3 {
+ int z;
+
+public:
+ VirtualInheritanceTest3()
+ : VirtualPolymorphicBaseClass3(int{}) {
+ z = 28; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fVirtualInheritanceTest3() {
+ VirtualInheritanceTest3();
+}
+
+//===----------------------------------------------------------------------===//
+// Multiple inheritance tests
+//===----------------------------------------------------------------------===//
+
+/*
+ Left Right
+ \ /
+ \ /
+ \ /
+ MultipleInheritanceTest
+*/
+
+struct Left1 {
+ int x;
+ Left1() = default;
+ Left1(int) : x(29) {}
+};
+struct Right1 {
+ int y;
+ Right1() = default;
+ Right1(int) : y(30) {}
+};
+
+class MultipleInheritanceTest1 : public Left1, public Right1 {
+ int z;
+
+public:
+ MultipleInheritanceTest1()
+ : Left1(int{}),
+ Right1(char{}) {
+ z = 31;
+ // All good!
+ }
+
+ MultipleInheritanceTest1(int)
+ : Left1(int{}) {
+ y = 32;
+ z = 33;
+ // All good!
+ }
+
+ MultipleInheritanceTest1(int, int)
+ : Right1(char{}) {
+ x = 34;
+ z = 35;
+ // All good!
+ }
+};
+
+void fMultipleInheritanceTest1() {
+ MultipleInheritanceTest1();
+ MultipleInheritanceTest1(int());
+ MultipleInheritanceTest1(int(), int());
+}
+
+struct Left2 {
+ int x;
+ Left2() = default;
+ Left2(int) : x(36) {}
+};
+struct Right2 {
+ int y; // expected-note{{uninitialized field 'this->y'}}
+ Right2() = default;
+ Right2(int) : y(37) {}
+};
+
+class MultipleInheritanceTest2 : public Left2, public Right2 {
+ int z;
+
+public:
+ MultipleInheritanceTest2()
+ : Left2(int{}) {
+ z = 38; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fMultipleInheritanceTest2() {
+ MultipleInheritanceTest2();
+}
+
+struct Left3 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+ Left3() = default;
+ Left3(int) : x(39) {}
+};
+struct Right3 {
+ int y;
+ Right3() = default;
+ Right3(int) : y(40) {}
+};
+
+class MultipleInheritanceTest3 : public Left3, public Right3 {
+ int z;
+
+public:
+ MultipleInheritanceTest3()
+ : Right3(char{}) {
+ z = 41; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fMultipleInheritanceTest3() {
+ MultipleInheritanceTest3();
+}
+
+struct Left4 {
+ int x;
+ Left4() = default;
+ Left4(int) : x(42) {}
+};
+struct Right4 {
+ int y;
+ Right4() = default;
+ Right4(int) : y(43) {}
+};
+
+class MultipleInheritanceTest4 : public Left4, public Right4 {
+ int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+ MultipleInheritanceTest4()
+ : Left4(int{}),
+ Right4(char{}) { // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fMultipleInheritanceTest4() {
+ MultipleInheritanceTest4();
+}
+
+struct Left5 {
+ int x;
+ Left5() = default;
+ Left5(int) : x(44) {}
+};
+struct Right5 {
+ int y; // expected-note{{uninitialized field 'this->y'}}
+ Right5() = default;
+ Right5(int) : y(45) {}
+};
+
+class MultipleInheritanceTest5 : public Left5, public Right5 {
+ int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+ MultipleInheritanceTest5() // expected-warning{{2 uninitialized fields}}
+ : Left5(int{}) {
+ }
+};
+
+void fMultipleInheritanceTest5() {
+ MultipleInheritanceTest5();
+}
+
+//===----------------------------------------------------------------------===//
+// Non-virtual diamond inheritance tests
+//===----------------------------------------------------------------------===//
+
+/*
+ NonVirtualBase NonVirtualBase
+ | |
+ | |
+ | |
+ First Second
+ \ /
+ \ /
+ \ /
+ NonVirtualDiamondInheritanceTest
+*/
+
+struct NonVirtualBase1 {
+ int x;
+ NonVirtualBase1() = default;
+ NonVirtualBase1(int) : x(46) {}
+};
+struct First1 : public NonVirtualBase1 {
+ First1() = default;
+ First1(int) : NonVirtualBase1(int{}) {}
+};
+struct Second1 : public NonVirtualBase1 {
+ Second1() = default;
+ Second1(int) : NonVirtualBase1(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest1 : public First1, public Second1 {
+ int z;
+
+public:
+ NonVirtualDiamondInheritanceTest1()
+ : First1(int{}),
+ Second1(int{}) {
+ z = 47;
+ // All good!
+ }
+
+ NonVirtualDiamondInheritanceTest1(int)
+ : First1(int{}) {
+ Second1::x = 48;
+ z = 49;
+ // All good!
+ }
+
+ NonVirtualDiamondInheritanceTest1(int, int)
+ : Second1(int{}) {
+ First1::x = 50;
+ z = 51;
+ // All good!
+ }
+};
+
+void fNonVirtualDiamondInheritanceTest1() {
+ NonVirtualDiamondInheritanceTest1();
+ NonVirtualDiamondInheritanceTest1(int());
+ NonVirtualDiamondInheritanceTest1(int(), int());
+}
+
+struct NonVirtualBase2 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+ NonVirtualBase2() = default;
+ NonVirtualBase2(int) : x(52) {}
+};
+struct First2 : public NonVirtualBase2 {
+ First2() = default;
+ First2(int) : NonVirtualBase2(int{}) {}
+};
+struct Second2 : public NonVirtualBase2 {
+ Second2() = default;
+ Second2(int) : NonVirtualBase2(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest2 : public First2, public Second2 {
+ int z;
+
+public:
+ NonVirtualDiamondInheritanceTest2()
+ : First2(int{}) {
+ z = 53; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fNonVirtualDiamondInheritanceTest2() {
+ NonVirtualDiamondInheritanceTest2();
+}
+
+struct NonVirtualBase3 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+ NonVirtualBase3() = default;
+ NonVirtualBase3(int) : x(54) {}
+};
+struct First3 : public NonVirtualBase3 {
+ First3() = default;
+ First3(int) : NonVirtualBase3(int{}) {}
+};
+struct Second3 : public NonVirtualBase3 {
+ Second3() = default;
+ Second3(int) : NonVirtualBase3(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest3 : public First3, public Second3 {
+ int z;
+
+public:
+ NonVirtualDiamondInheritanceTest3()
+ : Second3(int{}) {
+ z = 55; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fNonVirtualDiamondInheritanceTest3() {
+ NonVirtualDiamondInheritanceTest3();
+}
+
+struct NonVirtualBase4 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+ // expected-note@-1{{uninitialized field 'this->x'}}
+ NonVirtualBase4() = default;
+ NonVirtualBase4(int) : x(56) {}
+};
+struct First4 : public NonVirtualBase4 {
+ First4() = default;
+ First4(int) : NonVirtualBase4(int{}) {}
+};
+struct Second4 : public NonVirtualBase4 {
+ Second4() = default;
+ Second4(int) : NonVirtualBase4(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest4 : public First4, public Second4 {
+ int z;
+
+public:
+ NonVirtualDiamondInheritanceTest4() {
+ z = 57; // expected-warning{{2 uninitialized fields}}
+ }
+};
+
+void fNonVirtualDiamondInheritanceTest4() {
+ NonVirtualDiamondInheritanceTest4();
+}
+
+struct NonVirtualBase5 {
+ int x;
+ NonVirtualBase5() = default;
+ NonVirtualBase5(int) : x(58) {}
+};
+struct First5 : public NonVirtualBase5 {
+ First5() = default;
+ First5(int) : NonVirtualBase5(int{}) {}
+};
+struct Second5 : public NonVirtualBase5 {
+ Second5() = default;
+ Second5(int) : NonVirtualBase5(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest5 : public First5, public Second5 {
+ int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+ NonVirtualDiamondInheritanceTest5()
+ : First5(int{}),
+ Second5(int{}) { // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fNonVirtualDiamondInheritanceTest5() {
+ NonVirtualDiamondInheritanceTest5();
+}
+
+struct NonVirtualBase6 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+ NonVirtualBase6() = default;
+ NonVirtualBase6(int) : x(59) {}
+};
+struct First6 : public NonVirtualBase6 {
+ First6() = default;
+ First6(int) : NonVirtualBase6(int{}) {}
+};
+struct Second6 : public NonVirtualBase6 {
+ Second6() = default;
+ Second6(int) : NonVirtualBase6(int{}) {}
+};
+
+class NonVirtualDiamondInheritanceTest6 : public First6, public Second6 {
+ int z; // expected-note{{uninitialized field 'this->z'}}
+
+public:
+ NonVirtualDiamondInheritanceTest6() // expected-warning{{2 uninitialized fields}}
+ : First6(int{}) {
+ // 'z' and 'Second::x' unintialized
+ }
+};
+
+void fNonVirtualDiamondInheritanceTest6() {
+ NonVirtualDiamondInheritanceTest6();
+}
+
+//===----------------------------------------------------------------------===//
+// Virtual diamond inheritance tests
+//===----------------------------------------------------------------------===//
+
+/*
+ VirtualBase
+ / \
+ / \
+ / \
+ VirtualFirst VirtualSecond
+ \ /
+ \ /
+ \ /
+ VirtualDiamondInheritanceTest
+*/
+
+struct VirtualBase1 {
+ int x;
+ VirtualBase1() = default;
+ VirtualBase1(int) : x(60) {}
+};
+struct VirtualFirst1 : virtual public VirtualBase1 {
+ VirtualFirst1() = default;
+ VirtualFirst1(int) : VirtualBase1(int{}) {}
+ VirtualFirst1(int, int) { x = 61; }
+};
+struct VirtualSecond1 : virtual public VirtualBase1 {
+ VirtualSecond1() = default;
+ VirtualSecond1(int) : VirtualBase1(int{}) {}
+ VirtualSecond1(int, int) { x = 62; }
+};
+
+class VirtualDiamondInheritanceTest1 : public VirtualFirst1, public VirtualSecond1 {
+
+public:
+ VirtualDiamondInheritanceTest1() {
+ x = 0;
+ // All good!
+ }
+
+ VirtualDiamondInheritanceTest1(int)
+ : VirtualFirst1(int{}, int{}),
+ VirtualSecond1(int{}, int{}) {
+ // All good!
+ }
+
+ VirtualDiamondInheritanceTest1(int, int)
+ : VirtualFirst1(int{}, int{}) {
+ // All good!
+ }
+};
+
+void fVirtualDiamondInheritanceTest1() {
+ VirtualDiamondInheritanceTest1();
+ VirtualDiamondInheritanceTest1(int());
+ VirtualDiamondInheritanceTest1(int(), int());
+}
+
+struct VirtualBase2 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+ VirtualBase2() = default;
+ VirtualBase2(int) : x(63) {}
+};
+struct VirtualFirst2 : virtual public VirtualBase2 {
+ VirtualFirst2() = default;
+ VirtualFirst2(int) : VirtualBase2(int{}) {}
+ VirtualFirst2(int, int) { x = 64; }
+};
+struct VirtualSecond2 : virtual public VirtualBase2 {
+ VirtualSecond2() = default;
+ VirtualSecond2(int) : VirtualBase2(int{}) {}
+ VirtualSecond2(int, int) { x = 65; }
+};
+
+class VirtualDiamondInheritanceTest2 : public VirtualFirst2, public VirtualSecond2 {
+
+public:
+ VirtualDiamondInheritanceTest2() // expected-warning{{1 uninitialized field}}
+ : VirtualFirst2(int{}) {
+ // From the N4659 C++ Standard Working Draft:
+ //
+ // (15.6.2.7)
+ // [...] A 'mem-initializer' where the 'mem-initializer-id' denotes a
+ // virtual base class is ignored during execution of a constructor of any
+ // class that is not the most derived class.
+ //
+ // This means that Left1::x will not be initialized, because in both
+ // VirtualFirst::VirtualFirst(int) and VirtualSecond::VirtualSecond(int)
+ // the constructor delegation to Left1::Left1(int) will be
+ // ignored.
+ }
+};
+
+void fVirtualDiamondInheritanceTest2() {
+ VirtualDiamondInheritanceTest2();
+}
+
+struct VirtualBase3 {
+ int x; // expected-note{{uninitialized field 'this->x'}}
+ VirtualBase3() = default;
+ VirtualBase3(int) : x(66) {}
+};
+struct VirtualFirst3 : virtual public VirtualBase3 {
+ VirtualFirst3() = default;
+ VirtualFirst3(int) : VirtualBase3(int{}) {}
+ VirtualFirst3(int, int) { x = 67; }
+};
+struct VirtualSecond3 : virtual public VirtualBase3 {
+ VirtualSecond3() = default;
+ VirtualSecond3(int) : VirtualBase3(int{}) {}
+ VirtualSecond3(int, int) { x = 68; }
+};
+
+class VirtualDiamondInheritanceTest3 : public VirtualFirst3, public VirtualSecond3 {
+
+public:
+ VirtualDiamondInheritanceTest3() // expected-warning{{1 uninitialized field}}
+ : VirtualFirst3(int{}) {}
+};
+
+void fVirtualDiamondInheritanceTest3() {
+ VirtualDiamondInheritanceTest3();
+}
diff --git a/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp b/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
new file mode 100644
index 0000000000..e6c0b91a62
--- /dev/null
+++ b/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -0,0 +1,699 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
+
+//===----------------------------------------------------------------------===//
+// Concrete location tests.
+//===----------------------------------------------------------------------===//
+
+struct ConcreteIntLocTest {
+ int *ptr;
+
+ ConcreteIntLocTest() : ptr(reinterpret_cast<int *>(0xDEADBEEF)) {}
+};
+
+void fConcreteIntLocTest() {
+ ConcreteIntLocTest();
+}
+
+//===----------------------------------------------------------------------===//
+// Null pointer tests.
+//===----------------------------------------------------------------------===//
+
+class NullPtrTest {
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+ float *fptr = nullptr;
+ int *ptr;
+ RecordType *recPtr;
+
+public:
+ NullPtrTest() : ptr(nullptr), recPtr(nullptr) {
+ // All good!
+ }
+};
+
+void fNullPtrTest() {
+ NullPtrTest();
+}
+
+//===----------------------------------------------------------------------===//
+// Heap pointer tests.
+//===----------------------------------------------------------------------===//
+
+class HeapPointerTest1 {
+ struct RecordType {
+ // TODO: we'd expect the note: {{uninitialized field 'this->recPtr->y'}}
+ int x; // no-note
+ // TODO: we'd expect the note: {{uninitialized field 'this->recPtr->y'}}
+ int y; // no-note
+ };
+ // TODO: we'd expect the note: {{uninitialized pointee 'this->fptr'}}
+ float *fptr = new float; // no-note
+ // TODO: we'd expect the note: {{uninitialized pointee 'this->ptr'}}
+ int *ptr; // no-note
+ RecordType *recPtr;
+
+public:
+ // TODO: we'd expect the warning: {{4 uninitialized fields}}
+ HeapPointerTest1() : ptr(new int), recPtr(new RecordType) { // no-note
+ }
+};
+
+void fHeapPointerTest1() {
+ HeapPointerTest1();
+}
+
+class HeapPointerTest2 {
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+ float *fptr = new float(); // initializes to 0
+ int *ptr;
+ RecordType *recPtr;
+
+public:
+ HeapPointerTest2() : ptr(new int{25}), recPtr(new RecordType{26, 27}) {
+ // All good!
+ }
+};
+
+void fHeapPointerTest2() {
+ HeapPointerTest2();
+}
+
+//===----------------------------------------------------------------------===//
+// Stack pointer tests.
+//===----------------------------------------------------------------------===//
+
+class StackPointerTest1 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ int *ptr;
+ RecordType *recPtr;
+
+public:
+ StackPointerTest1(int *_ptr, StackPointerTest1::RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) {
+ // All good!
+ }
+};
+
+void fStackPointerTest1() {
+ int ok_a = 28;
+ StackPointerTest1::RecordType ok_rec{29, 30};
+ StackPointerTest1(&ok_a, &ok_rec); // 'a', 'rec.x', 'rec.y' uninitialized
+}
+
+#ifdef PEDANTIC
+class StackPointerTest2 {
+public:
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->recPtr->x'}}
+ int y; // expected-note{{uninitialized field 'this->recPtr->y'}}
+ };
+
+private:
+ int *ptr; // expected-note{{uninitialized pointee 'this->ptr'}}
+ RecordType *recPtr;
+
+public:
+ StackPointerTest2(int *_ptr, RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) { // expected-warning{{3 uninitialized fields}}
+ }
+};
+
+void fStackPointerTest2() {
+ int a;
+ StackPointerTest2::RecordType rec;
+ StackPointerTest2(&a, &rec); // 'a', 'rec.x', 'rec.y' uninitialized
+}
+#else
+class StackPointerTest2 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ int *ptr;
+ RecordType *recPtr;
+
+public:
+ StackPointerTest2(int *_ptr, RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) {
+ }
+};
+
+void fStackPointerTest2() {
+ int a;
+ StackPointerTest2::RecordType rec;
+ StackPointerTest2(&a, &rec); // 'a', 'rec.x', 'rec.y' uninitialized
+}
+#endif // PEDANTIC
+
+class UninitPointerTest {
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+ int *ptr; // expected-note{{uninitialized pointer 'this->ptr'}}
+ RecordType *recPtr;
+
+public:
+ UninitPointerTest() : recPtr(new RecordType{13, 13}) { // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fUninitPointerTest() {
+ UninitPointerTest();
+}
+
+struct CharPointerTest {
+ const char *str;
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ CharPointerTest() : str("") {}
+};
+
+void fCharPointerTest() {
+ CharPointerTest();
+}
+
+struct CyclicPointerTest {
+ int *ptr;
+ CyclicPointerTest() : ptr(reinterpret_cast<int*>(&ptr)) {}
+};
+
+void fCyclicPointerTest() {
+ CyclicPointerTest();
+}
+
+//===----------------------------------------------------------------------===//
+// Void pointer tests.
+//===----------------------------------------------------------------------===//
+
+// Void pointer tests are mainly no-crash tests.
+
+void *malloc(int size);
+
+class VoidPointerTest1 {
+ void *vptr;
+
+public:
+ VoidPointerTest1(void *vptr, char) : vptr(vptr) {
+ // All good!
+ }
+};
+
+void fVoidPointerTest1() {
+ void *vptr = malloc(sizeof(int));
+ VoidPointerTest1(vptr, char());
+}
+
+class VoidPointerTest2 {
+ void **vpptr;
+
+public:
+ VoidPointerTest2(void **vpptr, char) : vpptr(vpptr) {
+ // All good!
+ }
+};
+
+void fVoidPointerTest2() {
+ void *vptr = malloc(sizeof(int));
+ VoidPointerTest2(&vptr, char());
+}
+
+class VoidPointerRRefTest1 {
+ void *&&vptrrref;
+
+public:
+ VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void *&&>(vptr)) {
+ // All good!
+ }
+};
+
+void fVoidPointerRRefTest1() {
+ void *vptr = malloc(sizeof(int));
+ VoidPointerRRefTest1(vptr, char());
+}
+
+class VoidPointerRRefTest2 {
+ void **&&vpptrrref;
+
+public:
+ VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void **&&>(vptr)) {
+ // All good!
+ }
+};
+
+void fVoidPointerRRefTest2() {
+ void *vptr = malloc(sizeof(int));
+ VoidPointerRRefTest2(&vptr, char());
+}
+
+class VoidPointerLRefTest {
+ void *&vptrrref;
+
+public:
+ VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void *&>(vptr)) {
+ // All good!
+ }
+};
+
+void fVoidPointerLRefTest() {
+ void *vptr = malloc(sizeof(int));
+ VoidPointerLRefTest(vptr, char());
+}
+
+struct CyclicVoidPointerTest {
+ void *vptr; // no-crash
+
+ CyclicVoidPointerTest() : vptr(&vptr) {}
+
+};
+
+void fCyclicVoidPointerTest() {
+ CyclicVoidPointerTest();
+}
+
+//===----------------------------------------------------------------------===//
+// Multipointer tests.
+//===----------------------------------------------------------------------===//
+
+#ifdef PEDANTIC
+class MultiPointerTest1 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ RecordType **mptr; // expected-note{{uninitialized pointee 'this->mptr'}}
+
+public:
+ MultiPointerTest1(RecordType **p, int) : mptr(p) { // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fMultiPointerTest1() {
+ MultiPointerTest1::RecordType *p1;
+ MultiPointerTest1::RecordType **mptr = &p1;
+ MultiPointerTest1(mptr, int()); // '*mptr' uninitialized
+}
+#else
+class MultiPointerTest1 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ RecordType **mptr;
+
+public:
+ MultiPointerTest1(RecordType **p, int) : mptr(p) {}
+};
+
+void fMultiPointerTest1() {
+ MultiPointerTest1::RecordType *p1;
+ MultiPointerTest1::RecordType **mptr = &p1;
+ MultiPointerTest1(mptr, int()); // '*mptr' uninitialized
+}
+#endif // PEDANTIC
+
+#ifdef PEDANTIC
+class MultiPointerTest2 {
+public:
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->mptr->x'}}
+ int y; // expected-note{{uninitialized field 'this->mptr->y'}}
+ };
+
+private:
+ RecordType **mptr;
+
+public:
+ MultiPointerTest2(RecordType **p, int) : mptr(p) { // expected-warning{{2 uninitialized fields}}
+ }
+};
+
+void fMultiPointerTest2() {
+ MultiPointerTest2::RecordType i;
+ MultiPointerTest2::RecordType *p1 = &i;
+ MultiPointerTest2::RecordType **mptr = &p1;
+ MultiPointerTest2(mptr, int()); // '**mptr' uninitialized
+}
+#else
+class MultiPointerTest2 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ RecordType **mptr;
+
+public:
+ MultiPointerTest2(RecordType **p, int) : mptr(p) {
+ }
+};
+
+void fMultiPointerTest2() {
+ MultiPointerTest2::RecordType i;
+ MultiPointerTest2::RecordType *p1 = &i;
+ MultiPointerTest2::RecordType **mptr = &p1;
+ MultiPointerTest2(mptr, int()); // '**mptr' uninitialized
+}
+#endif // PEDANTIC
+
+class MultiPointerTest3 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ RecordType **mptr;
+
+public:
+ MultiPointerTest3(RecordType **p, int) : mptr(p) {
+ // All good!
+ }
+};
+
+void fMultiPointerTest3() {
+ MultiPointerTest3::RecordType i{31, 32};
+ MultiPointerTest3::RecordType *p1 = &i;
+ MultiPointerTest3::RecordType **mptr = &p1;
+ MultiPointerTest3(mptr, int()); // '**mptr' uninitialized
+}
+
+//===----------------------------------------------------------------------===//
+// Member pointer tests.
+//===----------------------------------------------------------------------===//
+
+struct UsefulFunctions {
+ int a, b;
+
+ void print() {}
+ void dump() {}
+};
+
+#ifdef PEDANTIC
+struct PointerToMemberFunctionTest1 {
+ // TODO: we'd expect the note {{uninitialized field 'this->f'}}
+ void (UsefulFunctions::*f)(void); // no-note
+ PointerToMemberFunctionTest1() {}
+};
+
+void fPointerToMemberFunctionTest1() {
+ // TODO: we'd expect the warning {{1 uninitialized field}}
+ PointerToMemberFunctionTest1(); // no-warning
+}
+
+struct PointerToMemberFunctionTest2 {
+ void (UsefulFunctions::*f)(void);
+ PointerToMemberFunctionTest2(void (UsefulFunctions::*f)(void)) : f(f) {
+ // All good!
+ }
+};
+
+void fPointerToMemberFunctionTest2() {
+ void (UsefulFunctions::*f)(void) = &UsefulFunctions::print;
+ PointerToMemberFunctionTest2 a(f);
+}
+
+struct MultiPointerToMemberFunctionTest1 {
+ void (UsefulFunctions::**f)(void); // expected-note{{uninitialized pointer 'this->f'}}
+ MultiPointerToMemberFunctionTest1() {}
+};
+
+void fMultiPointerToMemberFunctionTest1() {
+ MultiPointerToMemberFunctionTest1(); // expected-warning{{1 uninitialized field}}
+}
+
+struct MultiPointerToMemberFunctionTest2 {
+ void (UsefulFunctions::**f)(void);
+ MultiPointerToMemberFunctionTest2(void (UsefulFunctions::**f)(void)) : f(f) {
+ // All good!
+ }
+};
+
+void fMultiPointerToMemberFunctionTest2() {
+ void (UsefulFunctions::*f)(void) = &UsefulFunctions::print;
+ MultiPointerToMemberFunctionTest2 a(&f);
+}
+
+struct PointerToMemberDataTest1 {
+ // TODO: we'd expect the note {{uninitialized field 'this->f'}}
+ int UsefulFunctions::*d; // no-note
+ PointerToMemberDataTest1() {}
+};
+
+void fPointerToMemberDataTest1() {
+ // TODO: we'd expect the warning {{1 uninitialized field}}
+ PointerToMemberDataTest1(); // no-warning
+}
+
+struct PointerToMemberDataTest2 {
+ int UsefulFunctions::*d;
+ PointerToMemberDataTest2(int UsefulFunctions::*d) : d(d) {
+ // All good!
+ }
+};
+
+void fPointerToMemberDataTest2() {
+ int UsefulFunctions::*d = &UsefulFunctions::a;
+ PointerToMemberDataTest2 a(d);
+}
+
+struct MultiPointerToMemberDataTest1 {
+ int UsefulFunctions::**d; // expected-note{{uninitialized pointer 'this->d'}}
+ MultiPointerToMemberDataTest1() {}
+};
+
+void fMultiPointerToMemberDataTest1() {
+ MultiPointerToMemberDataTest1(); // expected-warning{{1 uninitialized field}}
+}
+
+struct MultiPointerToMemberDataTest2 {
+ int UsefulFunctions::**d;
+ MultiPointerToMemberDataTest2(int UsefulFunctions::**d) : d(d) {
+ // All good!
+ }
+};
+
+void fMultiPointerToMemberDataTest2() {
+ int UsefulFunctions::*d = &UsefulFunctions::a;
+ MultiPointerToMemberDataTest2 a(&d);
+}
+#endif // PEDANTIC
+
+//===----------------------------------------------------------------------===//
+// Tests for list-like records.
+//===----------------------------------------------------------------------===//
+
+class ListTest1 {
+public:
+ struct Node {
+ Node *next = nullptr; // no crash
+ int i;
+ };
+
+private:
+ Node *head = nullptr;
+
+public:
+ ListTest1() {
+ // All good!
+ }
+};
+
+void fListTest1() {
+ ListTest1();
+}
+
+class ListTest2 {
+public:
+ struct Node {
+ Node *next = nullptr;
+ int i; // expected-note{{uninitialized field 'this->head->i'}}
+ };
+
+private:
+ Node *head = nullptr;
+
+public:
+ ListTest2(Node *node, int) : head(node) { // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fListTest2() {
+ ListTest2::Node n;
+ ListTest2(&n, int());
+}
+
+class CyclicList {
+public:
+ struct Node {
+ Node *next = nullptr;
+ int i; // expected-note{{uninitialized field 'this->head->i'}}
+ };
+
+private:
+ Node *head = nullptr;
+
+public:
+ CyclicList(Node *node, int) : head(node) { // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fCyclicList() {
+ /*
+ n3
+ / \
+ this -- n1 -- n2
+ */
+
+ CyclicList::Node n1;
+ CyclicList::Node n2;
+ n2.next = &n1;
+ n2.i = 50;
+ CyclicList::Node n3;
+ n3.next = &n2;
+ n3.i = 50;
+ n1.next = &n3;
+ // note that n1.i is uninitialized
+ CyclicList(&n1, int());
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for classes containing references.
+//===----------------------------------------------------------------------===//
+
+class ReferenceTest1 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ RecordType &lref;
+ RecordType &&rref;
+
+public:
+ ReferenceTest1(RecordType &lref, RecordType &rref) : lref(lref), rref(static_cast<RecordType &&>(rref)) {
+ // All good!
+ }
+};
+
+void fReferenceTest1() {
+ ReferenceTest1::RecordType d{33, 34};
+ ReferenceTest1(d, d);
+}
+
+#ifdef PEDANTIC
+class ReferenceTest2 {
+public:
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->lref.x'}}
+ int y; // expected-note{{uninitialized field 'this->lref.y'}}
+ };
+
+private:
+ RecordType &lref;
+ RecordType &&rref;
+
+public:
+ ReferenceTest2(RecordType &lref, RecordType &rref)
+ : lref(lref), rref(static_cast<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}}
+ }
+};
+
+void fReferenceTest2() {
+ ReferenceTest2::RecordType c;
+ ReferenceTest2(c, c);
+}
+#else
+class ReferenceTest2 {
+public:
+ struct RecordType {
+ int x;
+ int y;
+ };
+
+private:
+ RecordType &lref;
+ RecordType &&rref;
+
+public:
+ ReferenceTest2(RecordType &lref, RecordType &rref)
+ : lref(lref), rref(static_cast<RecordType &&>(rref)) {
+ }
+};
+
+void fReferenceTest2() {
+ ReferenceTest2::RecordType c;
+ ReferenceTest2(c, c);
+}
+#endif // PEDANTIC
+
+class ReferenceTest3 {
+public:
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->lref.x'}}
+ int y; // expected-note{{uninitialized field 'this->lref.y'}}
+ };
+
+private:
+ RecordType &lref;
+ RecordType &&rref;
+
+public:
+ ReferenceTest3(RecordType &lref, RecordType &rref)
+ : lref(lref), rref(static_cast<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}}
+ }
+};
+
+void fReferenceTest3() {
+ ReferenceTest3::RecordType c, d{35, 36};
+ ReferenceTest3(c, d);
+}
+
+class ReferenceTest4 {
+public:
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->rref.x'}}
+ int y; // expected-note{{uninitialized field 'this->rref.y'}}
+ };
+
+private:
+ RecordType &lref;
+ RecordType &&rref;
+
+public:
+ ReferenceTest4(RecordType &lref, RecordType &rref)
+ : lref(lref), rref(static_cast<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}}
+ }
+};
+
+void fReferenceTest5() {
+ ReferenceTest4::RecordType c, d{37, 38};
+ ReferenceTest4(d, c);
+}
diff --git a/test/Analysis/cxx-uninitialized-object.cpp b/test/Analysis/cxx-uninitialized-object.cpp
new file mode 100644
index 0000000000..617ac78f40
--- /dev/null
+++ b/test/Analysis/cxx-uninitialized-object.cpp
@@ -0,0 +1,1058 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
+
+//===----------------------------------------------------------------------===//
+// Default constructor test.
+//===----------------------------------------------------------------------===//
+
+class CompilerGeneratedConstructorTest {
+ int a, b, c, d, e, f, g, h, i, j;
+
+public:
+ CompilerGeneratedConstructorTest() = default;
+};
+
+void fCompilerGeneratedConstructorTest() {
+ CompilerGeneratedConstructorTest();
+}
+
+#ifdef PEDANTIC
+class DefaultConstructorTest {
+ int a; // expected-note{{uninitialized field 'this->a'}}
+
+public:
+ DefaultConstructorTest();
+};
+
+DefaultConstructorTest::DefaultConstructorTest() = default;
+
+void fDefaultConstructorTest() {
+ DefaultConstructorTest(); // expected-warning{{1 uninitialized field}}
+}
+#else
+class DefaultConstructorTest {
+ int a;
+
+public:
+ DefaultConstructorTest();
+};
+
+DefaultConstructorTest::DefaultConstructorTest() = default;
+
+void fDefaultConstructorTest() {
+ DefaultConstructorTest();
+}
+#endif // PEDANTIC
+
+//===----------------------------------------------------------------------===//
+// Initializer list test.
+//===----------------------------------------------------------------------===//
+
+class InitListTest1 {
+ int a;
+ int b;
+
+public:
+ InitListTest1()
+ : a(1),
+ b(2) {
+ // All good!
+ }
+};
+
+void fInitListTest1() {
+ InitListTest1();
+}
+
+class InitListTest2 {
+ int a;
+ int b; // expected-note{{uninitialized field 'this->b'}}
+
+public:
+ InitListTest2()
+ : a(3) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fInitListTest2() {
+ InitListTest2();
+}
+
+class InitListTest3 {
+ int a; // expected-note{{uninitialized field 'this->a'}}
+ int b;
+
+public:
+ InitListTest3()
+ : b(4) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fInitListTest3() {
+ InitListTest3();
+}
+
+//===----------------------------------------------------------------------===//
+// Constructor body test.
+//===----------------------------------------------------------------------===//
+
+class CtorBodyTest1 {
+ int a, b;
+
+public:
+ CtorBodyTest1() {
+ a = 5;
+ b = 6;
+ // All good!
+ }
+};
+
+void fCtorBodyTest1() {
+ CtorBodyTest1();
+}
+
+class CtorBodyTest2 {
+ int a;
+ int b; // expected-note{{uninitialized field 'this->b'}}
+
+public:
+ CtorBodyTest2() {
+ a = 7; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fCtorBodyTest2() {
+ CtorBodyTest2();
+}
+
+class CtorBodyTest3 {
+ int a; // expected-note{{uninitialized field 'this->a'}}
+ int b;
+
+public:
+ CtorBodyTest3() {
+ b = 8; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fCtorBodyTest3() {
+ CtorBodyTest3();
+}
+
+#ifdef PEDANTIC
+class CtorBodyTest4 {
+ int a; // expected-note{{uninitialized field 'this->a'}}
+ int b; // expected-note{{uninitialized field 'this->b'}}
+
+public:
+ CtorBodyTest4() {}
+};
+
+void fCtorBodyTest4() {
+ CtorBodyTest4(); // expected-warning{{2 uninitialized fields}}
+}
+#else
+class CtorBodyTest4 {
+ int a;
+ int b;
+
+public:
+ CtorBodyTest4() {}
+};
+
+void fCtorBodyTest4() {
+ CtorBodyTest4();
+}
+#endif
+
+//===----------------------------------------------------------------------===//
+// Constructor delegation test.
+//===----------------------------------------------------------------------===//
+
+class CtorDelegationTest1 {
+ int a;
+ int b;
+
+public:
+ CtorDelegationTest1(int)
+ : a(9) {
+ // leaves 'b' unintialized, but we'll never check this function
+ }
+
+ CtorDelegationTest1()
+ : CtorDelegationTest1(int{}) { // Initializing 'a'
+ b = 10;
+ // All good!
+ }
+};
+
+void fCtorDelegationTest1() {
+ CtorDelegationTest1();
+}
+
+class CtorDelegationTest2 {
+ int a; // expected-note{{uninitialized field 'this->a'}}
+ int b;
+
+public:
+ CtorDelegationTest2(int)
+ : b(11) {
+ // leaves 'a' unintialized, but we'll never check this function
+ }
+
+ CtorDelegationTest2()
+ : CtorDelegationTest2(int{}) { // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fCtorDelegationTest2() {
+ CtorDelegationTest2();
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for classes containing records.
+//===----------------------------------------------------------------------===//
+
+class ContainsRecordTest1 {
+ struct RecordType {
+ int x;
+ int y;
+ } rec;
+ int c, d;
+
+public:
+ ContainsRecordTest1()
+ : rec({12, 13}),
+ c(14),
+ d(15) {
+ // All good!
+ }
+};
+
+void fContainsRecordTest1() {
+ ContainsRecordTest1();
+}
+
+class ContainsRecordTest2 {
+ struct RecordType {
+ int x;
+ int y; // expected-note{{uninitialized field 'this->rec.y'}}
+ } rec;
+ int c, d;
+
+public:
+ ContainsRecordTest2()
+ : c(16),
+ d(17) {
+ rec.x = 18; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fContainsRecordTest2() {
+ ContainsRecordTest2();
+}
+
+class ContainsRecordTest3 {
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->rec.x'}}
+ int y; // expected-note{{uninitialized field 'this->rec.y'}}
+ } rec;
+ int c, d;
+
+public:
+ ContainsRecordTest3()
+ : c(19),
+ d(20) { // expected-warning{{2 uninitialized fields}}
+ }
+};
+
+void fContainsRecordTest3() {
+ ContainsRecordTest3();
+}
+
+class ContainsRecordTest4 {
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->rec.x'}}
+ int y; // expected-note{{uninitialized field 'this->rec.y'}}
+ } rec;
+ int c, d; // expected-note{{uninitialized field 'this->d'}}
+
+public:
+ ContainsRecordTest4()
+ : c(19) { // expected-warning{{3 uninitialized fields}}
+ }
+};
+
+void fContainsRecordTest4() {
+ ContainsRecordTest4();
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for template classes.
+//===----------------------------------------------------------------------===//
+
+template <class T>
+class IntTemplateClassTest1 {
+ T t;
+ int b;
+
+public:
+ IntTemplateClassTest1(T i) {
+ b = 21;
+ t = i;
+ // All good!
+ }
+};
+
+void fIntTemplateClassTest1() {
+ IntTemplateClassTest1<int>(22);
+}
+
+template <class T>
+class IntTemplateClassTest2 {
+ T t; // expected-note{{uninitialized field 'this->t'}}
+ int b;
+
+public:
+ IntTemplateClassTest2() {
+ b = 23; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fIntTemplateClassTest2() {
+ IntTemplateClassTest2<int>();
+}
+
+struct Record {
+ int x; // expected-note{{uninitialized field 'this->t.x'}}
+ int y; // expected-note{{uninitialized field 'this->t.y'}}
+};
+
+template <class T>
+class RecordTemplateClassTest {
+ T t;
+ int b;
+
+public:
+ RecordTemplateClassTest() {
+ b = 24; // expected-warning{{2 uninitialized fields}}
+ }
+};
+
+void fRecordTemplateClassTest() {
+ RecordTemplateClassTest<Record>();
+}
+
+//===----------------------------------------------------------------------===//
+// Tests involving functions with unknown implementations.
+//===----------------------------------------------------------------------===//
+
+template <class T>
+void mayInitialize(T &);
+
+template <class T>
+void wontInitialize(const T &);
+
+class PassingToUnknownFunctionTest1 {
+ int a, b;
+
+public:
+ PassingToUnknownFunctionTest1() {
+ mayInitialize(a);
+ mayInitialize(b);
+ // All good!
+ }
+
+ PassingToUnknownFunctionTest1(int) {
+ mayInitialize(a);
+ // All good!
+ }
+
+ PassingToUnknownFunctionTest1(int, int) {
+ mayInitialize(*this);
+ // All good!
+ }
+};
+
+void fPassingToUnknownFunctionTest1() {
+ PassingToUnknownFunctionTest1();
+ PassingToUnknownFunctionTest1(int());
+ PassingToUnknownFunctionTest1(int(), int());
+}
+
+class PassingToUnknownFunctionTest2 {
+ int a; // expected-note{{uninitialized field 'this->a'}}
+ int b;
+
+public:
+ PassingToUnknownFunctionTest2() {
+ wontInitialize(a);
+ b = 4; // expected-warning{{1 uninitialized field}}
+ }
+};
+
+void fPassingToUnknownFunctionTest2() {
+ PassingToUnknownFunctionTest2();
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for classes containing unions.
+//===----------------------------------------------------------------------===//
+
+// FIXME: As of writing this checker, there is no good support for union types
+// in the Static Analyzer. Here is non-exhaustive list of cases.
+// Note that the rules for unions are different in C and C++.
+// http://lists.llvm.org/pipermail/cfe-dev/2017-March/052910.html
+
+class ContainsSimpleUnionTest1 {
+ union SimpleUnion {
+ float uf;
+ int ui;
+ char uc;
+ } u;
+
+public:
+ ContainsSimpleUnionTest1() {
+ u.uf = 3.14;
+ // All good!
+ }
+};
+
+void fContainsSimpleUnionTest1() {
+ ContainsSimpleUnionTest1();
+}
+
+class ContainsSimpleUnionTest2 {
+ union SimpleUnion {
+ float uf;
+ int ui;
+ char uc;
+ // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
+ } u; // no-note
+
+public:
+ ContainsSimpleUnionTest2() {}
+};
+
+void fContainsSimpleUnionTest2() {
+ // TODO: we'd expect the warning: {{1 uninitialized field}}
+ ContainsSimpleUnionTest2(); // no-warning
+}
+
+class UnionPointerTest1 {
+public:
+ union SimpleUnion {
+ float uf;
+ int ui;
+ char uc;
+ };
+
+private:
+ SimpleUnion *uptr;
+
+public:
+ UnionPointerTest1(SimpleUnion *uptr, int) : uptr(uptr) {
+ // All good!
+ }
+};
+
+void fUnionPointerTest1() {
+ UnionPointerTest1::SimpleUnion u;
+ u.uf = 41;
+ UnionPointerTest1(&u, int());
+}
+
+class UnionPointerTest2 {
+public:
+ union SimpleUnion {
+ float uf;
+ int ui;
+ char uc;
+ };
+
+private:
+ // TODO: we'd expect the note: {{uninitialized field 'this->uptr'}}
+ SimpleUnion *uptr; // no-note
+
+public:
+ UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {}
+};
+
+void fUnionPointerTest2() {
+ UnionPointerTest2::SimpleUnion u;
+ // TODO: we'd expect the warning: {{1 uninitialized field}}
+ UnionPointerTest2(&u, int()); // no-warning
+}
+
+class ContainsUnionWithRecordTest1 {
+ union UnionWithRecord {
+ struct RecordType {
+ int x;
+ int y;
+ } us;
+ double ud;
+ long ul;
+
+ UnionWithRecord(){};
+ } u;
+
+public:
+ ContainsUnionWithRecordTest1() {
+ u.ud = 3.14;
+ // All good!
+ }
+};
+
+void fContainsUnionWithRecordTest1() {
+ ContainsUnionWithRecordTest1();
+}
+
+class ContainsUnionWithRecordTest2 {
+ union UnionWithRecord {
+ struct RecordType {
+ int x;
+ int y;
+ } us;
+ double ud;
+ long ul;
+
+ UnionWithRecord(){};
+ } u;
+
+public:
+ ContainsUnionWithRecordTest2() {
+ u.us = UnionWithRecord::RecordType{42, 43};
+ // All good!
+ }
+};
+
+void fContainsUnionWithRecordTest2() {
+ ContainsUnionWithRecordTest1();
+}
+
+class ContainsUnionWithRecordTest3 {
+ union UnionWithRecord {
+ struct RecordType {
+ int x;
+ int y;
+ } us;
+ double ud;
+ long ul;
+
+ UnionWithRecord(){};
+ // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
+ } u; // no-note
+
+public:
+ ContainsUnionWithRecordTest3() {
+ UnionWithRecord::RecordType rec;
+ rec.x = 44;
+ // TODO: we'd expect the warning: {{1 uninitialized field}}
+ u.us = rec; // no-warning
+ }
+};
+
+void fContainsUnionWithRecordTest3() {
+ ContainsUnionWithRecordTest3();
+}
+
+class ContainsUnionWithSimpleUnionTest1 {
+ union UnionWithSimpleUnion {
+ union SimpleUnion {
+ float uf;
+ int ui;
+ char uc;
+ } usu;
+ long ul;
+ unsigned uu;
+ } u;
+
+public:
+ ContainsUnionWithSimpleUnionTest1() {
+ u.usu.ui = 5;
+ // All good!
+ }
+};
+
+void fContainsUnionWithSimpleUnionTest1() {
+ ContainsUnionWithSimpleUnionTest1();
+}
+
+class ContainsUnionWithSimpleUnionTest2 {
+ union UnionWithSimpleUnion {
+ union SimpleUnion {
+ float uf;
+ int ui;
+ char uc;
+ } usu;
+ long ul;
+ unsigned uu;
+ // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
+ } u; // no-note
+
+public:
+ ContainsUnionWithSimpleUnionTest2() {}
+};
+
+void fContainsUnionWithSimpleUnionTest2() {
+ // TODO: we'd expect the warning: {{1 uninitialized field}}
+ ContainsUnionWithSimpleUnionTest2(); // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// Zero initialization tests.
+//===----------------------------------------------------------------------===//
+
+struct GlobalVariableTest {
+ int i;
+
+ GlobalVariableTest() {}
+};
+
+GlobalVariableTest gvt; // no-warning
+
+//===----------------------------------------------------------------------===//
+// Copy and move constructor tests.
+//===----------------------------------------------------------------------===//
+
+template <class T>
+void funcToSquelchCompilerWarnings(const T &t);
+
+#ifdef PEDANTIC
+struct CopyConstructorTest {
+ int i; // expected-note{{uninitialized field 'this->i'}}
+
+ CopyConstructorTest() : i(1337) {}
+ CopyConstructorTest(const CopyConstructorTest &other) {}
+};
+
+void fCopyConstructorTest() {
+ CopyConstructorTest cct;
+ CopyConstructorTest copy = cct; // expected-warning{{1 uninitialized field}}
+ funcToSquelchCompilerWarnings(copy);
+}
+#else
+struct CopyConstructorTest {
+ int i;
+
+ CopyConstructorTest() : i(1337) {}
+ CopyConstructorTest(const CopyConstructorTest &other) {}
+};
+
+void fCopyConstructorTest() {
+ CopyConstructorTest cct;
+ CopyConstructorTest copy = cct;
+ funcToSquelchCompilerWarnings(copy);
+}
+#endif // PEDANTIC
+
+struct MoveConstructorTest {
+ // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
+ int i; // no-note
+
+ MoveConstructorTest() : i(1337) {}
+ MoveConstructorTest(const CopyConstructorTest &other) = delete;
+ MoveConstructorTest(const CopyConstructorTest &&other) {}
+};
+
+void fMoveConstructorTest() {
+ MoveConstructorTest cct;
+ // TODO: we'd expect the warning: {{1 uninitialized field}}
+ MoveConstructorTest copy(static_cast<MoveConstructorTest &&>(cct)); // no-warning
+ funcToSquelchCompilerWarnings(copy);
+}
+
+//===----------------------------------------------------------------------===//
+// Array tests.
+//===----------------------------------------------------------------------===//
+
+struct IntArrayTest {
+ int arr[256];
+
+ IntArrayTest() {
+ // All good!
+ }
+};
+
+void fIntArrayTest() {
+ IntArrayTest();
+}
+
+struct RecordTypeArrayTest {
+ struct RecordType {
+ int x, y;
+ } arr[256];
+
+ RecordTypeArrayTest() {
+ // All good!
+ }
+};
+
+void fRecordTypeArrayTest() {
+ RecordTypeArrayTest();
+}
+
+template <class T>
+class CharArrayPointerTest {
+ T *t; // no-crash
+
+public:
+ CharArrayPointerTest(T *t, int) : t(t) {}
+};
+
+void fCharArrayPointerTest() {
+ char str[16] = "012345678912345";
+ CharArrayPointerTest<char[16]>(&str, int());
+}
+
+//===----------------------------------------------------------------------===//
+// Memset tests.
+//===----------------------------------------------------------------------===//
+
+struct MemsetTest1 {
+ int a, b, c;
+
+ MemsetTest1() {
+ __builtin_memset(this, 0, sizeof(decltype(*this)));
+ }
+};
+
+void fMemsetTest1() {
+ MemsetTest1();
+}
+
+struct MemsetTest2 {
+ int a;
+
+ MemsetTest2() {
+ __builtin_memset(&a, 0, sizeof(int));
+ }
+};
+
+void fMemsetTest2() {
+ MemsetTest2();
+}
+
+//===----------------------------------------------------------------------===//
+// Lambda tests.
+//===----------------------------------------------------------------------===//
+
+template <class Callable>
+struct LambdaTest1 {
+ Callable functor;
+
+ LambdaTest1(const Callable &functor, int) : functor(functor) {
+ // All good!
+ }
+};
+
+void fLambdaTest1() {
+ auto isEven = [](int a) { return a % 2 == 0; };
+ LambdaTest1<decltype(isEven)>(isEven, int());
+}
+
+#ifdef PEDANTIC
+template <class Callable>
+struct LambdaTest2 {
+ Callable functor;
+
+ LambdaTest2(const Callable &functor, int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fLambdaTest2() {
+ int b;
+ auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
+ LambdaTest2<decltype(equals)>(equals, int());
+}
+#else
+template <class Callable>
+struct LambdaTest2 {
+ Callable functor;
+
+ LambdaTest2(const Callable &functor, int) : functor(functor) {}
+};
+
+void fLambdaTest2() {
+ int b;
+ auto equals = [&b](int a) { return a == b; };
+ LambdaTest2<decltype(equals)>(equals, int());
+}
+#endif //PEDANTIC
+
+#ifdef PEDANTIC
+namespace LT3Detail {
+
+struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->functor..x'}}
+ int y; // expected-note{{uninitialized field 'this->functor..y'}}
+};
+
+} // namespace LT3Detail
+template <class Callable>
+struct LambdaTest3 {
+ Callable functor;
+
+ LambdaTest3(const Callable &functor, int) : functor(functor) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fLambdaTest3() {
+ LT3Detail::RecordType rec1;
+ auto equals = [&rec1](LT3Detail::RecordType rec2) {
+ return rec1.x == rec2.x;
+ };
+ LambdaTest3<decltype(equals)>(equals, int());
+}
+#else
+namespace LT3Detail {
+
+struct RecordType {
+ int x;
+ int y;
+};
+
+} // namespace LT3Detail
+template <class Callable>
+struct LambdaTest3 {
+ Callable functor;
+
+ LambdaTest3(const Callable &functor, int) : functor(functor) {}
+};
+
+void fLambdaTest3() {
+ LT3Detail::RecordType rec1;
+ auto equals = [&rec1](LT3Detail::RecordType rec2) {
+ return rec1.x == rec2.x;
+ };
+ LambdaTest3<decltype(equals)>(equals, int());
+}
+#endif //PEDANTIC
+
+//===----------------------------------------------------------------------===//
+// System header tests.
+//===----------------------------------------------------------------------===//
+
+#include "Inputs/system-header-simulator-for-cxx-uninitialized-object.h"
+
+struct SystemHeaderTest1 {
+ RecordInSystemHeader rec; // defined in the system header simulator
+
+ SystemHeaderTest1() {
+ // All good!
+ }
+};
+
+void fSystemHeaderTest1() {
+ SystemHeaderTest1();
+}
+
+#ifdef PEDANTIC
+struct SystemHeaderTest2 {
+ struct RecordType {
+ int x; // expected-note{{uninitialized field 'this->container.t.x}}
+ int y; // expected-note{{uninitialized field 'this->container.t.y}}
+ };
+ ContainerInSystemHeader<RecordType> container;
+
+ SystemHeaderTest2(RecordType &rec, int) : container(rec) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fSystemHeaderTest2() {
+ SystemHeaderTest2::RecordType rec;
+ SystemHeaderTest2(rec, int());
+}
+#else
+struct SystemHeaderTest2 {
+ struct RecordType {
+ int x;
+ int y;
+ };
+ ContainerInSystemHeader<RecordType> container;
+
+ SystemHeaderTest2(RecordType &rec, int) : container(rec) {}
+};
+
+void fSystemHeaderTest2() {
+ SystemHeaderTest2::RecordType rec;
+ SystemHeaderTest2(rec, int());
+}
+#endif //PEDANTIC
+
+//===----------------------------------------------------------------------===//
+// Incomplete type tests.
+//===----------------------------------------------------------------------===//
+
+struct IncompleteTypeTest1 {
+ struct RecordType;
+ // no-crash
+ RecordType *recptr; // expected-note{{uninitialized pointer 'this->recptr}}
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ IncompleteTypeTest1() {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIncompleteTypeTest1() {
+ IncompleteTypeTest1();
+}
+
+struct IncompleteTypeTest2 {
+ struct RecordType;
+ RecordType *recptr; // no-crash
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ RecordType *recordTypeFactory();
+
+ IncompleteTypeTest2() : recptr(recordTypeFactory()) {}
+};
+
+void fIncompleteTypeTest2() {
+ IncompleteTypeTest2();
+}
+
+struct IncompleteTypeTest3 {
+ struct RecordType;
+ RecordType &recref; // no-crash
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ RecordType &recordTypeFactory();
+
+ IncompleteTypeTest3() : recref(recordTypeFactory()) {}
+};
+
+void fIncompleteTypeTest3() {
+ IncompleteTypeTest3();
+}
+
+//===----------------------------------------------------------------------===//
+// Builtin type or enumeration type related tests.
+//===----------------------------------------------------------------------===//
+
+struct IntegralTypeTest {
+ int a; // expected-note{{uninitialized field 'this->a'}}
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ IntegralTypeTest() {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIntegralTypeTest() {
+ IntegralTypeTest();
+}
+
+struct FloatingTypeTest {
+ float a; // expected-note{{uninitialized field 'this->a'}}
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ FloatingTypeTest() {} // expected-warning{{1 uninitialized field}}
+};
+
+void fFloatingTypeTest() {
+ FloatingTypeTest();
+}
+
+struct NullptrTypeTypeTest {
+ decltype(nullptr) a; // expected-note{{uninitialized field 'this->a'}}
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ NullptrTypeTypeTest() {} // expected-warning{{1 uninitialized field}}
+};
+
+void fNullptrTypeTypeTest() {
+ NullptrTypeTypeTest();
+}
+
+struct EnumTest {
+ enum Enum {
+ A,
+ B
+ } enum1; // expected-note{{uninitialized field 'this->enum1'}}
+ enum class Enum2 {
+ A,
+ B
+ } enum2; // expected-note{{uninitialized field 'this->enum2'}}
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ EnumTest() {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fEnumTest() {
+ EnumTest();
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for constructor calls within another cunstructor, without the two
+// records being in any relation.
+//===----------------------------------------------------------------------===//
+
+void halt() __attribute__((__noreturn__));
+void assert(int b) {
+ if (!b)
+ halt();
+}
+
+// While a singleton would make more sense as a static variable, that would zero
+// initialize all of its fields, hence the not too practical implementation.
+struct Singleton {
+ // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
+ int i; // no-note
+
+ Singleton() {
+ assert(!isInstantiated);
+ // TODO: we'd expect the warning: {{1 uninitialized field}}
+ isInstantiated = true; // no-warning
+ }
+
+ ~Singleton() {
+ isInstantiated = false;
+ }
+
+ static bool isInstantiated;
+};
+
+bool Singleton::isInstantiated = false;
+
+struct SingletonTest {
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ SingletonTest() {
+ Singleton();
+ }
+};
+
+void fSingletonTest() {
+ SingletonTest();
+}
+
+//===----------------------------------------------------------------------===//
+// C++11 member initializer tests.
+//===----------------------------------------------------------------------===//
+
+struct CXX11MemberInitTest1 {
+ int a = 3;
+ int b;
+ CXX11MemberInitTest1() : b(2) {
+ // All good!
+ }
+};
+
+void fCXX11MemberInitTest1() {
+ CXX11MemberInitTest1();
+}
+
+struct CXX11MemberInitTest2 {
+ struct RecordType {
+ // TODO: we'd expect the note: {{uninitialized field 'this->rec.a'}}
+ int a; // no-note
+ // TODO: we'd expect the note: {{uninitialized field 'this->rec.b'}}
+ int b; // no-note
+
+ RecordType(int) {}
+ };
+
+ RecordType rec = RecordType(int());
+ int dontGetFilteredByNonPedanticMode = 0;
+
+ CXX11MemberInitTest2() {}
+};
+
+void fCXX11MemberInitTest2() {
+ // TODO: we'd expect the warning: {{2 uninitializeds field}}
+ CXX11MemberInitTest2(); // no-warning
+}