<commit_before>//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ToolChains.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"

using namespace clang::diag;
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
    : ToolChain(D, Triple, Args) {
  getProgramPaths().push_back(getDriver().getInstalledDir());

  llvm::SmallString<1024> LibDir;

  // In Windows there aren't any standard install locations, we search
  // for gcc on the PATH. In Liunx the base is always /usr.
#ifdef LLVM_ON_WIN32
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else if (llvm::ErrorOr<std::string> GPPName =
               llvm::sys::findProgramByName("gcc"))
    Base = llvm::sys::path::parent_path(
        llvm::sys::path::parent_path(GPPName.get()));
  else
    Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
  Base += llvm::sys::path::get_separator();
#else
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else
    Base = "/usr/";
#endif

  // By default Arch is for mingw-w64.
  Arch = (getTriple().getArchName() + "-w64-mingw32").str();
  // lib: Arch Linux, Ubuntu, Windows
  // lib64: openSUSE Linux
  for (StringRef Lib : {"lib", "lib64 "}) {
    LibDir = Base;
    llvm::sys::path::append(LibDir, Lib, "gcc");
    LibDir += llvm::sys::path::get_separator();
    std::error_code EC;
    // First look for mingw-w64.
    llvm::sys::fs::directory_iterator MingW64Entry(LibDir + Arch, EC);
    if (!EC) {
      GccLibDir = MingW64Entry->path();
      Ver = llvm::sys::path::filename(GccLibDir);
      break;
    }
    // If mingw-w64 not found, try looking for mingw.org.
    llvm::sys::fs::directory_iterator MingwOrgEntry(LibDir + "mingw32", EC);
    if (!EC) {
      GccLibDir = MingwOrgEntry->path();
      // Replace Arch with mingw32 arch.
      Arch = "mingw32";
      break;
    }
  }

  Arch += llvm::sys::path::get_separator();
  // GccLibDir must precede Base/lib so that the
  // correct crtbegin.o ,cetend.o would be found.
  getFilePaths().push_back(GccLibDir);
  getFilePaths().push_back(Base + Arch + "lib");
#ifdef LLVM_ON_WIN32
  getFilePaths().push_back(Base + "lib");
#else
  // openSUSE
  getFilePaths().push_back(Base + Arch + "sys-root/mingw/lib");
#endif
}

bool MinGW::IsIntegratedAssemblerDefault() const { return true; }

Tool *MinGW::getTool(Action::ActionClass AC) const {
  switch (AC) {
  case Action::PreprocessJobClass:
    if (!Preprocessor)
      Preprocessor.reset(new tools::gcc::Preprocessor(*this));
    return Preprocessor.get();
  case Action::CompileJobClass:
    if (!Compiler)
      Compiler.reset(new tools::gcc::Compiler(*this));
    return Compiler.get();
  default:
    return ToolChain::getTool(AC);
  }
}

Tool *MinGW::buildAssembler() const {
  return new tools::MinGW::Assembler(*this);
}

Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); }

bool MinGW::IsUnwindTablesDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; }

bool MinGW::isPIEDefault() const { return false; }

bool MinGW::isPICDefaultForced() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::UseSEHExceptions() const {
  return getArch() == llvm::Triple::x86_64;
}

void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                      ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
    SmallString<1024> P(getDriver().ResourceDir);
    llvm::sys::path::append(P, "include");
    addSystemInclude(DriverArgs, CC1Args, P.str());
  }

  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

  llvm::SmallString<1024> IncludeDir(GccLibDir);
  llvm::sys::path::append(IncludeDir, "include");
  addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
  IncludeDir += "-fixed";
#ifdef LLVM_ON_UNIX
  // openSUSE
  addSystemInclude(DriverArgs, CC1Args,
                   "/usr/x86_64-w64-mingw32/sys-root/mingw/include");
#endif
  addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
  addSystemInclude(DriverArgs, CC1Args, Base + Arch + "include");
  addSystemInclude(DriverArgs, CC1Args, Base + "include");
}

void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                         ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
      DriverArgs.hasArg(options::OPT_nostdincxx))
    return;

  // C++ includes locations are different with almost every mingw distribution.
  //
  // Windows
  // -------
  // mingw-w64 mingw-builds: $sysroot/i686-w64-mingw32/include/c++
  // mingw-w64 msys2:        $sysroot/include/c++/4.9.2
  // mingw.org:              GccLibDir/include/c++
  //
  // Linux
  // -----
  // openSUSE:               GccLibDir/include/c++
  // Arch:                   $sysroot/i686-w64-mingw32/include/c++/5.1.0
  //
  llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
  CppIncludeBases.emplace_back(Base);
  llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
  CppIncludeBases.emplace_back(Base);
  llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
  CppIncludeBases.emplace_back(Base);
  llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
  CppIncludeBases.emplace_back(GccLibDir);
  llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
  for (auto &CppIncludeBase : CppIncludeBases) {
    CppIncludeBase += llvm::sys::path::get_separator();
    addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
    addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
    addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
  }
}
<commit_msg>Fix typo found by Joerg Sonnenberger.<commit_after>//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ToolChains.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"

using namespace clang::diag;
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
    : ToolChain(D, Triple, Args) {
  getProgramPaths().push_back(getDriver().getInstalledDir());

  llvm::SmallString<1024> LibDir;

  // In Windows there aren't any standard install locations, we search
  // for gcc on the PATH. In Linux the base is always /usr.
#ifdef LLVM_ON_WIN32
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else if (llvm::ErrorOr<std::string> GPPName =
               llvm::sys::findProgramByName("gcc"))
    Base = llvm::sys::path::parent_path(
        llvm::sys::path::parent_path(GPPName.get()));
  else
    Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
  Base += llvm::sys::path::get_separator();
#else
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else
    Base = "/usr/";
#endif

  // By default Arch is for mingw-w64.
  Arch = (getTriple().getArchName() + "-w64-mingw32").str();
  // lib: Arch Linux, Ubuntu, Windows
  // lib64: openSUSE Linux
  for (StringRef Lib : {"lib", "lib64 "}) {
    LibDir = Base;
    llvm::sys::path::append(LibDir, Lib, "gcc");
    LibDir += llvm::sys::path::get_separator();
    std::error_code EC;
    // First look for mingw-w64.
    llvm::sys::fs::directory_iterator MingW64Entry(LibDir + Arch, EC);
    if (!EC) {
      GccLibDir = MingW64Entry->path();
      Ver = llvm::sys::path::filename(GccLibDir);
      break;
    }
    // If mingw-w64 not found, try looking for mingw.org.
    llvm::sys::fs::directory_iterator MingwOrgEntry(LibDir + "mingw32", EC);
    if (!EC) {
      GccLibDir = MingwOrgEntry->path();
      // Replace Arch with mingw32 arch.
      Arch = "mingw32";
      break;
    }
  }

  Arch += llvm::sys::path::get_separator();
  // GccLibDir must precede Base/lib so that the
  // correct crtbegin.o ,cetend.o would be found.
  getFilePaths().push_back(GccLibDir);
  getFilePaths().push_back(Base + Arch + "lib");
#ifdef LLVM_ON_WIN32
  getFilePaths().push_back(Base + "lib");
#else
  // openSUSE
  getFilePaths().push_back(Base + Arch + "sys-root/mingw/lib");
#endif
}

bool MinGW::IsIntegratedAssemblerDefault() const { return true; }

Tool *MinGW::getTool(Action::ActionClass AC) const {
  switch (AC) {
  case Action::PreprocessJobClass:
    if (!Preprocessor)
      Preprocessor.reset(new tools::gcc::Preprocessor(*this));
    return Preprocessor.get();
  case Action::CompileJobClass:
    if (!Compiler)
      Compiler.reset(new tools::gcc::Compiler(*this));
    return Compiler.get();
  default:
    return ToolChain::getTool(AC);
  }
}

