r334935 - [analyzer] Checker for uninitialized C++ objects

Mikael Holmén via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 18 23:28:05 PDT 2018


Hi Kristof,

Building without asserts (-DNDEBUG) I get the following warning/error 
with this commit:

[3082/3387] Building CXX object 
tools/clang/lib/StaticAnalyzer/Checkers...eFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.
FAILED: 
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o 

/repo/app/clang/3.6/bin/clang++  -march=corei7  -DGTEST_HAS_RTTI=0 
-D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS 
-D__STDC_LIMIT_MACROS -Itools/clang/lib/StaticAnalyzer/Checkers 
-I../tools/clang/lib/StaticAnalyzer/Checkers -I../tools/clang/include 
-Itools/clang/include -I/usr/include/libxml2 -Iinclude -I../include 
-I/repo/app/valgrind/3.11.0/include  -fPIC -fvisibility-inlines-hidden 
-Werror -Werror=date-time -std=c++11 -Wall -Wextra -Wno-unused-parameter 
-Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic 
-Wno-long-long -Wcovered-switch-default -Wnon-virtual-dtor 
-Wdelete-non-virtual-dtor -Wstring-conversion -fdiagnostics-color 
-ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual 
-Wno-nested-anon-types -O3 -DNDEBUG    -fno-exceptions -fno-rtti -MMD 
-MT 
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o 
-MF 
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o.d 
-o 
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o 
-c ../tools/clang/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
../tools/clang/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:215:6: 
error: unused function 'isPrimitiveType' [-Werror,-Wunused-function]
bool isPrimitiveType(const QualType &T) {
      ^
1 error generated.

Regards,
Mikael

On 06/18/2018 01:50 PM, Kristof Umann via cfe-commits wrote:
> Author: szelethus
> Date: Mon Jun 18 04:50:17 2018
> New Revision: 334935
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=334935&view=rev
> Log:
> [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
> 
> Added:
>      cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
>      cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h
>      cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp
>      cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
>      cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp
> Modified:
>      cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
>      cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
> 
> Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td?rev=334935&r1=334934&r2=334935&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td (original)
> +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td Mon Jun 18 04:50:17 2018
> @@ -319,6 +319,10 @@ def MisusedMovedObjectChecker: Checker<"
>                 "object will be reported">,
>        DescFile<"MisusedMovedObjectChecker.cpp">;
>   
> +def UninitializedObjectChecker: Checker<"UninitializedObject">,
> +     HelpText<"Reports uninitialized fields after object construction">,
> +     DescFile<"UninitializedObjectChecker.cpp">;
> +
>   } // end: "alpha.cplusplus"
>   
>   
> 
> Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=334935&r1=334934&r2=334935&view=diff
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original)
> +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Mon Jun 18 04:50:17 2018
> @@ -92,6 +92,7 @@ add_clang_library(clangStaticAnalyzerChe
>     UndefResultChecker.cpp
>     UndefinedArraySubscriptChecker.cpp
>     UndefinedAssignmentChecker.cpp
> +  UninitializedObjectChecker.cpp
>     UnixAPIChecker.cpp
>     UnreachableCodeChecker.cpp
>     VforkChecker.cpp
> 
> Added: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp (added)
> +++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp Mon Jun 18 04:50:17 2018
> @@ -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);
> +}
> 
> Added: cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h (added)
> +++ cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h Mon Jun 18 04:50:17 2018
> @@ -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) {}
> +};
> 
> Added: cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp (added)
> +++ cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp Mon Jun 18 04:50:17 2018
> @@ -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 at -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();
> +}
> 
> Added: cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp (added)
> +++ cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp Mon Jun 18 04:50:17 2018
> @@ -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);
> +}
> 
> Added: cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp (added)
> +++ cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp Mon Jun 18 04:50:17 2018
> @@ -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
> +}
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
> 


More information about the cfe-commits mailing list