Tool *MinGW::buildAssembler() const {
  return new tools::MinGW::Assembler(*this);
}

Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); }

bool MinGW::IsUnwindTablesDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; }

bool MinGW::isPIEDefault() const { return false; }

bool MinGW::isPICDefaultForced() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::UseSEHExceptions() const {
  return getArch() == llvm::Triple::x86_64;
}

void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                      ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
    SmallString<1024> P(getDriver().ResourceDir);
    llvm::sys::path::append(P, "include");
    addSystemInclude(DriverArgs, CC1Args, P.str());
  }

  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

  llvm::SmallString<1024> IncludeDir(GccLibDir);
  llvm::sys::path::append(IncludeDir, "include");
  addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
  IncludeDir += "-fixed";
#ifdef LLVM_ON_UNIX
  // openSUSE
  addSystemInclude(DriverArgs, CC1Args,
                   "/usr/x86_64-w64-mingw32/sys-root/mingw/include");
#endif
  addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
  addSystemInclude(DriverArgs, CC1Args, Base + Arch + "include");
  addSystemInclude(DriverArgs, CC1Args, Base + "include");
}

void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                         ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
      DriverArgs.hasArg(options::OPT_nostdincxx))
    return;

  // C++ includes locations are different with almost every mingw distribution.
  //
  // Windows
  // -------
  // mingw-w64 mingw-builds: $sysroot/i686-w64-mingw32/include/c++
  // mingw-w64 msys2:        $sysroot/include/c++/4.9.2
  // mingw.org:              GccLibDir/include/c++
  //
  // Linux
  // -----
  // openSUSE:               GccLibDir/include/c++
  // Arch:                   $sysroot/i686-w64-mingw32/include/c++/5.1.0
  //
  llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
  CppIncludeBases.emplace_back(Base);
  llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
  CppIncludeBases.emplace_back(Base);
  llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
  CppIncludeBases.emplace_back(Base);
  llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
  CppIncludeBases.emplace_back(GccLibDir);
  llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
  for (auto &CppIncludeBase : CppIncludeBases) {
    CppIncludeBase += llvm::sys::path::get_separator();
    addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
    addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
    addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
  }
}
<|endoftext|>


<commit_before>#include "dg/MemorySSA/MemorySSA.h"

#include "dg/util/debug.h"

#ifndef NDEBUG
#include <iostream>
#endif

namespace dg {
namespace dda {

/// ------------------------------------------------------------------
// class Definitions
/// ------------------------------------------------------------------
///
// Update Definitions object with definitions from 'node'.
// 'defnode' is the node that should be added as the
// node that performs these definitions. Usually, defnode == node
// (defnode was added to correctly handle call nodes where the
// definitions are stored separately, but we want to have the call node
// as the node that defines the memory.
///
void Definitions::update(RWNode *node, RWNode *defnode) {
    if (!defnode)
        defnode = node;

    // possible definitions
    for (const auto &ds : node->getDefines()) {
        if (ds.target->isUnknown()) {
            // this makes all lastDefs into possibleDefs,
            // since we do not know if it was defined here or there
            // also add the definition as a proper target for Gvn
            definitions.addAll(defnode);
            addUnknownWrite(defnode);
        } else {
            definitions.add(ds, defnode);
        }
    }

    // definitive definitions
    for (const auto &ds : node->getOverwrites()) {
        assert((defnode->isPhi() || // we allow ? for PHI nodes
                !ds.offset.isUnknown()) &&
               "Update on unknown offset");
        assert(!ds.target->isUnknown() && "Update on unknown memory");

        kills.add(ds, defnode);
        definitions.update(ds, defnode);
    }

    // gather unknown uses
    if (node->usesUnknown()) {
        addUnknownRead(defnode);
    }
}

void Definitions::join(const Definitions &rhs) {
    definitions.add(rhs.definitions);
    kills = kills.intersect(rhs.kills);
    unknownWrites.insert(unknownWrites.end(), rhs.unknownWrites.begin(),
                         rhs.unknownWrites.end());
    unknownReads.insert(unknownReads.end(), rhs.unknownReads.begin(),
                        rhs.unknownReads.end());
}

#ifndef NDEBUG
void Definitions::dump() const {
    std::cout << "processed: " << _processed << "\n";
    std::cout << " -- defines -- \n";
    definitions.dump();
    std::cout << " -- kills -- \n";
    kills.dump();
    std::cout << " -- unknown reads -- \n";
    for (auto *nd : unknownReads) {
        std::cout << nd->getID() << " ";
    }
    std::cout << "\n";
    std::cout << " -- unknown writes -- \n";
    for (auto *nd : unknownWrites) {
        std::cout << nd->getID() << " ";
    }
    std::cout << std::endl;
}
#endif

} // namespace dda
} // namespace dg
<commit_msg>memoryssa: update an obsolete comment<commit_after>#include "dg/MemorySSA/MemorySSA.h"

#include "dg/util/debug.h"

#ifndef NDEBUG
#include <iostream>
#endif

namespace dg {
namespace dda {

/// ------------------------------------------------------------------
// class Definitions
/// ------------------------------------------------------------------
///
// Update Definitions object with definitions from 'node'.
// 'defnode' is the node that should be added as the
// node that performs these definitions. Usually, defnode == node
// (defnode was added to correctly handle call nodes where the
// definitions are stored separately, but we want to have the call node
// as the node that defines the memory.
///
void Definitions::update(RWNode *node, RWNode *defnode) {
    if (!defnode)
        defnode = node;

    // possible definitions
    for (const auto &ds : node->getDefines()) {
        if (ds.target->isUnknown()) {
            // add the definition to every known set of definitions
            // that we have so far
            definitions.addAll(defnode);
            // add the definition also as a proper target for Gvn,
            // since the previous step is not enough
            addUnknownWrite(defnode);
        } else {
            definitions.add(ds, defnode);
        }
    }

    // definitive definitions
    for (const auto &ds : node->getOverwrites()) {
        assert((defnode->isPhi() || // we allow ? for PHI nodes
                !ds.offset.isUnknown()) &&
               "Update on unknown offset");
        assert(!ds.target->isUnknown() && "Update on unknown memory");

        kills.add(ds, defnode);
        definitions.update(ds, defnode);
    }

    // gather unknown uses
    if (node->usesUnknown()) {
        addUnknownRead(defnode);
    }
}

void Definitions::join(const Definitions &rhs) {
    definitions.add(rhs.definitions);
    kills = kills.intersect(rhs.kills);
    unknownWrites.insert(unknownWrites.end(), rhs.unknownWrites.begin(),
                         rhs.unknownWrites.end());
    unknownReads.insert(unknownReads.end(), rhs.unknownReads.begin(),
                        rhs.unknownReads.end());
}

#ifndef NDEBUG
void Definitions::dump() const {
    std::cout << "processed: " << _processed << "\n";
    std::cout << " -- defines -- \n";
    definitions.dump();
    std::cout << " -- kills -- \n";
    kills.dump();
    std::cout << " -- unknown reads -- \n";
    for (auto *nd : unknownReads) {
        std::cout << nd->getID() << " ";
    }
    std::cout << "\n";
    std::cout << " -- unknown writes -- \n";
    for (auto *nd : unknownWrites) {
        std::cout << nd->getID() << " ";
    }
    std::cout << std::endl;
}
#endif

} // namespace dda
} // namespace dg
<|endoftext|>


<commit_before>// Copyright (c) 2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <tao/pegtl/internal/endian.hpp>

#include "test.hpp"

namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      void unit_test()
      {
         TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );

         const std::uint16_t a = 1;
         if(*static_cast<const std::uint8_t *>(static_cast<const void *>(&a)) != 1) {
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
         }
         else {
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
         }
      }

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao

#include "main.hpp"
<commit_msg>Formatting according to our .clang-format<commit_after>// Copyright (c) 2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <tao/pegtl/internal/endian.hpp>

#include "test.hpp"

namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      void unit_test()
      {
         TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int8_t( 0x7a ) ) == std::int8_t( 0x7a ) );
         TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint8_t( 0x7a ) ) == std::uint8_t( 0x7a ) );

         const std::uint16_t a = 1;
         if( *static_cast< const std::uint8_t* >( static_cast< const void* >( &a ) ) != 1 ) {
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
         }
         else {
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x7a39 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int16_t( 0x7a39 ) ) == std::int16_t( 0x397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint16_t( 0x7a39 ) ) == std::uint16_t( 0x397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x7a391f2b ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int32_t( 0x7a391f2b ) ) == std::int32_t( 0x2b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint32_t( 0x7a391f2b ) ) == std::uint32_t( 0x2b1f397a ) );

            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_le( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::h_to_be( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::le_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x7a391f2b33445567 ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::int64_t( 0x7a391f2b33445567 ) ) == std::int64_t( 0x675544332b1f397a ) );
            TAO_PEGTL_TEST_ASSERT( internal::be_to_h( std::uint64_t( 0x7a391f2b33445567 ) ) == std::uint64_t( 0x675544332b1f397a ) );
         }
      }

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao

#include "main.hpp"
<|endoftext|>


<commit_before>//==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Uninitialized Values analysis for source-level CFGs.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "llvm/Support/Compiler.h"

#include "llvm/ADT/SmallPtrSet.h"

using namespace clang;

//===----------------------------------------------------------------------===//
// Dataflow initialization logic.
//===----------------------------------------------------------------------===//

namespace {

class VISIBILITY_HIDDEN RegisterDecls
  : public CFGRecStmtDeclVisitor<RegisterDecls> {

  UninitializedValues::AnalysisDataTy& AD;
public:
  RegisterDecls(UninitializedValues::AnalysisDataTy& ad) :  AD(ad) {}

  void VisitVarDecl(VarDecl* VD) { AD.Register(VD); }
  CFG& getCFG() { return AD.getCFG(); }
};

} // end anonymous namespace

void UninitializedValues::InitializeValues(const CFG& cfg) {
  RegisterDecls R(getAnalysisData());
  cfg.VisitBlockStmts(R);
}

//===----------------------------------------------------------------------===//
// Transfer functions.
//===----------------------------------------------------------------------===//

namespace {
class VISIBILITY_HIDDEN TransferFuncs
  : public CFGStmtVisitor<TransferFuncs,bool> {

  UninitializedValues::ValTy V;
  UninitializedValues::AnalysisDataTy& AD;
public:
  TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}

  UninitializedValues::ValTy& getVal() { return V; }
  CFG& getCFG() { return AD.getCFG(); }

  void SetTopValue(UninitializedValues::ValTy& X) {
    X.setDeclValues(AD);
    X.resetBlkExprValues(AD);
  }

  bool VisitDeclRefExpr(DeclRefExpr* DR);
  bool VisitBinaryOperator(BinaryOperator* B);
  bool VisitUnaryOperator(UnaryOperator* U);
  bool VisitStmt(Stmt* S);
  bool VisitCallExpr(CallExpr* C);
  bool VisitDeclStmt(DeclStmt* D);
  bool VisitConditionalOperator(ConditionalOperator* C);
  bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);

  bool Visit(Stmt *S);
  bool BlockStmt_VisitExpr(Expr* E);

  void VisitTerminator(CFGBlock* B) { }
};

static const bool Initialized = false;
static const bool Uninitialized = true;

bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {

  if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
    if (VD->isBlockVarDecl()) {

      if (AD.Observer)
        AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD);

      // Pseudo-hack to prevent cascade of warnings.  If an accessed variable
      // is uninitialized, then we are already going to flag a warning for
      // this variable, which a "source" of uninitialized values.
      // We can otherwise do a full "taint" of uninitialized values.  The
      // client has both options by toggling AD.FullUninitTaint.

      if (AD.FullUninitTaint)
        return V(VD,AD);
    }

  return Initialized;
}

static VarDecl* FindBlockVarDecl(Expr* E) {

  // Blast through casts and parentheses to find any DeclRefExprs that
  // refer to a block VarDecl.

  if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
    if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
      if (VD->isBlockVarDecl()) return VD;

  return NULL;
}

bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {

  if (VarDecl* VD = FindBlockVarDecl(B->getLHS()))
    if (B->isAssignmentOp()) {
      if (B->getOpcode() == BinaryOperator::Assign)
        return V(VD,AD) = Visit(B->getRHS());
      else // Handle +=, -=, *=, etc.  We do want '&', not '&&'.
        return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS());
    }

  return VisitStmt(B);
}

bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
  for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
    VarDecl *VD = dyn_cast<VarDecl>(*I);
    if (VD && VD->isBlockVarDecl()) {
      if (Stmt* I = VD->getInit())
        V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized;
      else {
        // Special case for declarations of array types.  For things like:
        //
        //  char x[10];
        //
        // we should treat "x" as being initialized, because the variable
        // "x" really refers to the memory block.  Clearly x[1] is
        // uninitialized, but expressions like "(char *) x" really do refer to
        // an initialized value.  This simple dataflow analysis does not reason
        // about the contents of arrays, although it could be potentially
        // extended to do so if the array were of constant size.
        if (VD->getType()->isArrayType())
          V(VD,AD) = Initialized;
        else
          V(VD,AD) = Uninitialized;
      }
    }
  }
  return Uninitialized; // Value is never consumed.
}

bool TransferFuncs::VisitCallExpr(CallExpr* C) {
  VisitChildren(C);
  return Initialized;
}

bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
  switch (U->getOpcode()) {
    case UnaryOperator::AddrOf: {
      VarDecl* VD = FindBlockVarDecl(U->getSubExpr());
      if (VD && VD->isBlockVarDecl())
        return V(VD,AD) = Initialized;
      break;
    }

    default:
      break;
  }

  return Visit(U->getSubExpr());
}

bool
TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
  // This represents a use of the 'collection'
  bool x = Visit(S->getCollection());

  if (x == Uninitialized)
    return Uninitialized;

  // This represents an initialization of the 'element' value.
  Stmt* Element = S->getElement();
  VarDecl* VD = 0;

  if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
    VD = cast<VarDecl>(DS->getSolitaryDecl());
  else
    VD = cast<VarDecl>(cast<DeclRefExpr>(Element)->getDecl());

  V(VD,AD) = Initialized;
  return Initialized;
}

bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) {
  Visit(C->getCond());

  bool rhsResult = Visit(C->getRHS());
  // Handle the GNU extension for missing LHS.
  if (Expr *lhs = C->getLHS())
    return Visit(lhs) & rhsResult; // Yes: we want &, not &&.
  else
    return rhsResult;
}

bool TransferFuncs::VisitStmt(Stmt* S) {
  bool x = Initialized;

  // We don't stop at the first subexpression that is Uninitialized because
  // evaluating some subexpressions may result in propogating "Uninitialized"
  // or "Initialized" to variables referenced in the other subexpressions.
  for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
    if (*I && Visit(*I) == Uninitialized) x = Uninitialized;

  return x;
}

bool TransferFuncs::Visit(Stmt *S) {
  if (AD.isTracked(static_cast<Expr*>(S))) return V(static_cast<Expr*>(S),AD);
  else return static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(S);
}

bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
  bool x = static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E);
  if (AD.isTracked(E)) V(E,AD) = x;
  return x;
}

} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Merge operator.
//
//  In our transfer functions we take the approach that any
//  combination of uninitialized values, e.g.
//      Uninitialized + ___ = Uninitialized.
//
//  Merges take the same approach, preferring soundness.  At a confluence point,
//  if any predecessor has a variable marked uninitialized, the value is
//  uninitialized at the confluence point.
//===----------------------------------------------------------------------===//

namespace {
  typedef StmtDeclBitVector_Types::Union Merge;
  typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
}

//===----------------------------------------------------------------------===//
// Uninitialized values checker.   Scan an AST and flag variable uses
//===----------------------------------------------------------------------===//

UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}

namespace {
class VISIBILITY_HIDDEN UninitializedValuesChecker
  : public UninitializedValues::ObserverTy {

  ASTContext &Ctx;
  Diagnostic &Diags;
  llvm::SmallPtrSet<VarDecl*,10> AlreadyWarned;

public:
  UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
    : Ctx(ctx), Diags(diags) {}

  virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
                                  UninitializedValues::AnalysisDataTy& AD,
                                  DeclRefExpr* DR, VarDecl* VD) {

    assert ( AD.isTracked(VD) && "Unknown VarDecl.");

    if (V(VD,AD) == Uninitialized)
      if (AlreadyWarned.insert(VD))
        Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
                     diag::warn_uninit_val);
  }
};
} // end anonymous namespace

namespace clang {
void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags,
                              bool FullUninitTaint) {

  // Compute the uninitialized values information.
  UninitializedValues U(cfg);
  U.getAnalysisData().FullUninitTaint = FullUninitTaint;
  Solver S(U);
  S.runOnCFG(cfg);

  // Scan for DeclRefExprs that use uninitialized values.
  UninitializedValuesChecker Observer(Ctx,Diags);
  U.getAnalysisData().Observer = &Observer;
  S.runOnAllBlocks(cfg);
}
} // end namespace clang
<commit_msg>Flow-sensitive uninitialized values analysis: properly handle the 'element' expression of ObjCForCollectionStmt (can be anything).<commit_after>//==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Uninitialized Values analysis for source-level CFGs.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "llvm/Support/Compiler.h"

#include "llvm/ADT/SmallPtrSet.h"

using namespace clang;

//===----------------------------------------------------------------------===//
// Dataflow initialization logic.
//===----------------------------------------------------------------------===//

namespace {

class VISIBILITY_HIDDEN RegisterDecls
  : public CFGRecStmtDeclVisitor<RegisterDecls> {

  UninitializedValues::AnalysisDataTy& AD;
public:
  RegisterDecls(UninitializedValues::AnalysisDataTy& ad) :  AD(ad) {}

  void VisitVarDecl(VarDecl* VD) { AD.Register(VD); }
  CFG& getCFG() { return AD.getCFG(); }
};

} // end anonymous namespace

void UninitializedValues::InitializeValues(const CFG& cfg) {
  RegisterDecls R(getAnalysisData());
  cfg.VisitBlockStmts(R);
}

//===----------------------------------------------------------------------===//
// Transfer functions.
//===----------------------------------------------------------------------===//

namespace {
class VISIBILITY_HIDDEN TransferFuncs
  : public CFGStmtVisitor<TransferFuncs,bool> {

  UninitializedValues::ValTy V;
  UninitializedValues::AnalysisDataTy& AD;
public:
  TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}

  UninitializedValues::ValTy& getVal() { return V; }
  CFG& getCFG() { return AD.getCFG(); }

  void SetTopValue(UninitializedValues::ValTy& X) {
    X.setDeclValues(AD);
    X.resetBlkExprValues(AD);
  }

  bool VisitDeclRefExpr(DeclRefExpr* DR);
  bool VisitBinaryOperator(BinaryOperator* B);
  bool VisitUnaryOperator(UnaryOperator* U);
  bool VisitStmt(Stmt* S);
  bool VisitCallExpr(CallExpr* C);
  bool VisitDeclStmt(DeclStmt* D);
  bool VisitConditionalOperator(ConditionalOperator* C);
  bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);

  bool Visit(Stmt *S);
  bool BlockStmt_VisitExpr(Expr* E);

  void VisitTerminator(CFGBlock* B) { }
};

static const bool Initialized = false;
static const bool Uninitialized = true;

bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {

  if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
    if (VD->isBlockVarDecl()) {

      if (AD.Observer)
        AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD);

      // Pseudo-hack to prevent cascade of warnings.  If an accessed variable
      // is uninitialized, then we are already going to flag a warning for
      // this variable, which a "source" of uninitialized values.
      // We can otherwise do a full "taint" of uninitialized values.  The
      // client has both options by toggling AD.FullUninitTaint.

      if (AD.FullUninitTaint)
        return V(VD,AD);
    }

  return Initialized;
}

static VarDecl* FindBlockVarDecl(Expr* E) {

  // Blast through casts and parentheses to find any DeclRefExprs that
  // refer to a block VarDecl.

  if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
    if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
      if (VD->isBlockVarDecl()) return VD;

  return NULL;
}

bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {

  if (VarDecl* VD = FindBlockVarDecl(B->getLHS()))
    if (B->isAssignmentOp()) {
      if (B->getOpcode() == BinaryOperator::Assign)
        return V(VD,AD) = Visit(B->getRHS());
      else // Handle +=, -=, *=, etc.  We do want '&', not '&&'.
        return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS());
    }

  return VisitStmt(B);
}

bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
  for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
    VarDecl *VD = dyn_cast<VarDecl>(*I);
    if (VD && VD->isBlockVarDecl()) {
      if (Stmt* I = VD->getInit())
        V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized;
      else {
        // Special case for declarations of array types.  For things like:
        //
        //  char x[10];
        //
        // we should treat "x" as being initialized, because the variable
        // "x" really refers to the memory block.  Clearly x[1] is
        // uninitialized, but expressions like "(char *) x" really do refer to
        // an initialized value.  This simple dataflow analysis does not reason
        // about the contents of arrays, although it could be potentially
        // extended to do so if the array were of constant size.
        if (VD->getType()->isArrayType())
          V(VD,AD) = Initialized;
        else
          V(VD,AD) = Uninitialized;
      }
    }
  }
  return Uninitialized; // Value is never consumed.
}

bool TransferFuncs::VisitCallExpr(CallExpr* C) {
  VisitChildren(C);
  return Initialized;
}

bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
  switch (U->getOpcode()) {
    case UnaryOperator::AddrOf: {
      VarDecl* VD = FindBlockVarDecl(U->getSubExpr());
      if (VD && VD->isBlockVarDecl())
        return V(VD,AD) = Initialized;
      break;
    }

    default:
      break;
  }

  return Visit(U->getSubExpr());
}

bool
TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
  // This represents a use of the 'collection'
  bool x = Visit(S->getCollection());

  if (x == Uninitialized)
    return Uninitialized;

  // This represents an initialization of the 'element' value.
  Stmt* Element = S->getElement();
  VarDecl* VD = 0;

  if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
    VD = cast<VarDecl>(DS->getSolitaryDecl());
  else {
    Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens();

    // Initialize the value of the reference variable.
    if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(ElemExpr))
      VD = cast<VarDecl>(DR->getDecl());
    else
      return Visit(ElemExpr);
  }

  V(VD,AD) = Initialized;
  return Initialized;
}

bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) {
  Visit(C->getCond());

  bool rhsResult = Visit(C->getRHS());
  // Handle the GNU extension for missing LHS.
  if (Expr *lhs = C->getLHS())
    return Visit(lhs) & rhsResult; // Yes: we want &, not &&.
  else
    return rhsResult;
}

bool TransferFuncs::VisitStmt(Stmt* S) {
  bool x = Initialized;

  // We don't stop at the first subexpression that is Uninitialized because
  // evaluating some subexpressions may result in propogating "Uninitialized"
  // or "Initialized" to variables referenced in the other subexpressions.
  for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
    if (*I && Visit(*I) == Uninitialized) x = Uninitialized;

  return x;
}

bool TransferFuncs::Visit(Stmt *S) {
  if (AD.isTracked(static_cast<Expr*>(S))) return V(static_cast<Expr*>(S),AD);
  else return static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(S);
}

bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
  bool x = static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E);
  if (AD.isTracked(E)) V(E,AD) = x;
  return x;
}

} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Merge operator.
//
//  In our transfer functions we take the approach that any
//  combination of uninitialized values, e.g.
//      Uninitialized + ___ = Uninitialized.
//
//  Merges take the same approach, preferring soundness.  At a confluence point,
//  if any predecessor has a variable marked uninitialized, the value is
//  uninitialized at the confluence point.
//===----------------------------------------------------------------------===//

namespace {
  typedef StmtDeclBitVector_Types::Union Merge;
  typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
}

//===----------------------------------------------------------------------===//
// Uninitialized values checker.   Scan an AST and flag variable uses
//===----------------------------------------------------------------------===//

UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}

namespace {
class VISIBILITY_HIDDEN UninitializedValuesChecker
  : public UninitializedValues::ObserverTy {

  ASTContext &Ctx;
  Diagnostic &Diags;
  llvm::SmallPtrSet<VarDecl*,10> AlreadyWarned;

public:
  UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
    : Ctx(ctx), Diags(diags) {}

  virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
                                  UninitializedValues::AnalysisDataTy& AD,
                                  DeclRefExpr* DR, VarDecl* VD) {

    assert ( AD.isTracked(VD) && "Unknown VarDecl.");

    if (V(VD,AD) == Uninitialized)
      if (AlreadyWarned.insert(VD))
        Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
                     diag::warn_uninit_val);
  }
};
} // end anonymous namespace

namespace clang {
void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags,
                              bool FullUninitTaint) {

  // Compute the uninitialized values information.
  UninitializedValues U(cfg);
  U.getAnalysisData().FullUninitTaint = FullUninitTaint;
  Solver S(U);
  S.runOnCFG(cfg);

  // Scan for DeclRefExprs that use uninitialized values.
  UninitializedValuesChecker Observer(Ctx,Diags);
  U.getAnalysisData().Observer = &Observer;
  S.runOnAllBlocks(cfg);
}
} // end namespace clang
<|endoftext|>


<commit_before>#include "include/rados/librados.h"
#include "test/rados-api/test.h"

#include <errno.h>
#include <semaphore.h>
#include "gtest/gtest.h"

static sem_t sem;

static void watch_notify_test_cb(uint8_t opcode, uint64_t ver, void *arg)
{
  sem_post(&sem);
}

TEST(LibRadosWatchNotify, WatchNotifyTest) {
  ASSERT_EQ(0, sem_init(&sem, 0, 0));
  char buf[128];
  rados_t cluster;
  rados_ioctx_t ioctx;
  std::string pool_name = get_temp_pool_name();
  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
  memset(buf, 0xcc, sizeof(buf));
  ASSERT_EQ((int)sizeof(buf), rados_write(ioctx, "foo", buf, sizeof(buf), 0));
  uint64_t handle;
  ASSERT_EQ(0,
      rados_watch(ioctx, "foo", 0, &handle, watch_notify_test_cb, NULL));
  ASSERT_EQ(0, rados_notify(ioctx, "foo", 0, NULL, 0));
  TestAlarm alarm;
  sem_wait(&sem);
  rados_unwatch(ioctx, "foo", handle);
  rados_ioctx_destroy(ioctx);
  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
  sem_destroy(&sem);
}

<commit_msg>test/rados-api/watch_notify.cc: implement C++ ver<commit_after>#include "include/rados/librados.h"
#include "include/rados/librados.hpp"
#include "test/rados-api/test.h"

#include <errno.h>
#include <semaphore.h>
#include "gtest/gtest.h"

using namespace librados;

static sem_t sem;

static void watch_notify_test_cb(uint8_t opcode, uint64_t ver, void *arg)
{
  sem_post(&sem);
}

class WatchNotifyTestCtx : public WatchCtx
{
public:
    void notify(uint8_t opcode, uint64_t ver, bufferlist& bl)
    {
      sem_post(&sem);
    }
};

TEST(LibRadosWatchNotify, WatchNotifyTest) {
  ASSERT_EQ(0, sem_init(&sem, 0, 0));
  char buf[128];
  rados_t cluster;
  rados_ioctx_t ioctx;
  std::string pool_name = get_temp_pool_name();
  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
  memset(buf, 0xcc, sizeof(buf));
  ASSERT_EQ((int)sizeof(buf), rados_write(ioctx, "foo", buf, sizeof(buf), 0));
  uint64_t handle;
  ASSERT_EQ(0,
      rados_watch(ioctx, "foo", 0, &handle, watch_notify_test_cb, NULL));
  ASSERT_EQ(0, rados_notify(ioctx, "foo", 0, NULL, 0));
  TestAlarm alarm;
  sem_wait(&sem);
  rados_unwatch(ioctx, "foo", handle);
  rados_ioctx_destroy(ioctx);
  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
  sem_destroy(&sem);
}

TEST(LibRadosWatchNotify, WatchNotifyTestPP) {
  ASSERT_EQ(0, sem_init(&sem, 0, 0));
  Rados cluster;
  std::string pool_name = get_temp_pool_name();
  ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
  IoCtx ioctx;
  cluster.ioctx_create(pool_name.c_str(), ioctx);
  char buf[128];
  memset(buf, 0xcc, sizeof(buf));
  bufferlist bl1;
  bl1.append(buf, sizeof(buf));
  ASSERT_EQ((int)sizeof(buf), ioctx.write("foo", bl1, sizeof(buf), 0));
  uint64_t handle;
  WatchNotifyTestCtx ctx;
  ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
  bufferlist bl2;
  ASSERT_EQ(0, ioctx.notify("foo", 0, bl2));
  TestAlarm alarm;
  sem_wait(&sem);
  ioctx.unwatch("foo", handle);
  ioctx.close();
  ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
  sem_destroy(&sem);
}
<|endoftext|>


<commit_before>//===-- LiveIntervals.cpp - Live Interval Analysis ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveInterval analysis pass which is used
// by the Linear Scan Register allocator. This pass linearizes the
// basic blocks of the function in DFS order and uses the
// LiveVariables pass to conservatively compute live intervals for
// each virtual and physical register.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "liveintervals"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegInfo.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/DepthFirstIterator.h"
#include "Support/Statistic.h"
#include <iostream>

using namespace llvm;

namespace {
    RegisterAnalysis<LiveIntervals> X("liveintervals",
                                      "Live Interval Analysis");

    Statistic<> numIntervals("liveintervals", "Number of intervals");
};

void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const
{
    AU.setPreservesAll();
    AU.addRequired<LiveVariables>();
    AU.addRequiredID(PHIEliminationID);
    MachineFunctionPass::getAnalysisUsage(AU);
}

/// runOnMachineFunction - Register allocate the whole function
///
bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
    DEBUG(std::cerr << "Machine Function\n");
    mf_ = &fn;
    tm_ = &fn.getTarget();
    mri_ = tm_->getRegisterInfo();
    lv_ = &getAnalysis<LiveVariables>();
    allocatableRegisters_.clear();
    mbbi2mbbMap_.clear();
    mi2iMap_.clear();
    r2iMap_.clear();
    r2iMap_.clear();
    intervals_.clear();

    // mark allocatable registers
    allocatableRegisters_.resize(MRegisterInfo::FirstVirtualRegister);
    // Loop over all of the register classes...
    for (MRegisterInfo::regclass_iterator
             rci = mri_->regclass_begin(), rce = mri_->regclass_end();
         rci != rce; ++rci) {
        // Loop over all of the allocatable registers in the function...
        for (TargetRegisterClass::iterator
                 i = (*rci)->allocation_order_begin(*mf_),
                 e = (*rci)->allocation_order_end(*mf_); i != e; ++i) {
            allocatableRegisters_[*i] = true;  // The reg is allocatable!
        }
    }

    // number MachineInstrs
    unsigned miIndex = 0;
    for (MachineFunction::iterator mbb = mf_->begin(), mbbEnd = mf_->end();
         mbb != mbbEnd; ++mbb) {
        const std::pair<MachineBasicBlock*, unsigned>& entry =
            lv_->getMachineBasicBlockInfo(&*mbb);
        bool inserted = mbbi2mbbMap_.insert(std::make_pair(entry.second,
                                                           entry.first)).second;
        assert(inserted && "multiple index -> MachineBasicBlock");

        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            inserted = mi2iMap_.insert(std::make_pair(*mi, miIndex)).second;
            assert(inserted && "multiple MachineInstr -> index mappings");
            ++miIndex;
        }
    }

    computeIntervals();

    return true;
}

void LiveIntervals::printRegName(unsigned reg) const
{
    if (reg < MRegisterInfo::FirstVirtualRegister)
        std::cerr << mri_->getName(reg);
    else
        std::cerr << '%' << reg;
}

void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
                                             MachineBasicBlock::iterator mi,
                                             unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');

    unsigned instrIndex = getInstructionIndex(*mi);

    LiveVariables::VarInfo& vi = lv_->getVarInfo(reg);

    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    // handle multiple definition case (machine instructions violating
    // ssa after phi-elimination
    if (r2iit != r2iMap_.end()) {
        unsigned ii = r2iit->second;
        Interval& interval = intervals_[ii];
        unsigned end = getInstructionIndex(mbb->back()) + 1;
        DEBUG(std::cerr << "\t\t\t\tadding range: ["
              << instrIndex << ',' << end << "]\n");
        interval.addRange(instrIndex, end);
        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
    else {
        // add new interval
        intervals_.push_back(Interval(reg));
        Interval& interval = intervals_.back();
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;

        for (MbbIndex2MbbMap::iterator
                 it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
             it != itEnd; ++it) {
            unsigned liveBlockIndex = it->first;
            MachineBasicBlock* liveBlock = it->second;
            if (liveBlockIndex < vi.AliveBlocks.size() &&
                vi.AliveBlocks[liveBlockIndex]) {
                unsigned start =  getInstructionIndex(liveBlock->front());
                unsigned end = getInstructionIndex(liveBlock->back()) + 1;
                DEBUG(std::cerr << "\t\t\t\tadding range: ["
                      << start << ',' << end << "]\n");
                interval.addRange(start, end);
            }
        }

        bool killedInDefiningBasicBlock = false;
        for (int i = 0, e = vi.Kills.size(); i != e; ++i) {
            MachineBasicBlock* killerBlock = vi.Kills[i].first;
            MachineInstr* killerInstr = vi.Kills[i].second;
            killedInDefiningBasicBlock |= mbb == killerBlock;
            unsigned start = (mbb == killerBlock ?
                              instrIndex :
                              getInstructionIndex(killerBlock->front()));
            unsigned end = getInstructionIndex(killerInstr) + 1;
            DEBUG(std::cerr << "\t\t\t\tadding range: ["
                  << start << ',' << end << "]\n");
            interval.addRange(start, end);
        }

        if (!killedInDefiningBasicBlock) {
            unsigned end = getInstructionIndex(mbb->back()) + 1;
            interval.addRange(instrIndex, end);
        }

        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
}

void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock* mbb,
                                              MachineBasicBlock::iterator mi,
                                              unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');
    if (!lv_->getAllocatablePhysicalRegisters()[reg]) {
        DEBUG(std::cerr << "\t\t\t\tnon allocatable register: ignoring\n");
        return;
    }

    unsigned start = getInstructionIndex(*mi);
    unsigned end = start;

    for (MachineBasicBlock::iterator e = mbb->end(); mi != e; ++mi) {
        for (LiveVariables::killed_iterator
                 ki = lv_->dead_begin(*mi),
                 ke = lv_->dead_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }

        for (LiveVariables::killed_iterator
                 ki = lv_->killed_begin(*mi),
                 ke = lv_->killed_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }
    }
exit:
    assert(start < end && "did not find end of interval?");

    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    if (r2iit != r2iMap_.end()) {
        unsigned ii = r2iit->second;
        Interval& interval = intervals_[ii];
        DEBUG(std::cerr << "\t\t\t\tadding range: ["
              << start << ',' << end << "]\n");
        interval.addRange(start, end);
        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
    else {
        intervals_.push_back(Interval(reg));
        Interval& interval = intervals_.back();
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;
        DEBUG(std::cerr << "\t\t\t\tadding range: ["
              << start << ',' << end << "]\n");
        interval.addRange(start, end);
        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
}

void LiveIntervals::handleRegisterDef(MachineBasicBlock* mbb,
                                      MachineBasicBlock::iterator mi,
                                      unsigned reg)
{
    if (reg < MRegisterInfo::FirstVirtualRegister) {
        if (allocatableRegisters_[reg]) {
            handlePhysicalRegisterDef(mbb, mi, reg);
        }
    }
    else {
        handleVirtualRegisterDef(mbb, mi, reg);
    }
}

unsigned LiveIntervals::getInstructionIndex(MachineInstr* instr) const
{
    assert(mi2iMap_.find(instr) != mi2iMap_.end() &&
           "instruction not assigned a number");
    return mi2iMap_.find(instr)->second;
}

/// computeIntervals - computes the live intervals for virtual
/// registers. for some ordering of the machine instructions [1,N] a
/// live interval is an interval [i, j] where 1 <= i <= j <= N for
/// which a variable is live
void LiveIntervals::computeIntervals()
{
    DEBUG(std::cerr << "computing live intervals:\n");

    for (MbbIndex2MbbMap::iterator
             it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
         it != itEnd; ++it) {
        MachineBasicBlock* mbb = it->second;
        DEBUG(std::cerr << "machine basic block: "
              << mbb->getBasicBlock()->getName() << "\n");
        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            MachineInstr* instr = *mi;
            const TargetInstrDescriptor& tid =
                tm_->getInstrInfo().get(instr->getOpcode());
            DEBUG(std::cerr << "\t\tinstruction["
                  << getInstructionIndex(instr) << "]: ";
                  instr->print(std::cerr, *tm_););

            // handle implicit defs
            for (const unsigned* id = tid.ImplicitDefs; *id; ++id) {
                unsigned physReg = *id;
                handlePhysicalRegisterDef(mbb, mi, physReg);
            }

            // handle explicit defs
            for (int i = instr->getNumOperands() - 1; i >= 0; --i) {
                MachineOperand& mop = instr->getOperand(i);

                if (!mop.isRegister())
                    continue;

                if (mop.isDef()) {
                    unsigned reg = mop.getAllocatedRegNum();
                    if (reg < MRegisterInfo::FirstVirtualRegister)
                        handlePhysicalRegisterDef(mbb, mi, reg);
                    else
                        handleVirtualRegisterDef(mbb, mi, reg);
                }
            }
        }
    }

    std::sort(intervals_.begin(), intervals_.end(), StartPointComp());
    DEBUG(std::copy(intervals_.begin(), intervals_.end(),
                    std::ostream_iterator<Interval>(std::cerr, "\n")));
}

std::ostream& llvm::operator<<(std::ostream& os,
                               const LiveIntervals::Interval& li)
{
    os << "%reg" << li.reg << " = ";
    for (LiveIntervals::Interval::Ranges::const_iterator
             i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) {
        os << "[" << i->first << "," << i->second << "]";
    }
    return os;
}
<commit_msg>Change preserve all claim to just preserve live variables and phielimination.<commit_after>//===-- LiveIntervals.cpp - Live Interval Analysis ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveInterval analysis pass which is used
// by the Linear Scan Register allocator. This pass linearizes the
// basic blocks of the function in DFS order and uses the
// LiveVariables pass to conservatively compute live intervals for
// each virtual and physical register.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "liveintervals"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegInfo.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/DepthFirstIterator.h"
#include "Support/Statistic.h"
#include <iostream>

using namespace llvm;

namespace {
    RegisterAnalysis<LiveIntervals> X("liveintervals",
                                      "Live Interval Analysis");

    Statistic<> numIntervals("liveintervals", "Number of intervals");
};

void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const
{
    AU.addPreserved<LiveVariables>();
    AU.addRequired<LiveVariables>();
    AU.addPreservedID(PHIEliminationID);
    AU.addRequiredID(PHIEliminationID);
    MachineFunctionPass::getAnalysisUsage(AU);
}

/// runOnMachineFunction - Register allocate the whole function
///
bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
    DEBUG(std::cerr << "Machine Function\n");
    mf_ = &fn;
    tm_ = &fn.getTarget();
    mri_ = tm_->getRegisterInfo();
    lv_ = &getAnalysis<LiveVariables>();
    allocatableRegisters_.clear();
    mbbi2mbbMap_.clear();
    mi2iMap_.clear();
    r2iMap_.clear();
    r2iMap_.clear();
    intervals_.clear();

    // mark allocatable registers
    allocatableRegisters_.resize(MRegisterInfo::FirstVirtualRegister);
    // Loop over all of the register classes...
    for (MRegisterInfo::regclass_iterator
             rci = mri_->regclass_begin(), rce = mri_->regclass_end();
         rci != rce; ++rci) {
        // Loop over all of the allocatable registers in the function...
        for (TargetRegisterClass::iterator
                 i = (*rci)->allocation_order_begin(*mf_),
                 e = (*rci)->allocation_order_end(*mf_); i != e; ++i) {
            allocatableRegisters_[*i] = true;  // The reg is allocatable!
        }
    }

    // number MachineInstrs
    unsigned miIndex = 0;
    for (MachineFunction::iterator mbb = mf_->begin(), mbbEnd = mf_->end();
         mbb != mbbEnd; ++mbb) {
        const std::pair<MachineBasicBlock*, unsigned>& entry =
            lv_->getMachineBasicBlockInfo(&*mbb);
        bool inserted = mbbi2mbbMap_.insert(std::make_pair(entry.second,
                                                           entry.first)).second;
        assert(inserted && "multiple index -> MachineBasicBlock");

        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            inserted = mi2iMap_.insert(std::make_pair(*mi, miIndex)).second;
            assert(inserted && "multiple MachineInstr -> index mappings");
            ++miIndex;
        }
    }

    computeIntervals();

    return true;
}

void LiveIntervals::printRegName(unsigned reg) const
{
    if (reg < MRegisterInfo::FirstVirtualRegister)
        std::cerr << mri_->getName(reg);
    else
        std::cerr << '%' << reg;
}

void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
                                             MachineBasicBlock::iterator mi,
                                             unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');

    unsigned instrIndex = getInstructionIndex(*mi);

    LiveVariables::VarInfo& vi = lv_->getVarInfo(reg);

    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    // handle multiple definition case (machine instructions violating
    // ssa after phi-elimination
    if (r2iit != r2iMap_.end()) {
        unsigned ii = r2iit->second;
        Interval& interval = intervals_[ii];
        unsigned end = getInstructionIndex(mbb->back()) + 1;
        DEBUG(std::cerr << "\t\t\t\tadding range: ["
              << instrIndex << ',' << end << "]\n");
        interval.addRange(instrIndex, end);
        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
    else {
        // add new interval
        intervals_.push_back(Interval(reg));
        Interval& interval = intervals_.back();
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;

        for (MbbIndex2MbbMap::iterator
                 it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
             it != itEnd; ++it) {
            unsigned liveBlockIndex = it->first;
            MachineBasicBlock* liveBlock = it->second;
            if (liveBlockIndex < vi.AliveBlocks.size() &&
                vi.AliveBlocks[liveBlockIndex]) {
                unsigned start =  getInstructionIndex(liveBlock->front());
                unsigned end = getInstructionIndex(liveBlock->back()) + 1;
                DEBUG(std::cerr << "\t\t\t\tadding range: ["
                      << start << ',' << end << "]\n");
                interval.addRange(start, end);
            }
        }

        bool killedInDefiningBasicBlock = false;
        for (int i = 0, e = vi.Kills.size(); i != e; ++i) {
            MachineBasicBlock* killerBlock = vi.Kills[i].first;
            MachineInstr* killerInstr = vi.Kills[i].second;
            killedInDefiningBasicBlock |= mbb == killerBlock;
            unsigned start = (mbb == killerBlock ?
                              instrIndex :
                              getInstructionIndex(killerBlock->front()));
            unsigned end = getInstructionIndex(killerInstr) + 1;
            DEBUG(std::cerr << "\t\t\t\tadding range: ["
                  << start << ',' << end << "]\n");
            interval.addRange(start, end);
        }

        if (!killedInDefiningBasicBlock) {
            unsigned end = getInstructionIndex(mbb->back()) + 1;
            interval.addRange(instrIndex, end);
        }

        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
}

void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock* mbb,
                                              MachineBasicBlock::iterator mi,
                                              unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');
    if (!lv_->getAllocatablePhysicalRegisters()[reg]) {
        DEBUG(std::cerr << "\t\t\t\tnon allocatable register: ignoring\n");
        return;
    }

    unsigned start = getInstructionIndex(*mi);
    unsigned end = start;

    for (MachineBasicBlock::iterator e = mbb->end(); mi != e; ++mi) {
        for (LiveVariables::killed_iterator
                 ki = lv_->dead_begin(*mi),
                 ke = lv_->dead_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }

        for (LiveVariables::killed_iterator
                 ki = lv_->killed_begin(*mi),
                 ke = lv_->killed_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }
    }
exit:
    assert(start < end && "did not find end of interval?");

    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    if (r2iit != r2iMap_.end()) {
        unsigned ii = r2iit->second;
        Interval& interval = intervals_[ii];
        DEBUG(std::cerr << "\t\t\t\tadding range: ["
              << start << ',' << end << "]\n");
        interval.addRange(start, end);
        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
    else {
        intervals_.push_back(Interval(reg));
        Interval& interval = intervals_.back();
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;
        DEBUG(std::cerr << "\t\t\t\tadding range: ["
              << start << ',' << end << "]\n");
        interval.addRange(start, end);
        DEBUG(std::cerr << "\t\t\t\t" << interval << '\n');
    }
}

void LiveIntervals::handleRegisterDef(MachineBasicBlock* mbb,
                                      MachineBasicBlock::iterator mi,
                                      unsigned reg)
{
    if (reg < MRegisterInfo::FirstVirtualRegister) {
        if (allocatableRegisters_[reg]) {
            handlePhysicalRegisterDef(mbb, mi, reg);
        }
    }
    else {
        handleVirtualRegisterDef(mbb, mi, reg);
    }
}

unsigned LiveIntervals::getInstructionIndex(MachineInstr* instr) const
{
    assert(mi2iMap_.find(instr) != mi2iMap_.end() &&
           "instruction not assigned a number");
    return mi2iMap_.find(instr)->second;
}

/// computeIntervals - computes the live intervals for virtual
/// registers. for some ordering of the machine instructions [1,N] a
/// live interval is an interval [i, j] where 1 <= i <= j <= N for
/// which a variable is live
void LiveIntervals::computeIntervals()
{
    DEBUG(std::cerr << "computing live intervals:\n");

    for (MbbIndex2MbbMap::iterator
             it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
         it != itEnd; ++it) {
        MachineBasicBlock* mbb = it->second;
        DEBUG(std::cerr << "machine basic block: "
              << mbb->getBasicBlock()->getName() << "\n");
        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            MachineInstr* instr = *mi;
            const TargetInstrDescriptor& tid =
                tm_->getInstrInfo().get(instr->getOpcode());
            DEBUG(std::cerr << "\t\tinstruction["
                  << getInstructionIndex(instr) << "]: ";
                  instr->print(std::cerr, *tm_););

            // handle implicit defs
            for (const unsigned* id = tid.ImplicitDefs; *id; ++id) {
                unsigned physReg = *id;
                handlePhysicalRegisterDef(mbb, mi, physReg);
            }

            // handle explicit defs
            for (int i = instr->getNumOperands() - 1; i >= 0; --i) {
                MachineOperand& mop = instr->getOperand(i);

                if (!mop.isRegister())
                    continue;

                if (mop.isDef()) {
                    unsigned reg = mop.getAllocatedRegNum();
                    if (reg < MRegisterInfo::FirstVirtualRegister)
                        handlePhysicalRegisterDef(mbb, mi, reg);
                    else
                        handleVirtualRegisterDef(mbb, mi, reg);
                }
            }
        }
    }

    std::sort(intervals_.begin(), intervals_.end(), StartPointComp());
    DEBUG(std::copy(intervals_.begin(), intervals_.end(),
                    std::ostream_iterator<Interval>(std::cerr, "\n")));
}

std::ostream& llvm::operator<<(std::ostream& os,
                               const LiveIntervals::Interval& li)
{
    os << "%reg" << li.reg << " = ";
    for (LiveIntervals::Interval::Ranges::const_iterator
             i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) {
        os << "[" << i->first << "," << i->second << "]";
    }
    return os;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h" // for operator new[](unsigned long, ASTCtx..)
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

namespace {
  static const char annoTag[] = "$clingAutoload$";
  static const size_t lenAnnoTag = sizeof(annoTag) - 1;
}

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l, llvm::StringRef name,
                                llvm::StringRef header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    if (header.startswith(llvm::StringRef(annoTag, lenAnnoTag)))
      sema.Diags.Report(l, id) << name << header.drop_front(lenAnnoTag);

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (m_ShowSuggestions && t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }

  class AutoloadingVisitor: public RecursiveASTVisitor<AutoloadingVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
    clang::FileEntry* m_PrevFE;
    std::string m_PrevFileName;
  private:
    void InsertIntoAutoloadingState (Decl* decl, llvm::StringRef annotation) {

      assert(!annotation.empty() && "Empty annotation!");
      if (!annotation.startswith(llvm::StringRef(annoTag, lenAnnoTag))) {
        // not an autoload annotation.
        return;
      }

      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;
      if (m_PrevFE && m_PrevFileName == annotation.drop_front(lenAnnoTag))
        FE = m_PrevFE;
      else
        FE = m_PP->LookupFile(fileNameLoc,
                              annotation.drop_front(lenAnnoTag), isAngled,
                              LookupFrom, CurDir, /*SearchPath*/0,
                              /*RelativePath*/ 0, /*suggestedModule*/0,
                              /*SkipCache*/false, /*OpenFile*/ false,
                              /*CacheFail*/ false);

      assert(FE && "Must have a valid FileEntry");

      auto& Vec = (*m_Map)[FE];
      Vec.push_back(decl);
    }

  public:
    AutoloadingVisitor():
      m_IsStoringState(false), m_Map(0), m_PP(0), m_PrevFE(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
          EnumDecl* ED = cast<EnumDecl>(D);
          if (ED->isFixed()) {
            StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
            char ch = str.back();
//            str.drop_back(2);
            ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
            struct EnumDeclDerived: public EnumDecl {
              static void setFixed(EnumDecl* ED, bool value = true) {
                ((EnumDeclDerived*)ED)->IsFixed = value;
              }
            };

            if (ch != '1')
              EnumDeclDerived::setFixed(ED, false);
          }
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    // If File is 0 this means that the #included file doesn't exist.
    if (!File)
      return;

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    AutoloadingVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        AutoloadingVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                    defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
                }
              }
            }

        }
      }
  }

} //end namespace cling
<commit_msg>Set FE cache, invalid (=null) FE is a reasonable cached value, too.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h" // for operator new[](unsigned long, ASTCtx..)
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

namespace {
  static const char annoTag[] = "$clingAutoload$";
  static const size_t lenAnnoTag = sizeof(annoTag) - 1;
}

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l, llvm::StringRef name,
                                llvm::StringRef header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    if (header.startswith(llvm::StringRef(annoTag, lenAnnoTag)))
      sema.Diags.Report(l, id) << name << header.drop_front(lenAnnoTag);

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (m_ShowSuggestions && t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }

  class AutoloadingVisitor: public RecursiveASTVisitor<AutoloadingVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
    const clang::FileEntry* m_PrevFE;
    std::string m_PrevFileName;
  private:
    void InsertIntoAutoloadingState (Decl* decl, llvm::StringRef annotation) {

      assert(!annotation.empty() && "Empty annotation!");
      if (!annotation.startswith(llvm::StringRef(annoTag, lenAnnoTag))) {
        // not an autoload annotation.
        return;
      }

      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;
      llvm::StringRef FileName = annotation.drop_front(lenAnnoTag);
      if (FileName.equals(m_PrevFileName))
        FE = m_PrevFE;
      else {
        FE = m_PP->LookupFile(fileNameLoc, FileName, isAngled,
                              LookupFrom, CurDir, /*SearchPath*/0,
                              /*RelativePath*/ 0, /*suggestedModule*/0,
                              /*SkipCache*/false, /*OpenFile*/ false,
                              /*CacheFail*/ false);
        m_PrevFE = FE;
        m_PrevFileName = FileName;
      }

      assert(FE && "Must have a valid FileEntry");
      if (FE) {
        auto& Vec = (*m_Map)[FE];
        Vec.push_back(decl);
      }
    }

  public:
    AutoloadingVisitor():
      m_IsStoringState(false), m_Map(0), m_PP(0), m_PrevFE(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
          EnumDecl* ED = cast<EnumDecl>(D);
          if (ED->isFixed()) {
            StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
            char ch = str.back();
//            str.drop_back(2);
            ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
            struct EnumDeclDerived: public EnumDecl {
              static void setFixed(EnumDecl* ED, bool value = true) {
                ((EnumDeclDerived*)ED)->IsFixed = value;
              }
            };

            if (ch != '1')
              EnumDeclDerived::setFixed(ED, false);
          }
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    // If File is 0 this means that the #included file doesn't exist.
    if (!File)
      return;

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    AutoloadingVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        AutoloadingVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                    defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
                }
              }
            }

        }
      }
  }

} //end namespace cling
<|endoftext|>