Remove upstream files and directories from vendor/clang/dist that we do

not use.  This saves on repository space, and reduces the number of tree
conflicts when merging.
This commit is contained in:
Dimitry Andric 2019-08-20 17:59:23 +00:00
parent 676fbe8105
commit 9a83721404
15173 changed files with 0 additions and 1466591 deletions

View File

@ -1,4 +0,0 @@
{
"repository.callsign" : "C",
"conduit_uri" : "https://reviews.llvm.org/"
}

View File

@ -1 +0,0 @@
BasedOnStyle: LLVM

View File

@ -1,17 +0,0 @@
Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming'
CheckOptions:
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.EnumCase
value: CamelCase
- key: readability-identifier-naming.FunctionCase
value: camelBack
- key: readability-identifier-naming.MemberCase
value: CamelCase
- key: readability-identifier-naming.ParameterCase
value: CamelCase
- key: readability-identifier-naming.UnionCase
value: CamelCase
- key: readability-identifier-naming.VariableCase
value: CamelCase

43
.gitignore vendored
View File

@ -1,43 +0,0 @@
#==============================================================================#
# This file specifies intentionally untracked files that git should ignore.
# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
#
# This file is intentionally different from the output of `git svn show-ignore`,
# as most of those are useless.
#==============================================================================#
#==============================================================================#
# File extensions to be ignored anywhere in the tree.
#==============================================================================#
# Temp files created by most text editors.
*~
# Merge files created by git.
*.orig
# Byte compiled python modules.
*.pyc
# vim swap files
.*.sw?
.sw?
#==============================================================================#
# Explicit files to ignore (only matches one).
#==============================================================================#
cscope.files
cscope.out
/tags
#==============================================================================#
# Directories to ignore (do not add trailing '/'s, they skip symlinks).
#==============================================================================#
# Clang extra user tools, which is tracked independently (clang-tools-extra).
tools/extra
# Sphinx build products
docs/_build
docs/analyzer/_build
# debug info testsuite
test/debuginfo-tests
# VS2017 and VSCode config files.
.vscode
.vs

View File

@ -1,816 +0,0 @@
cmake_minimum_required(VERSION 3.4.3)
if(POLICY CMP0075)
cmake_policy(SET CMP0075 NEW)
endif()
# If we are not building as a part of LLVM, build Clang as an
# standalone project, using LLVM as an external library:
if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
project(Clang)
# Rely on llvm-config.
set(CONFIG_OUTPUT)
if(LLVM_CONFIG)
set (LLVM_CONFIG_FOUND 1)
message(STATUS "Found LLVM_CONFIG as ${LLVM_CONFIG}")
message(DEPRECATION "Using llvm-config to detect the LLVM installation is \
deprecated. The installed cmake files should be used \
instead. CMake should be able to detect your LLVM install \
automatically, but you can also use LLVM_DIR to specify \
the path containing LLVMConfig.cmake.")
set(CONFIG_COMMAND ${LLVM_CONFIG}
"--assertion-mode"
"--bindir"
"--libdir"
"--includedir"
"--prefix"
"--src-root"
"--cmakedir")
execute_process(
COMMAND ${CONFIG_COMMAND}
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE CONFIG_OUTPUT
)
if(NOT HAD_ERROR)
string(REGEX REPLACE
"[ \t]*[\r\n]+[ \t]*" ";"
CONFIG_OUTPUT ${CONFIG_OUTPUT})
else()
string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}")
message(STATUS "${CONFIG_COMMAND_STR}")
message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
endif()
list(GET CONFIG_OUTPUT 0 ENABLE_ASSERTIONS)
list(GET CONFIG_OUTPUT 1 TOOLS_BINARY_DIR)
list(GET CONFIG_OUTPUT 2 LIBRARY_DIR)
list(GET CONFIG_OUTPUT 3 INCLUDE_DIR)
list(GET CONFIG_OUTPUT 4 LLVM_OBJ_ROOT)
list(GET CONFIG_OUTPUT 5 MAIN_SRC_DIR)
list(GET CONFIG_OUTPUT 6 LLVM_CONFIG_CMAKE_PATH)
# Normalize LLVM_CMAKE_PATH. --cmakedir might contain backslashes.
# CMake assumes slashes as PATH.
file(TO_CMAKE_PATH ${LLVM_CONFIG_CMAKE_PATH} LLVM_CMAKE_PATH)
endif()
if(NOT MSVC_IDE)
set(LLVM_ENABLE_ASSERTIONS ${ENABLE_ASSERTIONS}
CACHE BOOL "Enable assertions")
# Assertions should follow llvm-config's.
mark_as_advanced(LLVM_ENABLE_ASSERTIONS)
endif()
find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_PATH}")
list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR})
# We can't check LLVM_CONFIG here, because find_package(LLVM ...) also sets
# LLVM_CONFIG.
if (NOT LLVM_CONFIG_FOUND)
# Pull values from LLVMConfig.cmake. We can drop this once the llvm-config
# path is removed.
set(TOOLS_BINARY_DIR ${LLVM_TOOLS_BINARY_DIR})
set(LIBRARY_DIR ${LLVM_LIBRARY_DIR})
set(INCLUDE_DIR ${LLVM_INCLUDE_DIR})
set(LLVM_OBJ_DIR ${LLVM_BINARY_DIR})
endif()
set(LLVM_TOOLS_BINARY_DIR ${TOOLS_BINARY_DIR} CACHE PATH "Path to llvm/bin")
set(LLVM_LIBRARY_DIR ${LIBRARY_DIR} CACHE PATH "Path to llvm/lib")
set(LLVM_MAIN_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include")
set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree")
set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR}
NO_DEFAULT_PATH)
# They are used as destination of target generators.
set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
if(WIN32 OR CYGWIN)
# DLL platform -- put DLLs into bin.
set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
else()
set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
endif()
option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON)
option(LLVM_INSTALL_TOOLCHAIN_ONLY
"Only include toolchain files in the 'install' target." OFF)
option(LLVM_FORCE_USE_OLD_HOST_TOOLCHAIN
"Set to ON to force using an old, unsupported host toolchain." OFF)
option(CLANG_ENABLE_BOOTSTRAP "Generate the clang bootstrap target" OFF)
option(LLVM_ENABLE_LIBXML2 "Use libxml2 if available." ON)
include(AddLLVM)
include(TableGen)
include(HandleLLVMOptions)
include(VersionFromVCS)
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
if (NOT DEFINED LLVM_INCLUDE_TESTS)
set(LLVM_INCLUDE_TESTS ON)
endif()
include_directories("${LLVM_BINARY_DIR}/include" "${LLVM_MAIN_INCLUDE_DIR}")
link_directories("${LLVM_LIBRARY_DIR}")
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} )
if(LLVM_INCLUDE_TESTS)
set(Python_ADDITIONAL_VERSIONS 2.7)
include(FindPythonInterp)
if(NOT PYTHONINTERP_FOUND)
message(FATAL_ERROR
"Unable to find Python interpreter, required for builds and testing.
Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
endif()
if( ${PYTHON_VERSION_STRING} VERSION_LESS 2.7 )
message(FATAL_ERROR "Python 2.7 or newer is required")
endif()
# Check prebuilt llvm/utils.
if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/count${CMAKE_EXECUTABLE_SUFFIX}
AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX})
set(LLVM_UTILS_PROVIDED ON)
endif()
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
# Note: path not really used, except for checking if lit was found
set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit utils/llvm-lit)
endif()
if(NOT LLVM_UTILS_PROVIDED)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/count utils/count)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not)
set(LLVM_UTILS_PROVIDED ON)
set(CLANG_TEST_DEPS FileCheck count not)
endif()
set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest)
if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h
AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt)
add_subdirectory(${UNITTEST_DIR} utils/unittest)
endif()
else()
# Seek installed Lit.
find_program(LLVM_LIT
NAMES llvm-lit lit.py lit
PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit"
DOC "Path to lit.py")
endif()
if(LLVM_LIT)
# Define the default arguments to use with 'lit', and an option for the user
# to override.
set(LIT_ARGS_DEFAULT "-sv")
if (MSVC OR XCODE)
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
endif()
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
# On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
if( WIN32 AND NOT CYGWIN )
set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
endif()
else()
set(LLVM_INCLUDE_TESTS OFF)
endif()
endif()
set( CLANG_BUILT_STANDALONE 1 )
set(BACKEND_PACKAGE_STRING "LLVM ${LLVM_PACKAGE_VERSION}")
else()
set(BACKEND_PACKAGE_STRING "${PACKAGE_STRING}")
endif()
# Make sure that our source directory is on the current cmake module path so that
# we can include cmake files from this directory.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
if(LLVM_ENABLE_LIBXML2)
# Don't look for libxml if we're using MSan, since uninstrumented third party
# code may call MSan interceptors like strlen, leading to false positives.
if(NOT LLVM_USE_SANITIZER MATCHES "Memory.*")
set (LIBXML2_FOUND 0)
find_package(LibXml2 2.5.3 QUIET)
if (LIBXML2_FOUND)
set(CLANG_HAVE_LIBXML 1)
endif()
endif()
endif()
include(CheckIncludeFile)
check_include_file(sys/resource.h CLANG_HAVE_RLIMITS)
set(CLANG_RESOURCE_DIR "" CACHE STRING
"Relative directory from the Clang binary to its resource files.")
set(C_INCLUDE_DIRS "" CACHE STRING
"Colon separated list of directories clang will search for headers.")
set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." )
set(DEFAULT_SYSROOT "" CACHE PATH
"Default <path> to all compiler invocations for --sysroot=<path>." )
set(ENABLE_LINKER_BUILD_ID OFF CACHE BOOL "pass --build-id to ld")
set(ENABLE_X86_RELAX_RELOCATIONS OFF CACHE BOOL
"enable x86 relax relocations by default")
set(ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER FALSE CACHE BOOL
"Enable the experimental new pass manager by default.")
# TODO: verify the values against LangStandards.def?
set(CLANG_DEFAULT_STD_C "" CACHE STRING
"Default standard to use for C/ObjC code (IDENT from LangStandards.def, empty for platform default)")
set(CLANG_DEFAULT_STD_CXX "" CACHE STRING
"Default standard to use for C++/ObjC++ code (IDENT from LangStandards.def, empty for platform default)")
set(CLANG_DEFAULT_LINKER "" CACHE STRING
"Default linker to use (linker name or absolute path, empty for platform default)")
set(CLANG_DEFAULT_CXX_STDLIB "" CACHE STRING
"Default C++ stdlib to use (\"libstdc++\" or \"libc++\", empty for platform default")
if (NOT(CLANG_DEFAULT_CXX_STDLIB STREQUAL "" OR
CLANG_DEFAULT_CXX_STDLIB STREQUAL "libstdc++" OR
CLANG_DEFAULT_CXX_STDLIB STREQUAL "libc++"))
message(WARNING "Resetting default C++ stdlib to use platform default")
set(CLANG_DEFAULT_CXX_STDLIB "" CACHE STRING
"Default C++ stdlib to use (\"libstdc++\" or \"libc++\", empty for platform default" FORCE)
endif()
set(CLANG_DEFAULT_RTLIB "" CACHE STRING
"Default runtime library to use (\"libgcc\" or \"compiler-rt\", empty for platform default)")
if (NOT(CLANG_DEFAULT_RTLIB STREQUAL "" OR
CLANG_DEFAULT_RTLIB STREQUAL "libgcc" OR
CLANG_DEFAULT_RTLIB STREQUAL "compiler-rt"))
message(WARNING "Resetting default rtlib to use platform default")
set(CLANG_DEFAULT_RTLIB "" CACHE STRING
"Default runtime library to use (\"libgcc\" or \"compiler-rt\", empty for platform default)" FORCE)
endif()
set(CLANG_DEFAULT_OBJCOPY "objcopy" CACHE STRING
"Default objcopy executable to use.")
set(CLANG_DEFAULT_OPENMP_RUNTIME "libomp" CACHE STRING
"Default OpenMP runtime used by -fopenmp.")
# OpenMP offloading requires at least sm_35 because we use shuffle instructions
# to generate efficient code for reductions and the atomicMax instruction on
# 64-bit integers in the implementation of conditional lastprivate.
set(CLANG_OPENMP_NVPTX_DEFAULT_ARCH "sm_35" CACHE STRING
"Default architecture for OpenMP offloading to Nvidia GPUs.")
string(REGEX MATCH "^sm_([0-9]+)$" MATCHED_ARCH "${CLANG_OPENMP_NVPTX_DEFAULT_ARCH}")
if (NOT DEFINED MATCHED_ARCH OR "${CMAKE_MATCH_1}" LESS 35)
message(WARNING "Resetting default architecture for OpenMP offloading to Nvidia GPUs to sm_35")
set(CLANG_OPENMP_NVPTX_DEFAULT_ARCH "sm_35" CACHE STRING
"Default architecture for OpenMP offloading to Nvidia GPUs." FORCE)
endif()
set(CLANG_VENDOR ${PACKAGE_VENDOR} CACHE STRING
"Vendor-specific text for showing with version information.")
if( CLANG_VENDOR )
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
endif()
set(CLANG_REPOSITORY_STRING "" CACHE STRING
"Vendor-specific text for showing the repository the source is taken from.")
if(CLANG_REPOSITORY_STRING)
add_definitions(-DCLANG_REPOSITORY_STRING="${CLANG_REPOSITORY_STRING}")
endif()
set(CLANG_VENDOR_UTI "org.llvm.clang" CACHE STRING
"Vendor-specific uti.")
set(CLANG_PYTHON_BINDINGS_VERSIONS "" CACHE STRING
"Python versions to install libclang python bindings for")
# The libdir suffix must exactly match whatever LLVM's configuration used.
set(CLANG_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}")
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
if( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE )
message(FATAL_ERROR "In-source builds are not allowed. "
"Please create a directory and run cmake "
"from there, passing the path to this source directory as the last argument. "
"This process created the file `CMakeCache.txt' and the directory "
"`CMakeFiles'. Please delete them.")
endif()
# If CLANG_VERSION_* is specified, use it, if not use LLVM_VERSION_*.
if(NOT DEFINED CLANG_VERSION_MAJOR)
set(CLANG_VERSION_MAJOR ${LLVM_VERSION_MAJOR})
endif()
if(NOT DEFINED CLANG_VERSION_MINOR)
set(CLANG_VERSION_MINOR ${LLVM_VERSION_MINOR})
endif()
if(NOT DEFINED CLANG_VERSION_PATCHLEVEL)
set(CLANG_VERSION_PATCHLEVEL ${LLVM_VERSION_PATCH})
endif()
# Unlike PACKAGE_VERSION, CLANG_VERSION does not include LLVM_VERSION_SUFFIX.
set(CLANG_VERSION "${CLANG_VERSION_MAJOR}.${CLANG_VERSION_MINOR}.${CLANG_VERSION_PATCHLEVEL}")
message(STATUS "Clang version: ${CLANG_VERSION}")
# Configure the Version.inc file.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/include/clang/Basic/Version.inc.in
${CMAKE_CURRENT_BINARY_DIR}/include/clang/Basic/Version.inc)
# Add appropriate flags for GCC
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual")
if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
endif ()
# Enable -pedantic for Clang even if it's not enabled for LLVM.
if (NOT LLVM_ENABLE_PEDANTIC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wno-long-long")
endif ()
check_cxx_compiler_flag("-Werror -Wnested-anon-types" CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG)
if( CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" )
endif()
endif ()
# Determine HOST_LINK_VERSION on Darwin.
set(HOST_LINK_VERSION)
if (APPLE)
set(LD_V_OUTPUT)
execute_process(
COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1"
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE LD_V_OUTPUT
)
if (NOT HAD_ERROR)
if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*")
string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT})
elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*")
string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT})
endif()
else()
message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}")
endif()
endif()
include(CMakeParseArguments)
include(AddClang)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(BEFORE
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/include
)
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
install(DIRECTORY include/clang include/clang-c
DESTINATION include
FILES_MATCHING
PATTERN "*.def"
PATTERN "*.h"
PATTERN "config.h" EXCLUDE
PATTERN ".svn" EXCLUDE
)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/clang
DESTINATION include
FILES_MATCHING
PATTERN "CMakeFiles" EXCLUDE
PATTERN "*.inc"
PATTERN "*.h"
)
install(PROGRAMS utils/bash-autocomplete.sh
DESTINATION share/clang
)
endif()
add_definitions( -D_GNU_SOURCE )
option(CLANG_BUILD_TOOLS
"Build the Clang tools. If OFF, just generate build targets." ON)
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
set(CLANG_ANALYZER_Z3_INSTALL_DIR "" CACHE STRING "Install directory of the Z3 solver.")
find_package(Z3 4.7.1)
if (CLANG_ANALYZER_Z3_INSTALL_DIR)
if (NOT Z3_FOUND)
message(FATAL_ERROR "Z3 4.7.1 has not been found in CLANG_ANALYZER_Z3_INSTALL_DIR: ${CLANG_ANALYZER_Z3_INSTALL_DIR}.")
endif()
endif()
set(CLANG_ANALYZER_ENABLE_Z3_SOLVER_DEFAULT "${Z3_FOUND}")
option(CLANG_ANALYZER_ENABLE_Z3_SOLVER
"Enable Support for the Z3 constraint solver in the Clang Static Analyzer."
${CLANG_ANALYZER_ENABLE_Z3_SOLVER_DEFAULT}
)
if (CLANG_ANALYZER_ENABLE_Z3_SOLVER)
if (NOT Z3_FOUND)
message(FATAL_ERROR "CLANG_ANALYZER_ENABLE_Z3_SOLVER cannot be enabled when Z3 is not available.")
endif()
set(CLANG_ANALYZER_WITH_Z3 1)
endif()
option(CLANG_ENABLE_PROTO_FUZZER "Build Clang protobuf fuzzer." OFF)
if(NOT CLANG_ENABLE_STATIC_ANALYZER AND (CLANG_ENABLE_ARCMT OR CLANG_ANALYZER_ENABLE_Z3_SOLVER))
message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT or Z3")
endif()
if(CLANG_ENABLE_ARCMT)
set(CLANG_ENABLE_OBJC_REWRITER ON)
endif()
# Clang version information
set(CLANG_EXECUTABLE_VERSION
"${CLANG_VERSION_MAJOR}" CACHE STRING
"Major version number that will be appended to the clang executable name")
set(LIBCLANG_LIBRARY_VERSION
"${CLANG_VERSION_MAJOR}" CACHE STRING
"Major version number that will be appended to the libclang library")
mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
option(CLANG_INCLUDE_TESTS
"Generate build targets for the Clang unit tests."
${LLVM_INCLUDE_TESTS})
add_subdirectory(utils/TableGen)
add_subdirectory(include)
# All targets below may depend on all tablegen'd files.
get_property(CLANG_TABLEGEN_TARGETS GLOBAL PROPERTY CLANG_TABLEGEN_TARGETS)
add_custom_target(clang-tablegen-targets DEPENDS ${CLANG_TABLEGEN_TARGETS})
set_target_properties(clang-tablegen-targets PROPERTIES FOLDER "Misc")
list(APPEND LLVM_COMMON_DEPENDS clang-tablegen-targets)
# Force target to be built as soon as possible. Clang modules builds depend
# header-wise on it as they ship all headers from the umbrella folders. Building
# an entire module might include header, which depends on intrinsics_gen.
if(LLVM_ENABLE_MODULES AND NOT CLANG_BUILT_STANDALONE)
list(APPEND LLVM_COMMON_DEPENDS intrinsics_gen)
endif()
add_subdirectory(lib)
add_subdirectory(tools)
add_subdirectory(runtime)
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
add_subdirectory(examples)
if(APPLE)
# this line is needed as a cleanup to ensure that any CMakeCaches with the old
# default value get updated to the new default.
if(CLANG_ORDER_FILE STREQUAL "")
unset(CLANG_ORDER_FILE CACHE)
unset(CLANG_ORDER_FILE)
endif()
set(CLANG_ORDER_FILE ${CMAKE_CURRENT_BINARY_DIR}/clang.order CACHE FILEPATH
"Order file to use when compiling clang in order to improve startup time (Darwin Only - requires ld64).")
if(NOT EXISTS ${CLANG_ORDER_FILE})
string(FIND "${CLANG_ORDER_FILE}" "${CMAKE_CURRENT_BINARY_DIR}" PATH_START)
if(PATH_START EQUAL 0)
file(WRITE ${CLANG_ORDER_FILE} "\n")
else()
message(FATAL_ERROR "Specified order file '${CLANG_ORDER_FILE}' does not exist.")
endif()
endif()
endif()
if( CLANG_INCLUDE_TESTS )
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include/gtest/gtest.h)
add_subdirectory(unittests)
list(APPEND CLANG_TEST_DEPS ClangUnitTests)
list(APPEND CLANG_TEST_PARAMS
clang_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/test/Unit/lit.site.cfg
)
endif()
add_subdirectory(test)
add_subdirectory(bindings/python/tests)
if(CLANG_BUILT_STANDALONE)
# Add a global check rule now that all subdirectories have been traversed
# and we know the total set of lit testsuites.
get_property(LLVM_LIT_TESTSUITES GLOBAL PROPERTY LLVM_LIT_TESTSUITES)
get_property(LLVM_LIT_PARAMS GLOBAL PROPERTY LLVM_LIT_PARAMS)
get_property(LLVM_LIT_DEPENDS GLOBAL PROPERTY LLVM_LIT_DEPENDS)
get_property(LLVM_LIT_EXTRA_ARGS GLOBAL PROPERTY LLVM_LIT_EXTRA_ARGS)
get_property(LLVM_ADDITIONAL_TEST_TARGETS
GLOBAL PROPERTY LLVM_ADDITIONAL_TEST_TARGETS)
add_lit_target(check-all
"Running all regression tests"
${LLVM_LIT_TESTSUITES}
PARAMS ${LLVM_LIT_PARAMS}
DEPENDS ${LLVM_LIT_DEPENDS} ${LLVM_ADDITIONAL_TEST_TARGETS}
ARGS ${LLVM_LIT_EXTRA_ARGS}
)
endif()
add_subdirectory(utils/perf-training)
endif()
option(CLANG_INCLUDE_DOCS "Generate build targets for the Clang docs."
${LLVM_INCLUDE_DOCS})
if( CLANG_INCLUDE_DOCS )
add_subdirectory(docs)
endif()
add_subdirectory(cmake/modules)
if(CLANG_STAGE)
message(STATUS "Setting current clang stage to: ${CLANG_STAGE}")
endif()
if (CLANG_ENABLE_BOOTSTRAP)
include(ExternalProject)
add_custom_target(clang-bootstrap-deps DEPENDS clang)
if(NOT CLANG_STAGE)
set(CLANG_STAGE stage1)
endif()
string(REGEX MATCH "stage([0-9]*)" MATCHED_STAGE "${CLANG_STAGE}")
if(MATCHED_STAGE)
if(NOT LLVM_BUILD_INSTRUMENTED)
math(EXPR STAGE_NUM "${CMAKE_MATCH_1} + 1")
set(NEXT_CLANG_STAGE stage${STAGE_NUM})
else()
set(NEXT_CLANG_STAGE stage${CMAKE_MATCH_1})
endif()
else()
set(NEXT_CLANG_STAGE bootstrap)
endif()
if(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED)
set(NEXT_CLANG_STAGE ${NEXT_CLANG_STAGE}-instrumented)
endif()
message(STATUS "Setting next clang stage to: ${NEXT_CLANG_STAGE}")
set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-stamps/)
set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-bins/)
if(BOOTSTRAP_LLVM_ENABLE_LLD)
add_dependencies(clang-bootstrap-deps lld)
endif()
# If the next stage is LTO we need to depend on LTO and possibly lld or LLVMgold
if(BOOTSTRAP_LLVM_ENABLE_LTO OR LLVM_ENABLE_LTO AND NOT LLVM_BUILD_INSTRUMENTED)
if(APPLE)
add_dependencies(clang-bootstrap-deps LTO)
# on Darwin we need to set DARWIN_LTO_LIBRARY so that -flto will work
# using the just-built compiler, and we need to override DYLD_LIBRARY_PATH
# so that the host object file tools will use the just-built libLTO.
# However if System Integrity Protection is enabled the DYLD variables
# will be scrubbed from the environment of any base system commands. This
# includes /bin/sh, which ninja uses when executing build commands. To
# work around the envar being filtered away we pass it in as a CMake
# variable, and have LLVM's CMake append the envar to the archiver calls.
set(LTO_LIBRARY -DDARWIN_LTO_LIBRARY=${LLVM_SHLIB_OUTPUT_INTDIR}/libLTO.dylib
-DDYLD_LIBRARY_PATH=${LLVM_LIBRARY_OUTPUT_INTDIR})
elseif(NOT WIN32)
add_dependencies(clang-bootstrap-deps llvm-ar llvm-ranlib)
if(NOT BOOTSTRAP_LLVM_ENABLE_LLD AND LLVM_BINUTILS_INCDIR)
add_dependencies(clang-bootstrap-deps LLVMgold)
endif()
set(${CLANG_STAGE}_AR -DCMAKE_AR=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ar)
set(${CLANG_STAGE}_RANLIB -DCMAKE_RANLIB=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ranlib)
endif()
endif()
if(CLANG_BOOTSTRAP_EXTRA_DEPS)
add_dependencies(clang-bootstrap-deps ${CLANG_BOOTSTRAP_EXTRA_DEPS})
endif()
add_custom_target(${NEXT_CLANG_STAGE}-clear
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-cleared
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-cleared
DEPENDS clang-bootstrap-deps
COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${STAMP_DIR}
COMMENT "Clobberring ${NEXT_CLANG_STAGE} build and stamp directories"
)
if(CMAKE_VERBOSE_MAKEFILE)
set(verbose -DCMAKE_VERBOSE_MAKEFILE=On)
endif()
set(_BOOTSTRAP_DEFAULT_PASSTHROUGH
PACKAGE_VERSION
PACKAGE_VENDOR
LLVM_VERSION_MAJOR
LLVM_VERSION_MINOR
LLVM_VERSION_PATCH
CLANG_VERSION_MAJOR
CLANG_VERSION_MINOR
CLANG_VERSION_PATCHLEVEL
LLVM_VERSION_SUFFIX
LLVM_BINUTILS_INCDIR
CLANG_REPOSITORY_STRING
CMAKE_MAKE_PROGRAM
CMAKE_OSX_ARCHITECTURES
LLVM_ENABLE_PROJECTS
LLVM_ENABLE_RUNTIMES)
# We don't need to depend on compiler-rt/libcxx if we're building instrumented
# because the next stage will use the same compiler used to build this stage.
if(NOT LLVM_BUILD_INSTRUMENTED)
if(TARGET compiler-rt)
add_dependencies(clang-bootstrap-deps compiler-rt)
endif()
if(TARGET cxx-headers)
add_dependencies(clang-bootstrap-deps cxx-headers)
endif()
endif()
set(C_COMPILER "clang")
set(CXX_COMPILER "clang++")
if(WIN32)
set(C_COMPILER "clang-cl.exe")
set(CXX_COMPILER "clang-cl.exe")
endif()
set(COMPILER_OPTIONS
-DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${CXX_COMPILER}
-DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${C_COMPILER}
-DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${C_COMPILER}
-DCMAKE_ASM_COMPILER_ID=Clang)
if(BOOTSTRAP_CMAKE_SYSTEM_NAME)
set(${CLANG_STAGE}_CONFIG -DLLVM_CONFIG_PATH=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-config)
set(${CLANG_STAGE}_TABLEGEN
-DLLVM_TABLEGEN=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-tblgen
-DCLANG_TABLEGEN=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang-tblgen)
if(BOOTSTRAP_CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(BOOTSTRAP_LLVM_ENABLE_LLD)
set(${CLANG_STAGE}_LINKER -DCMAKE_LINKER=${LLVM_RUNTIME_OUTPUT_INTDIR}/ld.lld)
endif()
if(NOT BOOTSTRAP_LLVM_ENABLE_LTO)
add_dependencies(clang-bootstrap-deps llvm-ar llvm-ranlib)
set(${CLANG_STAGE}_AR -DCMAKE_AR=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ar)
set(${CLANG_STAGE}_RANLIB -DCMAKE_RANLIB=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ranlib)
endif()
add_dependencies(clang-bootstrap-deps llvm-objcopy llvm-strip)
set(${CLANG_STAGE}_OBJCOPY -DCMAKE_OBJCOPY=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-objcopy)
set(${CLANG_STAGE}_STRIP -DCMAKE_STRIP=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-strip)
endif()
endif()
if(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED)
add_dependencies(clang-bootstrap-deps llvm-profdata)
set(PGO_OPT -DLLVM_PROFDATA=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-profdata)
endif()
if(LLVM_BUILD_INSTRUMENTED)
add_dependencies(clang-bootstrap-deps generate-profdata)
set(PGO_OPT -DLLVM_PROFDATA_FILE=${CMAKE_CURRENT_BINARY_DIR}/utils/perf-training/clang.profdata)
# Use the current tools for LTO instead of the instrumented ones
list(APPEND _BOOTSTRAP_DEFAULT_PASSTHROUGH
CMAKE_CXX_COMPILER
CMAKE_C_COMPILER
CMAKE_ASM_COMPILER
CMAKE_AR
CMAKE_RANLIB
DARWIN_LTO_LIBRARY
DYLD_LIBRARY_PATH)
set(COMPILER_OPTIONS)
set(LTO_LIBRARY)
set(LTO_AR)
set(LTO_RANLIB)
endif()
# Find all variables that start with BOOTSTRAP_ and populate a variable with
# them.
get_cmake_property(variableNames VARIABLES)
foreach(variableName ${variableNames})
if(variableName MATCHES "^BOOTSTRAP_")
string(SUBSTRING ${variableName} 10 -1 varName)
string(REPLACE ";" "|" value "${${variableName}}")
list(APPEND PASSTHROUGH_VARIABLES
-D${varName}=${value})
endif()
if(${variableName} AND variableName MATCHES "LLVM_EXTERNAL_.*_SOURCE_DIR")
list(APPEND PASSTHROUGH_VARIABLES
-D${variableName}=${${variableName}})
endif()
endforeach()
# Populate the passthrough variables
foreach(variableName ${CLANG_BOOTSTRAP_PASSTHROUGH} ${_BOOTSTRAP_DEFAULT_PASSTHROUGH})
if(DEFINED ${variableName})
if("${${variableName}}" STREQUAL "")
set(value "")
else()
string(REPLACE ";" "|" value "${${variableName}}")
endif()
list(APPEND PASSTHROUGH_VARIABLES
-D${variableName}=${value})
endif()
endforeach()
ExternalProject_Add(${NEXT_CLANG_STAGE}
DEPENDS clang-bootstrap-deps
PREFIX ${NEXT_CLANG_STAGE}
SOURCE_DIR ${CMAKE_SOURCE_DIR}
STAMP_DIR ${STAMP_DIR}
BINARY_DIR ${BINARY_DIR}
EXCLUDE_FROM_ALL 1
CMAKE_ARGS
# We shouldn't need to set this here, but INSTALL_DIR doesn't
# seem to work, so instead I'm passing this through
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
${CLANG_BOOTSTRAP_CMAKE_ARGS}
${PASSTHROUGH_VARIABLES}
-DCLANG_STAGE=${NEXT_CLANG_STAGE}
${COMPILER_OPTIONS}
${${CLANG_STAGE}_CONFIG}
${${CLANG_STAGE}_TABLEGEN}
${LTO_LIBRARY} ${verbose} ${PGO_OPT}
${${CLANG_STAGE}_LINKER}
${${CLANG_STAGE}_AR}
${${CLANG_STAGE}_RANLIB}
${${CLANG_STAGE}_OBJCOPY}
${${CLANG_STAGE}_STRIP}
INSTALL_COMMAND ""
STEP_TARGETS configure build
USES_TERMINAL_CONFIGURE 1
USES_TERMINAL_BUILD 1
USES_TERMINAL_INSTALL 1
LIST_SEPARATOR |
)
# exclude really-install from main target
set_target_properties(${NEXT_CLANG_STAGE} PROPERTIES _EP_really-install_EXCLUDE_FROM_MAIN On)
ExternalProject_Add_Step(${NEXT_CLANG_STAGE} really-install
COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target install
COMMENT "Performing install step for '${NEXT_CLANG_STAGE}'"
DEPENDEES build
USES_TERMINAL 1
)
ExternalProject_Add_StepTargets(${NEXT_CLANG_STAGE} really-install)
add_custom_target(${NEXT_CLANG_STAGE}-install DEPENDS ${NEXT_CLANG_STAGE}-really-install)
if(NOT CLANG_BOOTSTRAP_TARGETS)
set(CLANG_BOOTSTRAP_TARGETS check-llvm check-clang check-all)
endif()
foreach(target ${CLANG_BOOTSTRAP_TARGETS})
# exclude from main target
set_target_properties(${NEXT_CLANG_STAGE} PROPERTIES _EP_${target}_EXCLUDE_FROM_MAIN On)
ExternalProject_Add_Step(${NEXT_CLANG_STAGE} ${target}
COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target ${target}
COMMENT "Performing ${target} for '${NEXT_CLANG_STAGE}'"
DEPENDEES configure
USES_TERMINAL 1
)
if(target MATCHES "^stage[0-9]*")
add_custom_target(${target} DEPENDS ${NEXT_CLANG_STAGE}-${target})
endif()
ExternalProject_Add_StepTargets(${NEXT_CLANG_STAGE} ${target})
endforeach()
endif()
if (LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION)
add_subdirectory(utils/ClangVisualizers)
endif()
add_subdirectory(utils/hmaptool)
configure_file(
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
${CLANG_BINARY_DIR}/include/clang/Config/config.h)

View File

@ -1,62 +0,0 @@
This file is a list of the people responsible for ensuring that patches for a
particular part of Clang are reviewed, either by themself or by someone else.
They are also the gatekeepers for their part of Clang, with the final word on
what goes in or not.
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
N: Aaron Ballman
E: aaron@aaronballman.com
D: Clang attributes
N: Alexey Bataev
E: a.bataev@hotmail.com
D: OpenMP support
N: Chandler Carruth
E: chandlerc@gmail.com
E: chandlerc@google.com
D: CMake, library layering
N: Eric Christopher
E: echristo@gmail.com
D: Debug Information, inline assembly
N: Devin Coughlin
E: dcoughlin@apple.com
D: Clang Static Analyzer
N: Doug Gregor
E: dgregor@apple.com
D: Emeritus owner
N: Reid Kleckner
E: rnk@google.com
D: Microsoft C++ ABI compatibility and general Windows support
N: Manuel Klimek
E: klimek@google.com
D: AST matchers, LibTooling
N: Anton Korobeynikov
E: anton@korobeynikov.info
D: Exception handling, Windows codegen, ARM EABI
N: John McCall
E: rjmccall@apple.com
D: Clang LLVM IR generation
N: Brad Smith
E: brad@comstyle.com
D: OpenBSD driver
N: Richard Smith
E: richard@metafoo.co.uk
D: All parts of Clang not covered by someone else
N: Anastasia Stulova
E: anastasia.stulova@arm.com
D: OpenCL support

View File

@ -1,2 +0,0 @@
#import <Cocoa/Cocoa.h>

View File

@ -1,86 +0,0 @@
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <complex>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cwchar>
#include <cwctype>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#if __has_include(<strstream>)
#include <strstream>
#endif
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#if __cplusplus >= 201103 || defined(__GXX_EXPERIMENTAL_CXX0X__)
#include <array>
#if __has_include(<atomic>)
#include <atomic>
#endif
#include <chrono>
#if __has_include(<codecvt>)
#include <codecvt>
#endif
#include <condition_variable>
#include <forward_list>
#if __has_include(<future>)
#include <future>
#endif
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#if __has_include(<scoped_allocator>)
#include <scoped_allocator>
#endif
#include <system_error>
#include <thread>
#include <tuple>
#include <type_traits>
#if __has_include(<typeindex>)
#include <typeindex>
#endif
#include <unordered_map>
#include <unordered_set>
#endif

View File

@ -1,639 +0,0 @@
/* Test for integer constant types. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk>. */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
#include <limits.h>
/* Assertion that constant C is of type T. */
#define ASSERT_CONST_TYPE(C, T) \
do { \
typedef T type; \
typedef type **typepp; \
typedef __typeof__((C)) ctype; \
typedef ctype **ctypepp; \
typepp x = 0; \
ctypepp y = 0; \
x = y; \
y = x; \
} while (0)
/* (T *) if E is zero, (void *) otherwise. */
#define type_if_not(T, E) __typeof__(0 ? (T *)0 : (void *)(E))
/* (T *) if E is nonzero, (void *) otherwise. */
#define type_if(T, E) type_if_not(T, !(E))
/* Combine pointer types, all but one (void *). */
#define type_comb2(T1, T2) __typeof__(0 ? (T1)0 : (T2)0)
#define type_comb3(T1, T2, T3) type_comb2(T1, type_comb2(T2, T3))
#define type_comb4(T1, T2, T3, T4) \
type_comb2(T1, type_comb2(T2, type_comb2(T3, T4)))
#define type_comb6(T1, T2, T3, T4, T5, T6) \
type_comb2(T1, \
type_comb2(T2, \
type_comb2(T3, \
type_comb2(T4, \
type_comb2(T5, T6)))))
/* (T1 *) if E1, otherwise (T2 *) if E2. */
#define first_of2p(T1, E1, T2, E2) type_comb2(type_if(T1, (E1)), \
type_if(T2, (!(E1) && (E2))))
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3. */
#define first_of3p(T1, E1, T2, E2, T3, E3) \
type_comb3(type_if(T1, (E1)), \
type_if(T2, (!(E1) && (E2))), \
type_if(T3, (!(E1) && !(E2) && (E3))))
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
(T4 *) if E4. */
#define first_of4p(T1, E1, T2, E2, T3, E3, T4, E4) \
type_comb4(type_if(T1, (E1)), \
type_if(T2, (!(E1) && (E2))), \
type_if(T3, (!(E1) && !(E2) && (E3))), \
type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))))
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
(T4 *) if E4, otherwise (T5 *) if E5, otherwise (T6 *) if E6. */
#define first_of6p(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
type_comb6(type_if(T1, (E1)), \
type_if(T2, (!(E1) && (E2))), \
type_if(T3, (!(E1) && !(E2) && (E3))), \
type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))), \
type_if(T5, (!(E1) && !(E2) && !(E3) && !(E4) && (E5))), \
type_if(T6, (!(E1) && !(E2) && !(E3) \
&& !(E4) && !(E5) && (E6))))
/* Likewise, but return the original type rather than a pointer type. */
#define first_of2(T1, E1, T2, E2) \
__typeof__(*((first_of2p(T1, (E1), T2, (E2)))0))
#define first_of3(T1, E1, T2, E2, T3, E3) \
__typeof__(*((first_of3p(T1, (E1), T2, (E2), T3, (E3)))0))
#define first_of4(T1, E1, T2, E2, T3, E3, T4, E4) \
__typeof__(*((first_of4p(T1, (E1), T2, (E2), T3, (E3), T4, (E4)))0))
#define first_of6(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
__typeof__(*((first_of6p(T1, (E1), T2, (E2), T3, (E3), \
T4, (E4), T5, (E5), T6, (E6)))0))
/* Types of constants according to the C99 rules. */
#define C99_UNSUF_DEC_TYPE(C) \
first_of3(int, (C) <= INT_MAX, \
long int, (C) <= LONG_MAX, \
long long int, (C) <= LLONG_MAX)
#define C99_UNSUF_OCTHEX_TYPE(C) \
first_of6(int, (C) <= INT_MAX, \
unsigned int, (C) <= UINT_MAX, \
long int, (C) <= LONG_MAX, \
unsigned long int, (C) <= ULONG_MAX, \
long long int, (C) <= LLONG_MAX, \
unsigned long long int, (C) <= ULLONG_MAX)
#define C99_SUFu_TYPE(C) \
first_of3(unsigned int, (C) <= UINT_MAX, \
unsigned long int, (C) <= ULONG_MAX, \
unsigned long long int, (C) <= ULLONG_MAX)
#define C99_SUFl_DEC_TYPE(C) \
first_of2(long int, (C) <= LONG_MAX, \
long long int, (C) <= LLONG_MAX)
#define C99_SUFl_OCTHEX_TYPE(C) \
first_of4(long int, (C) <= LONG_MAX, \
unsigned long int, (C) <= ULONG_MAX, \
long long int, (C) <= LLONG_MAX, \
unsigned long long int, (C) <= ULLONG_MAX)
#define C99_SUFul_TYPE(C) \
first_of2(unsigned long int, (C) <= ULONG_MAX, \
unsigned long long int, (C) <= ULLONG_MAX)
#define C99_SUFll_OCTHEX_TYPE(C) \
first_of2(long long int, (C) <= LLONG_MAX, \
unsigned long long int, (C) <= ULLONG_MAX)
/* Checks that constants have correct type. */
#define CHECK_UNSUF_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_UNSUF_DEC_TYPE((C)))
#define CHECK_UNSUF_OCTHEX_TYPE(C) \
ASSERT_CONST_TYPE((C), C99_UNSUF_OCTHEX_TYPE((C)))
#define CHECK_SUFu_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFu_TYPE((C)))
#define CHECK_SUFl_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFl_DEC_TYPE((C)))
#define CHECK_SUFl_OCTHEX_TYPE(C) \
ASSERT_CONST_TYPE((C), C99_SUFl_OCTHEX_TYPE((C)))
#define CHECK_SUFul_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFul_TYPE((C)))
#define CHECK_SUFll_DEC_TYPE(C) ASSERT_CONST_TYPE((C), long long int)
#define CHECK_SUFll_OCTHEX_TYPE(C) \
ASSERT_CONST_TYPE((C), C99_SUFll_OCTHEX_TYPE((C)))
#define CHECK_SUFull_TYPE(C) ASSERT_CONST_TYPE((C), unsigned long long int)
/* Check a decimal value, with all suffixes. */
#define CHECK_DEC_CONST(C) \
CHECK_UNSUF_DEC_TYPE(C); \
CHECK_SUFu_TYPE(C##u); \
CHECK_SUFu_TYPE(C##U); \
CHECK_SUFl_DEC_TYPE(C##l); \
CHECK_SUFl_DEC_TYPE(C##L); \
CHECK_SUFul_TYPE(C##ul); \
CHECK_SUFul_TYPE(C##uL); \
CHECK_SUFul_TYPE(C##Ul); \
CHECK_SUFul_TYPE(C##UL); \
CHECK_SUFll_DEC_TYPE(C##ll); \
CHECK_SUFll_DEC_TYPE(C##LL); \
CHECK_SUFull_TYPE(C##ull); \
CHECK_SUFull_TYPE(C##uLL); \
CHECK_SUFull_TYPE(C##Ull); \
CHECK_SUFull_TYPE(C##ULL);
/* Check an octal or hexadecimal value, with all suffixes. */
#define CHECK_OCTHEX_CONST(C) \
CHECK_UNSUF_OCTHEX_TYPE(C); \
CHECK_SUFu_TYPE(C##u); \
CHECK_SUFu_TYPE(C##U); \
CHECK_SUFl_OCTHEX_TYPE(C##l); \
CHECK_SUFl_OCTHEX_TYPE(C##L); \
CHECK_SUFul_TYPE(C##ul); \
CHECK_SUFul_TYPE(C##uL); \
CHECK_SUFul_TYPE(C##Ul); \
CHECK_SUFul_TYPE(C##UL); \
CHECK_SUFll_OCTHEX_TYPE(C##ll); \
CHECK_SUFll_OCTHEX_TYPE(C##LL); \
CHECK_SUFull_TYPE(C##ull); \
CHECK_SUFull_TYPE(C##uLL); \
CHECK_SUFull_TYPE(C##Ull); \
CHECK_SUFull_TYPE(C##ULL);
#define CHECK_OCT_CONST(C) CHECK_OCTHEX_CONST(C)
#define CHECK_HEX_CONST(C) \
CHECK_OCTHEX_CONST(0x##C); \
CHECK_OCTHEX_CONST(0X##C);
/* True iff "long long" is at least B bits. This presumes that (B-2)/3 is at
most 63. */
#define LLONG_AT_LEAST(B) \
(LLONG_MAX >> ((B)-2)/3 >> ((B)-2)/3 \
>> ((B)-2 - ((B)-2)/3 - ((B)-2)/3))
#define LLONG_HAS_BITS(B) (LLONG_AT_LEAST((B)) && !LLONG_AT_LEAST((B) + 1))
void
foo (void)
{
/* Decimal. */
/* Check all 2^n and 2^n - 1 up to 2^71 - 1. */
CHECK_DEC_CONST(1);
CHECK_DEC_CONST(2);
CHECK_DEC_CONST(3);
CHECK_DEC_CONST(4);
CHECK_DEC_CONST(7);
CHECK_DEC_CONST(8);
CHECK_DEC_CONST(15);
CHECK_DEC_CONST(16);
CHECK_DEC_CONST(31);
CHECK_DEC_CONST(32);
CHECK_DEC_CONST(63);
CHECK_DEC_CONST(64);
CHECK_DEC_CONST(127);
CHECK_DEC_CONST(128);
CHECK_DEC_CONST(255);
CHECK_DEC_CONST(256);
CHECK_DEC_CONST(511);
CHECK_DEC_CONST(512);
CHECK_DEC_CONST(1023);
CHECK_DEC_CONST(1024);
CHECK_DEC_CONST(2047);
CHECK_DEC_CONST(2048);
CHECK_DEC_CONST(4095);
CHECK_DEC_CONST(4096);
CHECK_DEC_CONST(8191);
CHECK_DEC_CONST(8192);
CHECK_DEC_CONST(16383);
CHECK_DEC_CONST(16384);
CHECK_DEC_CONST(32767);
CHECK_DEC_CONST(32768);
CHECK_DEC_CONST(65535);
CHECK_DEC_CONST(65536);
CHECK_DEC_CONST(131071);
CHECK_DEC_CONST(131072);
CHECK_DEC_CONST(262143);
CHECK_DEC_CONST(262144);
CHECK_DEC_CONST(524287);
CHECK_DEC_CONST(524288);
CHECK_DEC_CONST(1048575);
CHECK_DEC_CONST(1048576);
CHECK_DEC_CONST(2097151);
CHECK_DEC_CONST(2097152);
CHECK_DEC_CONST(4194303);
CHECK_DEC_CONST(4194304);
CHECK_DEC_CONST(8388607);
CHECK_DEC_CONST(8388608);
CHECK_DEC_CONST(16777215);
CHECK_DEC_CONST(16777216);
CHECK_DEC_CONST(33554431);
CHECK_DEC_CONST(33554432);
CHECK_DEC_CONST(67108863);
CHECK_DEC_CONST(67108864);
CHECK_DEC_CONST(134217727);
CHECK_DEC_CONST(134217728);
CHECK_DEC_CONST(268435455);
CHECK_DEC_CONST(268435456);
CHECK_DEC_CONST(536870911);
CHECK_DEC_CONST(536870912);
CHECK_DEC_CONST(1073741823);
CHECK_DEC_CONST(1073741824);
CHECK_DEC_CONST(2147483647);
CHECK_DEC_CONST(2147483648);
CHECK_DEC_CONST(4294967295);
CHECK_DEC_CONST(4294967296);
CHECK_DEC_CONST(8589934591);
CHECK_DEC_CONST(8589934592);
CHECK_DEC_CONST(17179869183);
CHECK_DEC_CONST(17179869184);
CHECK_DEC_CONST(34359738367);
CHECK_DEC_CONST(34359738368);
CHECK_DEC_CONST(68719476735);
CHECK_DEC_CONST(68719476736);
CHECK_DEC_CONST(137438953471);
CHECK_DEC_CONST(137438953472);
CHECK_DEC_CONST(274877906943);
CHECK_DEC_CONST(274877906944);
CHECK_DEC_CONST(549755813887);
CHECK_DEC_CONST(549755813888);
CHECK_DEC_CONST(1099511627775);
CHECK_DEC_CONST(1099511627776);
CHECK_DEC_CONST(2199023255551);
CHECK_DEC_CONST(2199023255552);
CHECK_DEC_CONST(4398046511103);
CHECK_DEC_CONST(4398046511104);
CHECK_DEC_CONST(8796093022207);
CHECK_DEC_CONST(8796093022208);
CHECK_DEC_CONST(17592186044415);
CHECK_DEC_CONST(17592186044416);
CHECK_DEC_CONST(35184372088831);
CHECK_DEC_CONST(35184372088832);
CHECK_DEC_CONST(70368744177663);
CHECK_DEC_CONST(70368744177664);
CHECK_DEC_CONST(140737488355327);
CHECK_DEC_CONST(140737488355328);
CHECK_DEC_CONST(281474976710655);
CHECK_DEC_CONST(281474976710656);
CHECK_DEC_CONST(562949953421311);
CHECK_DEC_CONST(562949953421312);
CHECK_DEC_CONST(1125899906842623);
CHECK_DEC_CONST(1125899906842624);
CHECK_DEC_CONST(2251799813685247);
CHECK_DEC_CONST(2251799813685248);
CHECK_DEC_CONST(4503599627370495);
CHECK_DEC_CONST(4503599627370496);
CHECK_DEC_CONST(9007199254740991);
CHECK_DEC_CONST(9007199254740992);
CHECK_DEC_CONST(18014398509481983);
CHECK_DEC_CONST(18014398509481984);
CHECK_DEC_CONST(36028797018963967);
CHECK_DEC_CONST(36028797018963968);
CHECK_DEC_CONST(72057594037927935);
CHECK_DEC_CONST(72057594037927936);
CHECK_DEC_CONST(144115188075855871);
CHECK_DEC_CONST(144115188075855872);
CHECK_DEC_CONST(288230376151711743);
CHECK_DEC_CONST(288230376151711744);
CHECK_DEC_CONST(576460752303423487);
CHECK_DEC_CONST(576460752303423488);
CHECK_DEC_CONST(1152921504606846975);
CHECK_DEC_CONST(1152921504606846976);
CHECK_DEC_CONST(2305843009213693951);
CHECK_DEC_CONST(2305843009213693952);
CHECK_DEC_CONST(4611686018427387903);
CHECK_DEC_CONST(4611686018427387904);
CHECK_DEC_CONST(9223372036854775807);
#if LLONG_AT_LEAST(65)
CHECK_DEC_CONST(9223372036854775808);
CHECK_DEC_CONST(18446744073709551615);
#endif
#if LLONG_AT_LEAST(66)
CHECK_DEC_CONST(18446744073709551616);
CHECK_DEC_CONST(36893488147419103231);
#endif
#if LLONG_AT_LEAST(67)
CHECK_DEC_CONST(36893488147419103232);
CHECK_DEC_CONST(73786976294838206463);
#endif
#if LLONG_AT_LEAST(68)
CHECK_DEC_CONST(73786976294838206464);
CHECK_DEC_CONST(147573952589676412927);
#endif
#if LLONG_AT_LEAST(69)
CHECK_DEC_CONST(147573952589676412928);
CHECK_DEC_CONST(295147905179352825855);
#endif
#if LLONG_AT_LEAST(70)
CHECK_DEC_CONST(295147905179352825856);
CHECK_DEC_CONST(590295810358705651711);
#endif
#if LLONG_AT_LEAST(71)
CHECK_DEC_CONST(590295810358705651712);
CHECK_DEC_CONST(1180591620717411303423);
#endif
#if LLONG_AT_LEAST(72)
CHECK_DEC_CONST(1180591620717411303424);
CHECK_DEC_CONST(2361183241434822606847);
#endif
/* Octal and hexadecimal. */
/* Check all 2^n and 2^n - 1 up to 2^72 - 1. */
CHECK_OCT_CONST(0);
CHECK_HEX_CONST(0);
CHECK_OCT_CONST(01);
CHECK_HEX_CONST(1);
CHECK_OCT_CONST(02);
CHECK_HEX_CONST(2);
CHECK_OCT_CONST(03);
CHECK_HEX_CONST(3);
CHECK_OCT_CONST(04);
CHECK_HEX_CONST(4);
CHECK_OCT_CONST(07);
CHECK_HEX_CONST(7);
CHECK_OCT_CONST(010);
CHECK_HEX_CONST(8);
CHECK_OCT_CONST(017);
CHECK_HEX_CONST(f);
CHECK_OCT_CONST(020);
CHECK_HEX_CONST(10);
CHECK_OCT_CONST(037);
CHECK_HEX_CONST(1f);
CHECK_OCT_CONST(040);
CHECK_HEX_CONST(20);
CHECK_OCT_CONST(077);
CHECK_HEX_CONST(3f);
CHECK_OCT_CONST(0100);
CHECK_HEX_CONST(40);
CHECK_OCT_CONST(0177);
CHECK_HEX_CONST(7f);
CHECK_OCT_CONST(0200);
CHECK_HEX_CONST(80);
CHECK_OCT_CONST(0377);
CHECK_HEX_CONST(ff);
CHECK_OCT_CONST(0400);
CHECK_HEX_CONST(100);
CHECK_OCT_CONST(0777);
CHECK_HEX_CONST(1ff);
CHECK_OCT_CONST(01000);
CHECK_HEX_CONST(200);
CHECK_OCT_CONST(01777);
CHECK_HEX_CONST(3ff);
CHECK_OCT_CONST(02000);
CHECK_HEX_CONST(400);
CHECK_OCT_CONST(03777);
CHECK_HEX_CONST(7ff);
CHECK_OCT_CONST(04000);
CHECK_HEX_CONST(800);
CHECK_OCT_CONST(07777);
CHECK_HEX_CONST(fff);
CHECK_OCT_CONST(010000);
CHECK_HEX_CONST(1000);
CHECK_OCT_CONST(017777);
CHECK_HEX_CONST(1fff);
CHECK_OCT_CONST(020000);
CHECK_HEX_CONST(2000);
CHECK_OCT_CONST(037777);
CHECK_HEX_CONST(3fff);
CHECK_OCT_CONST(040000);
CHECK_HEX_CONST(4000);
CHECK_OCT_CONST(077777);
CHECK_HEX_CONST(7fff);
CHECK_OCT_CONST(0100000);
CHECK_HEX_CONST(8000);
CHECK_OCT_CONST(0177777);
CHECK_HEX_CONST(ffff);
CHECK_OCT_CONST(0200000);
CHECK_HEX_CONST(10000);
CHECK_OCT_CONST(0377777);
CHECK_HEX_CONST(1ffff);
CHECK_OCT_CONST(0400000);
CHECK_HEX_CONST(20000);
CHECK_OCT_CONST(0777777);
CHECK_HEX_CONST(3ffff);
CHECK_OCT_CONST(01000000);
CHECK_HEX_CONST(40000);
CHECK_OCT_CONST(01777777);
CHECK_HEX_CONST(7ffff);
CHECK_OCT_CONST(02000000);
CHECK_HEX_CONST(80000);
CHECK_OCT_CONST(03777777);
CHECK_HEX_CONST(fffff);
CHECK_OCT_CONST(04000000);
CHECK_HEX_CONST(100000);
CHECK_OCT_CONST(07777777);
CHECK_HEX_CONST(1fffff);
CHECK_OCT_CONST(010000000);
CHECK_HEX_CONST(200000);
CHECK_OCT_CONST(017777777);
CHECK_HEX_CONST(3fffff);
CHECK_OCT_CONST(020000000);
CHECK_HEX_CONST(400000);
CHECK_OCT_CONST(037777777);
CHECK_HEX_CONST(7fffff);
CHECK_OCT_CONST(040000000);
CHECK_HEX_CONST(800000);
CHECK_OCT_CONST(077777777);
CHECK_HEX_CONST(ffffff);
CHECK_OCT_CONST(0100000000);
CHECK_HEX_CONST(1000000);
CHECK_OCT_CONST(0177777777);
CHECK_HEX_CONST(1ffffff);
CHECK_OCT_CONST(0200000000);
CHECK_HEX_CONST(2000000);
CHECK_OCT_CONST(0377777777);
CHECK_HEX_CONST(3ffffff);
CHECK_OCT_CONST(0400000000);
CHECK_HEX_CONST(4000000);
CHECK_OCT_CONST(0777777777);
CHECK_HEX_CONST(7ffffff);
CHECK_OCT_CONST(01000000000);
CHECK_HEX_CONST(8000000);
CHECK_OCT_CONST(01777777777);
CHECK_HEX_CONST(fffffff);
CHECK_OCT_CONST(02000000000);
CHECK_HEX_CONST(10000000);
CHECK_OCT_CONST(03777777777);
CHECK_HEX_CONST(1fffffff);
CHECK_OCT_CONST(04000000000);
CHECK_HEX_CONST(20000000);
CHECK_OCT_CONST(07777777777);
CHECK_HEX_CONST(3fffffff);
CHECK_OCT_CONST(010000000000);
CHECK_HEX_CONST(40000000);
CHECK_OCT_CONST(017777777777);
CHECK_HEX_CONST(7fffffff);
CHECK_OCT_CONST(020000000000);
CHECK_HEX_CONST(80000000);
CHECK_OCT_CONST(037777777777);
CHECK_HEX_CONST(ffffffff);
CHECK_OCT_CONST(040000000000);
CHECK_HEX_CONST(100000000);
CHECK_OCT_CONST(077777777777);
CHECK_HEX_CONST(1ffffffff);
CHECK_OCT_CONST(0100000000000);
CHECK_HEX_CONST(200000000);
CHECK_OCT_CONST(0177777777777);
CHECK_HEX_CONST(3ffffffff);
CHECK_OCT_CONST(0200000000000);
CHECK_HEX_CONST(400000000);
CHECK_OCT_CONST(0377777777777);
CHECK_HEX_CONST(7ffffffff);
CHECK_OCT_CONST(0400000000000);
CHECK_HEX_CONST(800000000);
CHECK_OCT_CONST(0777777777777);
CHECK_HEX_CONST(fffffffff);
CHECK_OCT_CONST(01000000000000);
CHECK_HEX_CONST(1000000000);
CHECK_OCT_CONST(01777777777777);
CHECK_HEX_CONST(1fffffffff);
CHECK_OCT_CONST(02000000000000);
CHECK_HEX_CONST(2000000000);
CHECK_OCT_CONST(03777777777777);
CHECK_HEX_CONST(3fffffffff);
CHECK_OCT_CONST(04000000000000);
CHECK_HEX_CONST(4000000000);
CHECK_OCT_CONST(07777777777777);
CHECK_HEX_CONST(7fffffffff);
CHECK_OCT_CONST(010000000000000);
CHECK_HEX_CONST(8000000000);
CHECK_OCT_CONST(017777777777777);
CHECK_HEX_CONST(ffffffffff);
CHECK_OCT_CONST(020000000000000);
CHECK_HEX_CONST(10000000000);
CHECK_OCT_CONST(037777777777777);
CHECK_HEX_CONST(1ffffffffff);
CHECK_OCT_CONST(040000000000000);
CHECK_HEX_CONST(20000000000);
CHECK_OCT_CONST(077777777777777);
CHECK_HEX_CONST(3ffffffffff);
CHECK_OCT_CONST(0100000000000000);
CHECK_HEX_CONST(40000000000);
CHECK_OCT_CONST(0177777777777777);
CHECK_HEX_CONST(7ffffffffff);
CHECK_OCT_CONST(0200000000000000);
CHECK_HEX_CONST(80000000000);
CHECK_OCT_CONST(0377777777777777);
CHECK_HEX_CONST(fffffffffff);
CHECK_OCT_CONST(0400000000000000);
CHECK_HEX_CONST(100000000000);
CHECK_OCT_CONST(0777777777777777);
CHECK_HEX_CONST(1fffffffffff);
CHECK_OCT_CONST(01000000000000000);
CHECK_HEX_CONST(200000000000);
CHECK_OCT_CONST(01777777777777777);
CHECK_HEX_CONST(3fffffffffff);
CHECK_OCT_CONST(02000000000000000);
CHECK_HEX_CONST(400000000000);
CHECK_OCT_CONST(03777777777777777);
CHECK_HEX_CONST(7fffffffffff);
CHECK_OCT_CONST(04000000000000000);
CHECK_HEX_CONST(800000000000);
CHECK_OCT_CONST(07777777777777777);
CHECK_HEX_CONST(ffffffffffff);
CHECK_OCT_CONST(010000000000000000);
CHECK_HEX_CONST(1000000000000);
CHECK_OCT_CONST(017777777777777777);
CHECK_HEX_CONST(1ffffffffffff);
CHECK_OCT_CONST(020000000000000000);
CHECK_HEX_CONST(2000000000000);
CHECK_OCT_CONST(037777777777777777);
CHECK_HEX_CONST(3ffffffffffff);
CHECK_OCT_CONST(040000000000000000);
CHECK_HEX_CONST(4000000000000);
CHECK_OCT_CONST(077777777777777777);
CHECK_HEX_CONST(7ffffffffffff);
CHECK_OCT_CONST(0100000000000000000);
CHECK_HEX_CONST(8000000000000);
CHECK_OCT_CONST(0177777777777777777);
CHECK_HEX_CONST(fffffffffffff);
CHECK_OCT_CONST(0200000000000000000);
CHECK_HEX_CONST(10000000000000);
CHECK_OCT_CONST(0377777777777777777);
CHECK_HEX_CONST(1fffffffffffff);
CHECK_OCT_CONST(0400000000000000000);
CHECK_HEX_CONST(20000000000000);
CHECK_OCT_CONST(0777777777777777777);
CHECK_HEX_CONST(3fffffffffffff);
CHECK_OCT_CONST(01000000000000000000);
CHECK_HEX_CONST(40000000000000);
CHECK_OCT_CONST(01777777777777777777);
CHECK_HEX_CONST(7fffffffffffff);
CHECK_OCT_CONST(02000000000000000000);
CHECK_HEX_CONST(80000000000000);
CHECK_OCT_CONST(03777777777777777777);
CHECK_HEX_CONST(ffffffffffffff);
CHECK_OCT_CONST(04000000000000000000);
CHECK_HEX_CONST(100000000000000);
CHECK_OCT_CONST(07777777777777777777);
CHECK_HEX_CONST(1ffffffffffffff);
CHECK_OCT_CONST(010000000000000000000);
CHECK_HEX_CONST(200000000000000);
CHECK_OCT_CONST(017777777777777777777);
CHECK_HEX_CONST(3ffffffffffffff);
CHECK_OCT_CONST(020000000000000000000);
CHECK_HEX_CONST(400000000000000);
CHECK_OCT_CONST(037777777777777777777);
CHECK_HEX_CONST(7ffffffffffffff);
CHECK_OCT_CONST(040000000000000000000);
CHECK_HEX_CONST(800000000000000);
CHECK_OCT_CONST(077777777777777777777);
CHECK_HEX_CONST(fffffffffffffff);
CHECK_OCT_CONST(0100000000000000000000);
CHECK_HEX_CONST(1000000000000000);
CHECK_OCT_CONST(0177777777777777777777);
CHECK_HEX_CONST(1fffffffffffffff);
CHECK_OCT_CONST(0200000000000000000000);
CHECK_HEX_CONST(2000000000000000);
CHECK_OCT_CONST(0377777777777777777777);
CHECK_HEX_CONST(3fffffffffffffff);
CHECK_OCT_CONST(0400000000000000000000);
CHECK_HEX_CONST(4000000000000000);
CHECK_OCT_CONST(0777777777777777777777);
CHECK_HEX_CONST(7fffffffffffffff);
CHECK_OCT_CONST(01000000000000000000000);
CHECK_HEX_CONST(8000000000000000);
CHECK_OCT_CONST(01777777777777777777777);
CHECK_HEX_CONST(ffffffffffffffff);
#if LLONG_AT_LEAST(65)
CHECK_OCT_CONST(02000000000000000000000);
CHECK_HEX_CONST(10000000000000000);
CHECK_OCT_CONST(03777777777777777777777);
CHECK_HEX_CONST(1ffffffffffffffff);
#endif
#if LLONG_AT_LEAST(66)
CHECK_OCT_CONST(04000000000000000000000);
CHECK_HEX_CONST(20000000000000000);
CHECK_OCT_CONST(07777777777777777777777);
CHECK_HEX_CONST(3ffffffffffffffff);
#endif
#if LLONG_AT_LEAST(67)
CHECK_OCT_CONST(010000000000000000000000);
CHECK_HEX_CONST(40000000000000000);
CHECK_OCT_CONST(017777777777777777777777);
CHECK_HEX_CONST(7ffffffffffffffff);
#endif
#if LLONG_AT_LEAST(68)
CHECK_OCT_CONST(020000000000000000000000);
CHECK_HEX_CONST(80000000000000000);
CHECK_OCT_CONST(037777777777777777777777);
CHECK_HEX_CONST(fffffffffffffffff);
#endif
#if LLONG_AT_LEAST(69)
CHECK_OCT_CONST(040000000000000000000000);
CHECK_HEX_CONST(100000000000000000);
CHECK_OCT_CONST(077777777777777777777777);
CHECK_HEX_CONST(1fffffffffffffffff);
#endif
#if LLONG_AT_LEAST(70)
CHECK_OCT_CONST(0100000000000000000000000);
CHECK_HEX_CONST(200000000000000000);
CHECK_OCT_CONST(0177777777777777777777777);
CHECK_HEX_CONST(3fffffffffffffffff);
#endif
#if LLONG_AT_LEAST(71)
CHECK_OCT_CONST(0200000000000000000000000);
CHECK_HEX_CONST(400000000000000000);
CHECK_OCT_CONST(0377777777777777777777777);
CHECK_HEX_CONST(7fffffffffffffffff);
#endif
#if LLONG_AT_LEAST(72)
CHECK_OCT_CONST(0400000000000000000000000);
CHECK_HEX_CONST(800000000000000000);
CHECK_OCT_CONST(0777777777777777777777777);
CHECK_HEX_CONST(ffffffffffffffffff);
#endif
}

View File

@ -1,4 +0,0 @@
#include <Carbon/Carbon.h>
//#import<vecLib/vecLib.h>

View File

@ -1,27 +0,0 @@
#define EXPAND_2_CASES(i, x, y) CASE(i, x, y); CASE(i + 1, x, y);
#define EXPAND_4_CASES(i, x, y) EXPAND_2_CASES(i, x, y) EXPAND_2_CASES(i + 2, x, y)
#define EXPAND_8_CASES(i, x, y) EXPAND_4_CASES(i, x, y) EXPAND_4_CASES(i + 4, x, y)
#define EXPAND_16_CASES(i, x, y) EXPAND_8_CASES(i, x, y) EXPAND_8_CASES(i + 8, x, y)
#define EXPAND_32_CASES(i, x, y) EXPAND_16_CASES(i, x, y) EXPAND_16_CASES(i + 16, x, y)
#define EXPAND_64_CASES(i, x, y) EXPAND_32_CASES(i, x, y) EXPAND_32_CASES(i + 32, x, y)
#define EXPAND_128_CASES(i, x, y) EXPAND_64_CASES(i, x, y) EXPAND_64_CASES(i + 64, x, y)
#define EXPAND_256_CASES(i, x, y) EXPAND_128_CASES(i, x, y) EXPAND_128_CASES(i + 128, x, y)
#define EXPAND_512_CASES(i, x, y) EXPAND_256_CASES(i, x, y) EXPAND_256_CASES(i + 256, x, y)
#define EXPAND_1024_CASES(i, x, y) EXPAND_512_CASES(i, x, y) EXPAND_512_CASES(i + 512, x, y)
#define EXPAND_2048_CASES(i, x, y) EXPAND_1024_CASES(i, x, y) EXPAND_1024_CASES(i + 1024, x, y)
#define EXPAND_4096_CASES(i, x, y) EXPAND_2048_CASES(i, x, y) EXPAND_2048_CASES(i + 2048, x, y)
// This has a *monstrous* single fan-out in the CFG, across 8000 blocks inside
// the while loop.
unsigned cfg_big_switch(int x) {
unsigned y = 0;
while (x > 0) {
switch(x) {
#define CASE(i, x, y) \
case i: { int case_var = 3*x + i; y += case_var - 1; break; }
EXPAND_4096_CASES(0, x, y);
}
--x;
}
return y;
}

View File

@ -1,20 +0,0 @@
#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y);
#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y)
#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y)
#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y)
#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y)
#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y)
#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y)
#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y)
#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y)
#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y)
#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y)
#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y)
unsigned cfg_long_chain_single_exit(unsigned x) {
unsigned y = 0;
#define BRANCH(i, x, y) if ((x % 13171) < i) { int var = x / 13171; y ^= var; }
EXPAND_4096_BRANCHES(1, x, y);
#undef BRANCH
return y;
}

View File

@ -1,20 +0,0 @@
#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y);
#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y)
#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y)
#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y)
#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y)
#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y)
#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y)
#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y)
#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y)
#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y)
#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y)
#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y)
unsigned cfg_long_chain_multiple_exit(unsigned x) {
unsigned y = 0;
#define BRANCH(i, x, y) if (((x % 13171) + ++y) < i) { int var = x / 13171 + y; return var; }
EXPAND_4096_BRANCHES(1, x, y);
#undef BRANCH
return 42;
}

View File

@ -1,21 +0,0 @@
#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y);
#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y)
#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y)
#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y)
#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y)
#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y)
#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y)
#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y)
#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y)
#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y)
#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y)
#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y)
unsigned cfg_long_chain_many_preds(unsigned x) {
unsigned y = 0;
#define BRANCH(i, x, y) if ((x % 13171) < i) { int var = x / 13171; y ^= var; } else
EXPAND_4096_BRANCHES(1, x, y);
#undef BRANCH
int var = x / 13171; y^= var;
return y;
}

View File

@ -1,36 +0,0 @@
#define EXPAND_2_INNER_CASES(i, x, y) INNER_CASE(i, x, y); INNER_CASE(i + 1, x, y);
#define EXPAND_4_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i + 2, x, y)
#define EXPAND_8_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i + 4, x, y)
#define EXPAND_16_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i + 8, x, y)
#define EXPAND_32_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i + 16, x, y)
#define EXPAND_64_INNER_CASES(i, x, y) EXPAND_32_INNER_CASES(i, x, y) EXPAND_32_INNER_CASES(i + 32, x, y)
#define EXPAND_2_OUTER_CASES(i, x, y) OUTER_CASE(i, x, y); OUTER_CASE(i + 1, x, y);
#define EXPAND_4_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i + 2, x, y)
#define EXPAND_8_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i + 4, x, y)
#define EXPAND_16_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i + 8, x, y)
#define EXPAND_32_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i + 16, x, y)
#define EXPAND_64_OUTER_CASES(i, x, y) EXPAND_32_OUTER_CASES(i, x, y) EXPAND_32_OUTER_CASES(i + 32, x, y)
// Rather than a single monstrous fan-out, this fans out in smaller increments,
// but to a similar size.
unsigned cfg_nested_switch(int x) {
unsigned y = 0;
while (x > 0) {
switch (x) {
#define INNER_CASE(i, x, y) \
case i: { int case_var = 3*x + i; y += case_var - 1; break; }
#define OUTER_CASE(i, x, y) \
case i: { \
int case_var = y >> 8; \
switch (case_var) { \
EXPAND_64_INNER_CASES(0, x, y); \
} \
break; \
}
EXPAND_64_OUTER_CASES(0, x, y);
}
--x;
}
return y;
}

View File

@ -1,59 +0,0 @@
// Hammer the CFG with large numbers of overlapping variable scopes, which
// implicit destructors triggered at each edge.
#define EXPAND_BASIC_STRUCT(i) struct X##i { X##i(int); ~X##i(); };
#define EXPAND_NORET_STRUCT(i) struct X##i { X##i(int); ~X##i() __attribute__((noreturn)); };
EXPAND_BASIC_STRUCT(0000); EXPAND_NORET_STRUCT(0001);
EXPAND_BASIC_STRUCT(0010); EXPAND_BASIC_STRUCT(0011);
EXPAND_BASIC_STRUCT(0100); EXPAND_NORET_STRUCT(0101);
EXPAND_NORET_STRUCT(0110); EXPAND_BASIC_STRUCT(0111);
EXPAND_BASIC_STRUCT(1000); EXPAND_NORET_STRUCT(1001);
EXPAND_BASIC_STRUCT(1010); EXPAND_BASIC_STRUCT(1011);
EXPAND_NORET_STRUCT(1100); EXPAND_NORET_STRUCT(1101);
EXPAND_BASIC_STRUCT(1110); EXPAND_BASIC_STRUCT(1111);
#define EXPAND_2_VARS(c, i, x) const X##i var_##c##_##i##0(x), &var_##c##_##i##1 = X##i(x)
#define EXPAND_4_VARS(c, i, x) EXPAND_2_VARS(c, i##0, x); EXPAND_2_VARS(c, i##1, x)
#define EXPAND_8_VARS(c, i, x) EXPAND_4_VARS(c, i##0, x); EXPAND_4_VARS(c, i##1, x)
#define EXPAND_16_VARS(c, i, x) EXPAND_8_VARS(c, i##0, x); EXPAND_8_VARS(c, i##1, x)
#define EXPAND_32_VARS(c, x) EXPAND_16_VARS(c, 0, x); EXPAND_16_VARS(c, 1, x)
#define EXPAND_2_INNER_CASES(i, x, y) INNER_CASE(i, x, y); INNER_CASE(i + 1, x, y);
#define EXPAND_4_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i + 2, x, y)
#define EXPAND_8_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i + 4, x, y)
#define EXPAND_16_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i + 8, x, y)
#define EXPAND_32_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i + 16, x, y)
#define EXPAND_2_OUTER_CASES(i, x, y) OUTER_CASE(i, x, y); OUTER_CASE(i + 1, x, y);
#define EXPAND_4_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i + 2, x, y)
#define EXPAND_8_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i + 4, x, y)
#define EXPAND_16_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i + 8, x, y)
#define EXPAND_32_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i + 16, x, y)
unsigned cfg_nested_vars(int x) {
int y = 0;
while (x > 0) {
EXPAND_32_VARS(a, x);
switch (x) {
#define INNER_CASE(i, x, y) \
case i: { \
int case_var = 3*x + i; \
EXPAND_32_VARS(c, case_var); \
y += case_var - 1; \
break; \
}
#define OUTER_CASE(i, x, y) \
case i: { \
int case_var = y >> 8; \
EXPAND_32_VARS(b, y); \
switch (case_var) { \
EXPAND_32_INNER_CASES(0, x, y); \
} \
break; \
}
EXPAND_32_OUTER_CASES(0, x, y);
}
--x;
}
return y;
}

View File

@ -1,5 +0,0 @@
// clang -I/usr/include/c++/4.0.0 -I/usr/include/c++/4.0.0/powerpc-apple-darwin8 -I/usr/include/c++/4.0.0/backward INPUTS/iostream.cc -Eonly
#include <iostream>
#include <stdint.h>

View File

@ -1,17 +0,0 @@
// This pounds on macro expansion for performance reasons. This is currently
// heavily constrained by darwin's malloc.
// Function-like macros.
#define A0(A, B) A B
#define A1(A, B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B)
#define A2(A, B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B)
#define A3(A, B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B)
#define A4(A, B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B)
#define A5(A, B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B)
#define A6(A, B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B)
#define A7(A, B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B)
#define A8(A, B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B)
A8(a, b)

View File

@ -1,16 +0,0 @@
// This pounds on macro expansion for performance reasons. This is currently
// heavily constrained by darwin's malloc.
// Object-like expansions
#define A0 a b
#define A1 A0 A0 A0 A0 A0 A0
#define A2 A1 A1 A1 A1 A1 A1
#define A3 A2 A2 A2 A2 A2 A2
#define A4 A3 A3 A3 A3 A3 A3
#define A5 A4 A4 A4 A4 A4 A4
#define A6 A5 A5 A5 A5 A5 A5
#define A7 A6 A6 A6 A6 A6 A6
#define A8 A7 A7 A7 A7 A7 A7
A8

View File

@ -1,47 +0,0 @@
#define __extension__
#define __stpcpy(dest, src) (__extension__ (__builtin_constant_p (src) ? (__string2_1bptr_p (src) && strlen (src) + 1 <= 8 ? __stpcpy_small (dest, __stpcpy_args (src), strlen (src) + 1) : ((char *) __mempcpy (dest, src, strlen (src) + 1) - 1)) : __stpcpy (dest, src)))
#define stpcpy(dest, src) __stpcpy (dest, src)
#define __stpcpy_args(src) __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
#define __mempcpy(dest, src, n) (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n) && __string2_1bptr_p (src) && n <= 8 ? __mempcpy_small (dest, __mempcpy_args (src), n) : __mempcpy (dest, src, n)))
#define mempcpy(dest, src, n) __mempcpy (dest, src, n)
#define __mempcpy_args(src) ((char *) (src))[0], ((char *) (src))[2], ((char *) (src))[4], ((char *) (src))[6], __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
#define __STRING2_SMALL_GET16(src, idx) (((__const unsigned char *) (__const char *) (src))[idx + 1] << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
#define __STRING2_SMALL_GET32(src, idx) (((((__const unsigned char *) (__const char *) (src))[idx + 3] << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 2]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 1]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)

View File

@ -1,48 +0,0 @@
//===----------------------------------------------------------------------===//
// Clang Installation Instructions
//===----------------------------------------------------------------------===//
These instructions describe how to build and install Clang.
//===----------------------------------------------------------------------===//
// Step 1: Organization
//===----------------------------------------------------------------------===//
Clang is designed to be built as part of an LLVM build. Assuming that the LLVM
source code is located at $LLVM_SRC_ROOT, then the clang source code should be
installed as:
$LLVM_SRC_ROOT/tools/clang
The directory is not required to be called clang, but doing so will allow the
LLVM build system to automatically recognize it and build it along with LLVM.
//===----------------------------------------------------------------------===//
// Step 2: Configure and Build LLVM
//===----------------------------------------------------------------------===//
Configure and build your copy of LLVM (see $LLVM_SRC_ROOT/GettingStarted.html
for more information).
Assuming you installed clang at $LLVM_SRC_ROOT/tools/clang then Clang will
automatically be built with LLVM. Otherwise, run 'make' in the Clang source
directory to build Clang.
//===----------------------------------------------------------------------===//
// Step 3: (Optional) Verify Your Build
//===----------------------------------------------------------------------===//
It is a good idea to run the Clang tests to make sure your build works
correctly. From inside the Clang build directory, run 'make test' to run the
tests.
//===----------------------------------------------------------------------===//
// Step 4: Install Clang
//===----------------------------------------------------------------------===//
From inside the Clang build directory, run 'make install' to install the Clang
compiler and header files into the prefix directory selected when LLVM was
configured.
The Clang compiler is available as 'clang' and 'clang++'. It supports a gcc like
command line interface. See the man page for clang for more information.

View File

@ -1,5 +0,0 @@
# This file provides information for llvm-top
DepModule: llvm
ConfigCmd:
ConfigTest:
BuildCmd:

104
NOTES.txt
View File

@ -1,104 +0,0 @@
//===---------------------------------------------------------------------===//
// Random Notes
//===---------------------------------------------------------------------===//
//===---------------------------------------------------------------------===//
To time GCC preprocessing speed without output, use:
"time gcc -MM file"
This is similar to -Eonly.
//===---------------------------------------------------------------------===//
C++ Template Instantiation benchmark:
http://users.rcn.com/abrahams/instantiation_speed/index.html
//===---------------------------------------------------------------------===//
TODO: File Manager Speedup:
We currently do a lot of stat'ing for files that don't exist, particularly
when lots of -I paths exist (e.g. see the <iostream> example, check for
failures in stat in FileManager::getFile). It would be far better to make
the following changes:
1. FileEntry contains a sys::Path instead of a std::string for Name.
2. sys::Path contains timestamp and size, lazily computed. Eliminate from
FileEntry.
3. File UIDs are created on request, not when files are opened.
These changes make it possible to efficiently have FileEntry objects for
files that exist on the file system, but have not been used yet.
Once this is done:
1. DirectoryEntry gets a boolean value "has read entries". When false, not
all entries in the directory are in the file mgr, when true, they are.
2. Instead of stat'ing the file in FileManager::getFile, check to see if
the dir has been read. If so, fail immediately, if not, read the dir,
then retry.
3. Reading the dir uses the getdirentries syscall, creating a FileEntry
for all files found.
//===---------------------------------------------------------------------===//
// Specifying targets: -triple and -arch
//===---------------------------------------------------------------------===//
The clang supports "-triple" and "-arch" options. At most one -triple and one
-arch option may be specified. Both are optional.
The "selection of target" behavior is defined as follows:
(1) If the user does not specify -triple, we default to the host triple.
(2) If the user specifies a -arch, that overrides the arch in the host or
specified triple.
//===---------------------------------------------------------------------===//
verifyInputConstraint and verifyOutputConstraint should not return bool.
Instead we should return something like:
enum VerifyConstraintResult {
Valid,
// Output only
OutputOperandConstraintLacksEqualsCharacter,
MatchingConstraintNotValidInOutputOperand,
// Input only
InputOperandConstraintContainsEqualsCharacter,
MatchingConstraintReferencesInvalidOperandNumber,
// Both
PercentConstraintUsedWithLastOperand
};
//===---------------------------------------------------------------------===//
Blocks should not capture variables that are only used in dead code.
The rule that we came up with is that blocks are required to capture
variables if they're referenced in evaluated code, even if that code
doesn't actually rely on the value of the captured variable.
For example, this requires a capture:
(void) var;
But this does not:
if (false) puts(var);
Summary of <rdar://problem/9851835>: if we implement this, we should
warn about non-POD variables that are referenced but not captured, but
only if the non-reachability is not due to macro or template
metaprogramming.
//===---------------------------------------------------------------------===//
We can still apply a modified version of the constructor/destructor
delegation optimization in cases of virtual inheritance where:
- there is no function-try-block,
- the constructor signature is not variadic, and
- the parameter variables can safely be copied and repassed
to the base constructor because either
- they have not had their addresses taken by the vbase initializers or
- they were passed indirectly.
//===---------------------------------------------------------------------===//

View File

@ -1,27 +0,0 @@
//===----------------------------------------------------------------------===//
// C Language Family Front-end
//===----------------------------------------------------------------------===//
Welcome to Clang. This is a compiler front-end for the C family of languages
(C, C++, Objective-C, and Objective-C++) which is built as part of the LLVM
compiler infrastructure project.
Unlike many other compiler frontends, Clang is useful for a number of things
beyond just compiling code: we intend for Clang to be host to a number of
different source-level tools. One example of this is the Clang Static Analyzer.
If you're interested in more (including how to build Clang) it is best to read
the relevant web sites. Here are some pointers:
Information on Clang: http://clang.llvm.org/
Building and using Clang: http://clang.llvm.org/get_started.html
Clang Static Analyzer: http://clang-analyzer.llvm.org/
Information on the LLVM project: http://llvm.org/
If you have questions or comments about Clang, a great place to discuss them is
on the Clang development mailing list:
http://lists.llvm.org/mailman/listinfo/cfe-dev
If you find a bug in Clang, please file it in the LLVM bug tracker:
http://llvm.org/bugs/

View File

@ -1,18 +0,0 @@
//===----------------------------------------------------------------------===//
// Clang Python Bindings
//===----------------------------------------------------------------------===//
This directory implements Python bindings for Clang.
You may need to set CLANG_LIBRARY_PATH so that the Clang library can be
found. The unit tests are designed to be run with any standard test
runner. For example:
--
$ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \
CLANG_LIBRARY_PATH=$(llvm-config --libdir) \
python -m unittest discover -v
tests.cindex.test_index.test_create ... ok
...
OK
--

View File

@ -1,24 +0,0 @@
#===- __init__.py - Clang Python Bindings --------------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
r"""
Clang Library Bindings
======================
This package provides access to the Clang compiler and libraries.
The available modules are:
cindex
Bindings for the Clang indexing library.
"""
__all__ = ['cindex']

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +0,0 @@
#===- enumerations.py - Python Enumerations ------------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
"""
Clang Enumerations
==================
This module provides static definitions of enumerations that exist in libclang.
Enumerations are typically defined as a list of tuples. The exported values are
typically munged into other types or classes at module load time.
All enumerations are centrally defined in this file so they are all grouped
together and easier to audit. And, maybe even one day this file will be
automatically generated by scanning the libclang headers!
"""
# Maps to CXTokenKind. Note that libclang maintains a separate set of token
# enumerations from the C++ API.
TokenKinds = [
('PUNCTUATION', 0),
('KEYWORD', 1),
('IDENTIFIER', 2),
('LITERAL', 3),
('COMMENT', 4),
]
__all__ = ['TokenKinds']

View File

@ -1,87 +0,0 @@
#!/usr/bin/env python
#===- cindex-dump.py - cindex/Python Source Dump -------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
"""
A simple command line tool for dumping a source file using the Clang Index
Library.
"""
def get_diag_info(diag):
return { 'severity' : diag.severity,
'location' : diag.location,
'spelling' : diag.spelling,
'ranges' : diag.ranges,
'fixits' : diag.fixits }
def get_cursor_id(cursor, cursor_list = []):
if not opts.showIDs:
return None
if cursor is None:
return None
# FIXME: This is really slow. It would be nice if the index API exposed
# something that let us hash cursors.
for i,c in enumerate(cursor_list):
if cursor == c:
return i
cursor_list.append(cursor)
return len(cursor_list) - 1
def get_info(node, depth=0):
if opts.maxDepth is not None and depth >= opts.maxDepth:
children = None
else:
children = [get_info(c, depth+1)
for c in node.get_children()]
return { 'id' : get_cursor_id(node),
'kind' : node.kind,
'usr' : node.get_usr(),
'spelling' : node.spelling,
'location' : node.location,
'extent.start' : node.extent.start,
'extent.end' : node.extent.end,
'is_definition' : node.is_definition(),
'definition id' : get_cursor_id(node.get_definition()),
'children' : children }
def main():
from clang.cindex import Index
from pprint import pprint
from optparse import OptionParser, OptionGroup
global opts
parser = OptionParser("usage: %prog [options] {filename} [clang-args*]")
parser.add_option("", "--show-ids", dest="showIDs",
help="Compute cursor IDs (very slow)",
action="store_true", default=False)
parser.add_option("", "--max-depth", dest="maxDepth",
help="Limit cursor expansion to depth N",
metavar="N", type=int, default=None)
parser.disable_interspersed_args()
(opts, args) = parser.parse_args()
if len(args) == 0:
parser.error('invalid number arguments')
index = Index.create()
tu = index.parse(None, args)
if not tu:
parser.error("unable to load input")
pprint(('diags', [get_diag_info(d) for d in tu.diagnostics]))
pprint(('nodes', get_info(tu.cursor)))
if __name__ == '__main__':
main()

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python
#===- cindex-includes.py - cindex/Python Inclusion Graph -----*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
"""
A simple command line tool for dumping a Graphviz description (dot) that
describes include dependencies.
"""
def main():
import sys
from clang.cindex import Index
from optparse import OptionParser, OptionGroup
parser = OptionParser("usage: %prog [options] {filename} [clang-args*]")
parser.disable_interspersed_args()
(opts, args) = parser.parse_args()
if len(args) == 0:
parser.error('invalid number arguments')
# FIXME: Add an output file option
out = sys.stdout
index = Index.create()
tu = index.parse(None, args)
if not tu:
parser.error("unable to load input")
# A helper function for generating the node name.
def name(f):
if f:
return "\"" + f.name + "\""
# Generate the include graph
out.write("digraph G {\n")
for i in tu.get_includes():
line = " ";
if i.is_input_file:
# Always write the input file as a node just in case it doesn't
# actually include anything. This would generate a 1 node graph.
line += name(i.include)
else:
line += '%s->%s' % (name(i.source), name(i.include))
line += "\n";
out.write(line)
out.write("}\n")
if __name__ == '__main__':
main()

View File

@ -1,46 +0,0 @@
# Test target to run Python test suite from main build.
add_custom_target(check-clang-python
COMMAND ${CMAKE_COMMAND} -E env
CLANG_LIBRARY_PATH=$<TARGET_FILE_DIR:libclang>
${PYTHON_EXECUTABLE} -m unittest discover
DEPENDS libclang
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..)
set(RUN_PYTHON_TESTS TRUE)
set_target_properties(check-clang-python PROPERTIES FOLDER "Clang tests")
# Tests require libclang.so which is only built with LLVM_ENABLE_PIC=ON
if(NOT LLVM_ENABLE_PIC)
set(RUN_PYTHON_TESTS FALSE)
endif()
# Do not try to run if libclang was built with ASan because
# the sanitizer library will likely be loaded too late to perform
# interception and will then fail.
# We could use LD_PRELOAD/DYLD_INSERT_LIBRARIES but this isn't
# portable so its easier just to not run the tests when building
# with ASan.
list(FIND LLVM_USE_SANITIZER "Address" LLVM_USE_ASAN_INDEX)
if(NOT LLVM_USE_ASAN_INDEX EQUAL -1)
set(RUN_PYTHON_TESTS FALSE)
endif()
# Tests fail on Windows, and need someone knowledgeable to fix.
# It's not clear whether it's a test or a valid binding problem.
if(WIN32)
set(RUN_PYTHON_TESTS FALSE)
endif()
# AArch64 and Hexagon have known test failures that need to be
# addressed.
# SystemZ has broken Python/FFI interface:
# https://reviews.llvm.org/D52840#1265716
if(${LLVM_NATIVE_ARCH} MATCHES "^(AArch64|Hexagon|SystemZ)$")
set(RUN_PYTHON_TESTS FALSE)
endif()
if(RUN_PYTHON_TESTS)
set_property(GLOBAL APPEND PROPERTY
LLVM_ADDITIONAL_TEST_TARGETS check-clang-python)
endif()

View File

@ -1,17 +0,0 @@
[
{
"directory": "/home/john.doe/MyProject",
"command": "clang++ -o project.o -c /home/john.doe/MyProject/project.cpp",
"file": "/home/john.doe/MyProject/project.cpp"
},
{
"directory": "/home/john.doe/MyProjectA",
"command": "clang++ -o project2.o -c /home/john.doe/MyProject/project2.cpp",
"file": "/home/john.doe/MyProject/project2.cpp"
},
{
"directory": "/home/john.doe/MyProjectB",
"command": "clang++ -DFEATURE=1 -o project2-feature.o -c /home/john.doe/MyProject/project2.cpp",
"file": "/home/john.doe/MyProject/project2.cpp"
}
]

View File

@ -1,6 +0,0 @@
#ifndef HEADER1
#define HEADER1
#include "header3.h"
#endif

View File

@ -1,6 +0,0 @@
#ifndef HEADER2
#define HEADER2
#include "header3.h"
#endif

View File

@ -1,3 +0,0 @@
// Not a guarded header!
void f();

View File

@ -1,6 +0,0 @@
#include "stdio.h"
int main(int argc, char* argv[]) {
printf("hello world\n");
return 0;
}

View File

@ -1,5 +0,0 @@
#include "header1.h"
#include "header2.h"
#include "header1.h"
int main() { }

View File

@ -1,2 +0,0 @@
int DECL_ONE = 1;
int DECL_TWO = 2;

View File

@ -1,41 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import AccessSpecifier
from clang.cindex import Cursor
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
import unittest
class TestAccessSpecifiers(unittest.TestCase):
def test_access_specifiers(self):
"""Ensure that C++ access specifiers are available on cursors"""
tu = get_tu("""
class test_class {
public:
void public_member_function();
protected:
void protected_member_function();
private:
void private_member_function();
};
""", lang = 'cpp')
test_class = get_cursor(tu, "test_class")
self.assertEqual(test_class.access_specifier, AccessSpecifier.INVALID)
public = get_cursor(tu.cursor, "public_member_function")
self.assertEqual(public.access_specifier, AccessSpecifier.PUBLIC)
protected = get_cursor(tu.cursor, "protected_member_function")
self.assertEqual(protected.access_specifier, AccessSpecifier.PROTECTED)
private = get_cursor(tu.cursor, "private_member_function")
self.assertEqual(private.access_specifier, AccessSpecifier.PRIVATE)

View File

@ -1,130 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import CompilationDatabase
from clang.cindex import CompilationDatabaseError
from clang.cindex import CompileCommands
from clang.cindex import CompileCommand
import os
import gc
import unittest
import sys
from .util import skip_if_no_fspath
from .util import str_to_path
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
@unittest.skipIf(sys.platform == 'win32', "TODO: Fix these tests on Windows")
class TestCDB(unittest.TestCase):
def test_create_fail(self):
"""Check we fail loading a database with an assertion"""
path = os.path.dirname(__file__)
with self.assertRaises(CompilationDatabaseError) as cm:
cdb = CompilationDatabase.fromDirectory(path)
e = cm.exception
self.assertEqual(e.cdb_error,
CompilationDatabaseError.ERROR_CANNOTLOADDATABASE)
def test_create(self):
"""Check we can load a compilation database"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
def test_lookup_succeed(self):
"""Check we get some results if the file exists in the db"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
self.assertNotEqual(len(cmds), 0)
@skip_if_no_fspath
def test_lookup_succeed_pathlike(self):
"""Same as test_lookup_succeed, but with PathLikes"""
cdb = CompilationDatabase.fromDirectory(str_to_path(kInputsDir))
cmds = cdb.getCompileCommands(str_to_path('/home/john.doe/MyProject/project.cpp'))
self.assertNotEqual(len(cmds), 0)
def test_all_compilecommand(self):
"""Check we get all results from the db"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getAllCompileCommands()
self.assertEqual(len(cmds), 3)
expected = [
{ 'wd': '/home/john.doe/MyProject',
'file': '/home/john.doe/MyProject/project.cpp',
'line': ['clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']},
{ 'wd': '/home/john.doe/MyProjectA',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-o', 'project2.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
{ 'wd': '/home/john.doe/MyProjectB',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
]
for i in range(len(cmds)):
self.assertEqual(cmds[i].directory, expected[i]['wd'])
self.assertEqual(cmds[i].filename, expected[i]['file'])
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
self.assertEqual(arg, exp)
def test_1_compilecommand(self):
"""Check file with single compile command"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
file = '/home/john.doe/MyProject/project.cpp'
cmds = cdb.getCompileCommands(file)
self.assertEqual(len(cmds), 1)
self.assertEqual(cmds[0].directory, os.path.dirname(file))
self.assertEqual(cmds[0].filename, file)
expected = [ 'clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']
for arg, exp in zip(cmds[0].arguments, expected):
self.assertEqual(arg, exp)
def test_2_compilecommand(self):
"""Check file with 2 compile commands"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
self.assertEqual(len(cmds), 2)
expected = [
{ 'wd': '/home/john.doe/MyProjectA',
'line': ['clang++', '-o', 'project2.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
{ 'wd': '/home/john.doe/MyProjectB',
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
'/home/john.doe/MyProject/project2.cpp']}
]
for i in range(len(cmds)):
self.assertEqual(cmds[i].directory, expected[i]['wd'])
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
self.assertEqual(arg, exp)
def test_compilecommand_iterator_stops(self):
"""Check that iterator stops after the correct number of elements"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
count = 0
for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
count += 1
self.assertLessEqual(count, 2)
def test_compilationDB_references(self):
"""Ensure CompilationsCommands are independent of the database"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
del cdb
gc.collect()
workingdir = cmds[0].directory
def test_compilationCommands_references(self):
"""Ensure CompilationsCommand keeps a reference to CompilationCommands"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
del cdb
cmd0 = cmds[0]
del cmds
gc.collect()
workingdir = cmd0.directory

View File

@ -1,112 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import TranslationUnit
import unittest
from .util import skip_if_no_fspath
from .util import str_to_path
class TestCodeCompletion(unittest.TestCase):
def check_completion_results(self, cr, expected):
self.assertIsNotNone(cr)
self.assertEqual(len(cr.diagnostics), 0)
completions = [str(c) for c in cr.results]
for c in expected:
self.assertIn(c, completions)
def test_code_complete(self):
files = [('fake.c', """
/// Aaa.
int test1;
/// Bbb.
void test2(void);
void f() {
}
""")]
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
expected = [
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)
@skip_if_no_fspath
def test_code_complete_pathlike(self):
files = [(str_to_path('fake.c'), """
/// Aaa.
int test1;
/// Bbb.
void test2(void);
void f() {
}
""")]
tu = TranslationUnit.from_source(str_to_path('fake.c'), ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
cr = tu.codeComplete(str_to_path('fake.c'), 9, 1, unsaved_files=files, include_brief_comments=True)
expected = [
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)
def test_code_complete_availability(self):
files = [('fake.cpp', """
class P {
protected:
int member;
};
class Q : public P {
public:
using P::member;
};
void f(P x, Q y) {
x.; // member is inaccessible
y.; // member is accessible
}
""")]
tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
expected = [
"{'const', TypedText} || Priority: 50 || Availability: Available || Brief comment: None",
"{'volatile', TypedText} || Priority: 50 || Availability: Available || Brief comment: None",
"{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'P', TypedText} || Priority: 50 || Availability: Available || Brief comment: None",
"{'Q', TypedText} || Priority: 50 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)
cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
expected = [
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None",
"{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
"{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)

View File

@ -1,47 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import TranslationUnit
from tests.cindex.util import get_cursor
import unittest
class TestComment(unittest.TestCase):
def test_comment(self):
files = [('fake.c', """
/// Aaa.
int test1;
/// Bbb.
/// x
void test2(void);
void f() {
}
""")]
# make a comment-aware TU
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
test1 = get_cursor(tu, 'test1')
self.assertIsNotNone(test1, "Could not find test1.")
self.assertTrue(test1.type.is_pod())
raw = test1.raw_comment
brief = test1.brief_comment
self.assertEqual(raw, """/// Aaa.""")
self.assertEqual(brief, """Aaa.""")
test2 = get_cursor(tu, 'test2')
raw = test2.raw_comment
brief = test2.brief_comment
self.assertEqual(raw, """/// Bbb.\n/// x""")
self.assertEqual(brief, """Bbb. x""")
f = get_cursor(tu, 'f')
raw = f.raw_comment
brief = f.brief_comment
self.assertIsNone(raw)
self.assertIsNone(brief)

View File

@ -1,569 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
import ctypes
import gc
import unittest
from clang.cindex import AvailabilityKind
from clang.cindex import CursorKind
from clang.cindex import TemplateArgumentKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
from .util import get_cursor
from .util import get_cursors
from .util import get_tu
kInput = """\
struct s0 {
int a;
int b;
};
struct s1;
void f0(int a0, int a1) {
int l0, l1;
if (a0)
return;
for (;;) {
break;
}
}
"""
kParentTest = """\
class C {
void f();
}
void C::f() { }
"""
kTemplateArgTest = """\
template <int kInt, typename T, bool kBool>
void foo();
template<>
void foo<-7, float, true>();
"""
class TestCursor(unittest.TestCase):
def test_get_children(self):
tu = get_tu(kInput)
it = tu.cursor.get_children()
tu_nodes = list(it)
self.assertEqual(len(tu_nodes), 3)
for cursor in tu_nodes:
self.assertIsNotNone(cursor.translation_unit)
self.assertNotEqual(tu_nodes[0], tu_nodes[1])
self.assertEqual(tu_nodes[0].kind, CursorKind.STRUCT_DECL)
self.assertEqual(tu_nodes[0].spelling, 's0')
self.assertEqual(tu_nodes[0].is_definition(), True)
self.assertEqual(tu_nodes[0].location.file.name, 't.c')
self.assertEqual(tu_nodes[0].location.line, 1)
self.assertEqual(tu_nodes[0].location.column, 8)
self.assertGreater(tu_nodes[0].hash, 0)
self.assertIsNotNone(tu_nodes[0].translation_unit)
s0_nodes = list(tu_nodes[0].get_children())
self.assertEqual(len(s0_nodes), 2)
self.assertEqual(s0_nodes[0].kind, CursorKind.FIELD_DECL)
self.assertEqual(s0_nodes[0].spelling, 'a')
self.assertEqual(s0_nodes[0].type.kind, TypeKind.INT)
self.assertEqual(s0_nodes[1].kind, CursorKind.FIELD_DECL)
self.assertEqual(s0_nodes[1].spelling, 'b')
self.assertEqual(s0_nodes[1].type.kind, TypeKind.INT)
self.assertEqual(tu_nodes[1].kind, CursorKind.STRUCT_DECL)
self.assertEqual(tu_nodes[1].spelling, 's1')
self.assertEqual(tu_nodes[1].displayname, 's1')
self.assertEqual(tu_nodes[1].is_definition(), False)
self.assertEqual(tu_nodes[2].kind, CursorKind.FUNCTION_DECL)
self.assertEqual(tu_nodes[2].spelling, 'f0')
self.assertEqual(tu_nodes[2].displayname, 'f0(int, int)')
self.assertEqual(tu_nodes[2].is_definition(), True)
def test_references(self):
"""Ensure that references to TranslationUnit are kept."""
tu = get_tu('int x;')
cursors = list(tu.cursor.get_children())
self.assertGreater(len(cursors), 0)
cursor = cursors[0]
self.assertIsInstance(cursor.translation_unit, TranslationUnit)
# Delete reference to TU and perform a full GC.
del tu
gc.collect()
self.assertIsInstance(cursor.translation_unit, TranslationUnit)
# If the TU was destroyed, this should cause a segfault.
parent = cursor.semantic_parent
def test_canonical(self):
source = 'struct X; struct X; struct X { int member; };'
tu = get_tu(source)
cursors = []
for cursor in tu.cursor.get_children():
if cursor.spelling == 'X':
cursors.append(cursor)
self.assertEqual(len(cursors), 3)
self.assertEqual(cursors[1].canonical, cursors[2].canonical)
def test_is_const_method(self):
"""Ensure Cursor.is_const_method works."""
source = 'class X { void foo() const; void bar(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_const_method())
self.assertFalse(bar.is_const_method())
def test_is_converting_constructor(self):
"""Ensure Cursor.is_converting_constructor works."""
source = 'class X { explicit X(int); X(double); X(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(len(xs), 4)
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_converting_constructor())
self.assertTrue(cs[1].is_converting_constructor())
self.assertFalse(cs[2].is_converting_constructor())
def test_is_copy_constructor(self):
"""Ensure Cursor.is_copy_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_copy_constructor())
self.assertTrue(cs[1].is_copy_constructor())
self.assertFalse(cs[2].is_copy_constructor())
def test_is_default_constructor(self):
"""Ensure Cursor.is_default_constructor works."""
source = 'class X { X(); X(int); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertTrue(cs[0].is_default_constructor())
self.assertFalse(cs[1].is_default_constructor())
def test_is_move_constructor(self):
"""Ensure Cursor.is_move_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_move_constructor())
self.assertFalse(cs[1].is_move_constructor())
self.assertTrue(cs[2].is_move_constructor())
def test_is_default_method(self):
"""Ensure Cursor.is_default_method works."""
source = 'class X { X() = default; }; class Y { Y(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
ys = get_cursors(tu, 'Y')
self.assertEqual(len(xs), 2)
self.assertEqual(len(ys), 2)
xc = xs[1]
yc = ys[1]
self.assertTrue(xc.is_default_method())
self.assertFalse(yc.is_default_method())
def test_is_mutable_field(self):
"""Ensure Cursor.is_mutable_field works."""
source = 'class X { int x_; mutable int y_; };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
x_ = get_cursor(tu, 'x_')
y_ = get_cursor(tu, 'y_')
self.assertIsNotNone(cls)
self.assertIsNotNone(x_)
self.assertIsNotNone(y_)
self.assertFalse(x_.is_mutable_field())
self.assertTrue(y_.is_mutable_field())
def test_is_static_method(self):
"""Ensure Cursor.is_static_method works."""
source = 'class X { static void foo(); void bar(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_static_method())
self.assertFalse(bar.is_static_method())
def test_is_pure_virtual_method(self):
"""Ensure Cursor.is_pure_virtual_method works."""
source = 'class X { virtual void foo() = 0; virtual void bar(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_pure_virtual_method())
self.assertFalse(bar.is_pure_virtual_method())
def test_is_virtual_method(self):
"""Ensure Cursor.is_virtual_method works."""
source = 'class X { virtual void foo(); void bar(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_virtual_method())
self.assertFalse(bar.is_virtual_method())
def test_is_abstract_record(self):
"""Ensure Cursor.is_abstract_record works."""
source = 'struct X { virtual void x() = 0; }; struct Y : X { void x(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
self.assertTrue(cls.is_abstract_record())
cls = get_cursor(tu, 'Y')
self.assertFalse(cls.is_abstract_record())
def test_is_scoped_enum(self):
"""Ensure Cursor.is_scoped_enum works."""
source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
regular_enum = get_cursor(tu, 'RegularEnum')
scoped_enum = get_cursor(tu, 'ScopedEnum')
self.assertIsNotNone(cls)
self.assertIsNotNone(regular_enum)
self.assertIsNotNone(scoped_enum)
self.assertFalse(cls.is_scoped_enum())
self.assertFalse(regular_enum.is_scoped_enum())
self.assertTrue(scoped_enum.is_scoped_enum())
def test_underlying_type(self):
tu = get_tu('typedef int foo;')
typedef = get_cursor(tu, 'foo')
self.assertIsNotNone(typedef)
self.assertTrue(typedef.kind.is_declaration())
underlying = typedef.underlying_typedef_type
self.assertEqual(underlying.kind, TypeKind.INT)
def test_semantic_parent(self):
tu = get_tu(kParentTest, 'cpp')
curs = get_cursors(tu, 'f')
decl = get_cursor(tu, 'C')
self.assertEqual(len(curs), 2)
self.assertEqual(curs[0].semantic_parent, curs[1].semantic_parent)
self.assertEqual(curs[0].semantic_parent, decl)
def test_lexical_parent(self):
tu = get_tu(kParentTest, 'cpp')
curs = get_cursors(tu, 'f')
decl = get_cursor(tu, 'C')
self.assertEqual(len(curs), 2)
self.assertNotEqual(curs[0].lexical_parent, curs[1].lexical_parent)
self.assertEqual(curs[0].lexical_parent, decl)
self.assertEqual(curs[1].lexical_parent, tu.cursor)
def test_enum_type(self):
tu = get_tu('enum TEST { FOO=1, BAR=2 };')
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_type = enum.enum_type
self.assertIn(enum_type.kind, (TypeKind.UINT, TypeKind.INT))
def test_enum_type_cpp(self):
tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
self.assertEqual(enum.enum_type.kind, TypeKind.LONGLONG)
def test_objc_type_encoding(self):
tu = get_tu('int i;', lang='objc')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
self.assertEqual(i.objc_type_encoding, 'i')
def test_enum_values(self):
tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_constants = list(enum.get_children())
self.assertEqual(len(enum_constants), 3)
spam, egg, ham = enum_constants
self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(spam.enum_value, 1)
self.assertEqual(egg.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(egg.enum_value, 2)
self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(ham.enum_value, 40)
def test_enum_values_cpp(self):
tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_constants = list(enum.get_children())
self.assertEqual(len(enum_constants), 2)
spam, ham = enum_constants
self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(spam.enum_value, -1)
self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(ham.enum_value, 0x10000000000)
def test_annotation_attribute(self):
tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
for c in foo.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
self.assertEqual(c.displayname, "here be annotation attribute")
break
else:
self.fail("Couldn't find annotation")
def test_annotation_template(self):
annotation = '__attribute__ ((annotate("annotation")))'
for source, kind in [
('int foo (T value) %s;', CursorKind.FUNCTION_TEMPLATE),
('class %s foo {};', CursorKind.CLASS_TEMPLATE),
]:
source = 'template<typename T> ' + (source % annotation)
tu = get_tu(source, lang="cpp")
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
self.assertEqual(foo.kind, kind)
for c in foo.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
self.assertEqual(c.displayname, "annotation")
break
else:
self.fail("Couldn't find annotation for {}".format(kind))
def test_result_type(self):
tu = get_tu('int foo();')
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
t = foo.result_type
self.assertEqual(t.kind, TypeKind.INT)
def test_result_type_objc_method_decl(self):
code = """\
@interface Interface : NSObject
-(void)voidMethod;
@end
"""
tu = get_tu(code, lang='objc')
cursor = get_cursor(tu, 'voidMethod')
result_type = cursor.result_type
self.assertEqual(cursor.kind, CursorKind.OBJC_INSTANCE_METHOD_DECL)
self.assertEqual(result_type.kind, TypeKind.VOID)
def test_availability(self):
tu = get_tu('class A { A(A const&) = delete; };', lang='cpp')
# AvailabilityKind.AVAILABLE
cursor = get_cursor(tu, 'A')
self.assertEqual(cursor.kind, CursorKind.CLASS_DECL)
self.assertEqual(cursor.availability, AvailabilityKind.AVAILABLE)
# AvailabilityKind.NOT_AVAILABLE
cursors = get_cursors(tu, 'A')
for c in cursors:
if c.kind == CursorKind.CONSTRUCTOR:
self.assertEqual(c.availability, AvailabilityKind.NOT_AVAILABLE)
break
else:
self.fail("Could not find cursor for deleted constructor")
# AvailabilityKind.DEPRECATED
tu = get_tu('void test() __attribute__((deprecated));', lang='cpp')
cursor = get_cursor(tu, 'test')
self.assertEqual(cursor.availability, AvailabilityKind.DEPRECATED)
# AvailabilityKind.NOT_ACCESSIBLE is only used in the code completion results
def test_get_tokens(self):
"""Ensure we can map cursors back to tokens."""
tu = get_tu('int foo(int i);')
foo = get_cursor(tu, 'foo')
tokens = list(foo.get_tokens())
self.assertEqual(len(tokens), 6)
self.assertEqual(tokens[0].spelling, 'int')
self.assertEqual(tokens[1].spelling, 'foo')
def test_get_token_cursor(self):
"""Ensure we can map tokens to cursors."""
tu = get_tu('class A {}; int foo(A var = A());', lang='cpp')
foo = get_cursor(tu, 'foo')
for cursor in foo.walk_preorder():
if cursor.kind.is_expression() and not cursor.kind.is_statement():
break
else:
self.fail("Could not find default value expression")
tokens = list(cursor.get_tokens())
self.assertEqual(len(tokens), 4, [t.spelling for t in tokens])
self.assertEqual(tokens[0].spelling, '=')
self.assertEqual(tokens[1].spelling, 'A')
self.assertEqual(tokens[2].spelling, '(')
self.assertEqual(tokens[3].spelling, ')')
t_cursor = tokens[1].cursor
self.assertEqual(t_cursor.kind, CursorKind.TYPE_REF)
r_cursor = t_cursor.referenced # should not raise an exception
self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL)
def test_get_arguments(self):
tu = get_tu('void foo(int i, int j);')
foo = get_cursor(tu, 'foo')
arguments = list(foo.get_arguments())
self.assertEqual(len(arguments), 2)
self.assertEqual(arguments[0].spelling, "i")
self.assertEqual(arguments[1].spelling, "j")
def test_get_num_template_arguments(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_num_template_arguments(), 3)
def test_get_template_argument_kind(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_kind(0), TemplateArgumentKind.INTEGRAL)
self.assertEqual(foos[1].get_template_argument_kind(1), TemplateArgumentKind.TYPE)
self.assertEqual(foos[1].get_template_argument_kind(2), TemplateArgumentKind.INTEGRAL)
def test_get_template_argument_type(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_type(1).kind, TypeKind.FLOAT)
def test_get_template_argument_value(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_value(0), -7)
self.assertEqual(foos[1].get_template_argument_value(2), True)
def test_get_template_argument_unsigned_value(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_unsigned_value(0), 2 ** 32 - 7)
self.assertEqual(foos[1].get_template_argument_unsigned_value(2), True)
def test_referenced(self):
tu = get_tu('void foo(); void bar() { foo(); }')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
for c in bar.get_children():
if c.kind == CursorKind.CALL_EXPR:
self.assertEqual(c.referenced.spelling, foo.spelling)
break
def test_mangled_name(self):
kInputForMangling = """\
int foo(int, int);
"""
tu = get_tu(kInputForMangling, lang='cpp')
foo = get_cursor(tu, 'foo')
# Since libclang does not link in targets, we cannot pass a triple to it
# and force the target. To enable this test to pass on all platforms, accept
# all valid manglings.
# [c-index-test handles this by running the source through clang, emitting
# an AST file and running libclang on that AST file]
self.assertIn(foo.mangled_name, ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH', '?foo@@YAHHH@Z'))

View File

@ -1,58 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import CursorKind
import unittest
class TestCursorKind(unittest.TestCase):
def test_name(self):
self.assertTrue(CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL')
def test_get_all_kinds(self):
kinds = CursorKind.get_all_kinds()
self.assertIn(CursorKind.UNEXPOSED_DECL, kinds)
self.assertIn(CursorKind.TRANSLATION_UNIT, kinds)
self.assertIn(CursorKind.VARIABLE_REF, kinds)
self.assertIn(CursorKind.LAMBDA_EXPR, kinds)
self.assertIn(CursorKind.OBJ_BOOL_LITERAL_EXPR, kinds)
self.assertIn(CursorKind.OBJ_SELF_EXPR, kinds)
self.assertIn(CursorKind.MS_ASM_STMT, kinds)
self.assertIn(CursorKind.MODULE_IMPORT_DECL, kinds)
self.assertIn(CursorKind.TYPE_ALIAS_TEMPLATE_DECL, kinds)
def test_kind_groups(self):
"""Check that every kind classifies to exactly one group."""
self.assertTrue(CursorKind.UNEXPOSED_DECL.is_declaration())
self.assertTrue(CursorKind.TYPE_REF.is_reference())
self.assertTrue(CursorKind.DECL_REF_EXPR.is_expression())
self.assertTrue(CursorKind.UNEXPOSED_STMT.is_statement())
self.assertTrue(CursorKind.INVALID_FILE.is_invalid())
self.assertTrue(CursorKind.TRANSLATION_UNIT.is_translation_unit())
self.assertFalse(CursorKind.TYPE_REF.is_translation_unit())
self.assertTrue(CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing())
self.assertFalse(CursorKind.TYPE_REF.is_preprocessing())
self.assertTrue(CursorKind.UNEXPOSED_DECL.is_unexposed())
self.assertFalse(CursorKind.TYPE_REF.is_unexposed())
for k in CursorKind.get_all_kinds():
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
'is_statement', 'is_invalid', 'is_attribute')
if getattr(k, n)()]
if k in ( CursorKind.TRANSLATION_UNIT,
CursorKind.MACRO_DEFINITION,
CursorKind.MACRO_INSTANTIATION,
CursorKind.INCLUSION_DIRECTIVE,
CursorKind.PREPROCESSING_DIRECTIVE,
CursorKind.OVERLOAD_CANDIDATE):
self.assertEqual(len(group), 0)
else:
self.assertEqual(len(group), 1)

View File

@ -1,110 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import *
from .util import get_tu
import unittest
# FIXME: We need support for invalid translation units to test better.
class TestDiagnostics(unittest.TestCase):
def test_diagnostic_warning(self):
tu = get_tu('int f0() {}\n')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 1)
self.assertEqual(tu.diagnostics[0].location.column, 11)
self.assertEqual(tu.diagnostics[0].spelling,
'control reaches end of non-void function')
def test_diagnostic_note(self):
# FIXME: We aren't getting notes here for some reason.
tu = get_tu('#define A x\nvoid *A = 1;\n')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 2)
self.assertEqual(tu.diagnostics[0].location.column, 7)
self.assertIn('incompatible', tu.diagnostics[0].spelling)
# self.assertEqual(tu.diagnostics[1].severity, Diagnostic.Note)
# self.assertEqual(tu.diagnostics[1].location.line, 1)
# self.assertEqual(tu.diagnostics[1].location.column, 11)
# self.assertEqual(tu.diagnostics[1].spelling, 'instantiated from')
def test_diagnostic_fixit(self):
tu = get_tu('struct { int f0; } x = { f0 : 1 };')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 1)
self.assertEqual(tu.diagnostics[0].location.column, 26)
self.assertRegexpMatches(tu.diagnostics[0].spelling,
'use of GNU old-style.*')
self.assertEqual(len(tu.diagnostics[0].fixits), 1)
self.assertEqual(tu.diagnostics[0].fixits[0].range.start.line, 1)
self.assertEqual(tu.diagnostics[0].fixits[0].range.start.column, 26)
self.assertEqual(tu.diagnostics[0].fixits[0].range.end.line, 1)
self.assertEqual(tu.diagnostics[0].fixits[0].range.end.column, 30)
self.assertEqual(tu.diagnostics[0].fixits[0].value, '.f0 = ')
def test_diagnostic_range(self):
tu = get_tu('void f() { int i = "a"; }')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 1)
self.assertEqual(tu.diagnostics[0].location.column, 16)
self.assertRegexpMatches(tu.diagnostics[0].spelling,
'incompatible pointer to.*')
self.assertEqual(len(tu.diagnostics[0].fixits), 0)
self.assertEqual(len(tu.diagnostics[0].ranges), 1)
self.assertEqual(tu.diagnostics[0].ranges[0].start.line, 1)
self.assertEqual(tu.diagnostics[0].ranges[0].start.column, 20)
self.assertEqual(tu.diagnostics[0].ranges[0].end.line, 1)
self.assertEqual(tu.diagnostics[0].ranges[0].end.column, 23)
with self.assertRaises(IndexError):
tu.diagnostics[0].ranges[1].start.line
def test_diagnostic_category(self):
"""Ensure that category properties work."""
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
self.assertEqual(d.severity, Diagnostic.Warning)
self.assertEqual(d.location.line, 1)
self.assertEqual(d.location.column, 11)
self.assertEqual(d.category_number, 2)
self.assertEqual(d.category_name, 'Semantic Issue')
def test_diagnostic_option(self):
"""Ensure that category option properties work."""
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
self.assertEqual(d.option, '-Wunused-parameter')
self.assertEqual(d.disable_option, '-Wno-unused-parameter')
def test_diagnostic_children(self):
tu = get_tu('void f(int x) {} void g() { f(); }')
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
children = d.children
self.assertEqual(len(children), 1)
self.assertEqual(children[0].severity, Diagnostic.Note)
self.assertRegexpMatches(children[0].spelling,
'.*declared here')
self.assertEqual(children[0].location.line, 1)
self.assertEqual(children[0].location.column, 1)
def test_diagnostic_string_repr(self):
tu = get_tu('struct MissingSemicolon{}')
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
self.assertEqual(repr(d), '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">')

View File

@ -1,35 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
import clang.cindex
from clang.cindex import ExceptionSpecificationKind
from .util import get_tu
import unittest
def find_function_declarations(node, declarations=[]):
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
declarations.append((node.spelling, node.exception_specification_kind))
for child in node.get_children():
declarations = find_function_declarations(child, declarations)
return declarations
class TestExceptionSpecificationKind(unittest.TestCase):
def test_exception_specification_kind(self):
source = """int square1(int x);
int square2(int x) noexcept;
int square3(int x) noexcept(noexcept(x * x));"""
tu = get_tu(source, lang='cpp', flags=['-std=c++14'])
declarations = find_function_declarations(tu.cursor)
expected = [
('square1', ExceptionSpecificationKind.NONE),
('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT),
('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT)
]
self.assertListEqual(declarations, expected)

View File

@ -1,18 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import Index, File
import unittest
class TestFile(unittest.TestCase):
def test_file(self):
index = Index.create()
tu = index.parse('t.c', unsaved_files = [('t.c', "")])
file = File.from_name(tu, "t.c")
self.assertEqual(str(file), "t.c")
self.assertEqual(file.name, "t.c")
self.assertEqual(repr(file), "<File: t.c>")

View File

@ -1,26 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import *
import os
import unittest
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
class TestIndex(unittest.TestCase):
def test_create(self):
index = Index.create()
# FIXME: test Index.read
def test_parse(self):
index = Index.create()
self.assertIsInstance(index, Index)
tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
self.assertIsInstance(tu, TranslationUnit)
tu = index.parse(None, ['-c', os.path.join(kInputsDir, 'hello.cpp')])
self.assertIsInstance(tu, TranslationUnit)

View File

@ -1,38 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import LinkageKind
from clang.cindex import Cursor
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
import unittest
class TestLinkage(unittest.TestCase):
def test_linkage(self):
"""Ensure that linkage specifers are available on cursors"""
tu = get_tu("""
void foo() { int no_linkage; }
static int internal;
namespace { struct unique_external_type {} }
unique_external_type unique_external;
extern int external;
""", lang = 'cpp')
no_linkage = get_cursor(tu.cursor, 'no_linkage')
self.assertEqual(no_linkage.linkage, LinkageKind.NO_LINKAGE)
internal = get_cursor(tu.cursor, 'internal')
self.assertEqual(internal.linkage, LinkageKind.INTERNAL)
unique_external = get_cursor(tu.cursor, 'unique_external')
self.assertEqual(unique_external.linkage, LinkageKind.UNIQUE_EXTERNAL)
external = get_cursor(tu.cursor, 'external')
self.assertEqual(external.linkage, LinkageKind.EXTERNAL)

View File

@ -1,105 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import Cursor
from clang.cindex import File
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from .util import get_cursor
from .util import get_tu
import unittest
baseInput="int one;\nint two;\n"
class TestLocation(unittest.TestCase):
def assert_location(self, loc, line, column, offset):
self.assertEqual(loc.line, line)
self.assertEqual(loc.column, column)
self.assertEqual(loc.offset, offset)
def test_location(self):
tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
self.assertIsNotNone(one)
self.assertIsNotNone(two)
self.assert_location(one.location,line=1,column=5,offset=4)
self.assert_location(two.location,line=2,column=5,offset=13)
# adding a linebreak at top should keep columns same
tu = get_tu('\n' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
self.assertIsNotNone(one)
self.assertIsNotNone(two)
self.assert_location(one.location,line=2,column=5,offset=5)
self.assert_location(two.location,line=3,column=5,offset=14)
# adding a space should affect column on first line only
tu = get_tu(' ' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
self.assert_location(one.location,line=1,column=6,offset=5)
self.assert_location(two.location,line=2,column=5,offset=14)
# define the expected location ourselves and see if it matches
# the returned location
tu = get_tu(baseInput)
file = File.from_name(tu, 't.c')
location = SourceLocation.from_position(tu, file, 1, 5)
cursor = Cursor.from_location(tu, location)
one = get_cursor(tu, 'one')
self.assertIsNotNone(one)
self.assertEqual(one, cursor)
# Ensure locations referring to the same entity are equivalent.
location2 = SourceLocation.from_position(tu, file, 1, 5)
self.assertEqual(location, location2)
location3 = SourceLocation.from_position(tu, file, 1, 4)
self.assertNotEqual(location2, location3)
offset_location = SourceLocation.from_offset(tu, file, 5)
cursor = Cursor.from_location(tu, offset_location)
verified = False
for n in [n for n in tu.cursor.get_children() if n.spelling == 'one']:
self.assertEqual(n, cursor)
verified = True
self.assertTrue(verified)
def test_extent(self):
tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
self.assert_location(one.extent.start,line=1,column=1,offset=0)
self.assert_location(one.extent.end,line=1,column=8,offset=7)
self.assertEqual(baseInput[one.extent.start.offset:one.extent.end.offset], "int one")
self.assert_location(two.extent.start,line=2,column=1,offset=9)
self.assert_location(two.extent.end,line=2,column=8,offset=16)
self.assertEqual(baseInput[two.extent.start.offset:two.extent.end.offset], "int two")
file = File.from_name(tu, 't.c')
location1 = SourceLocation.from_position(tu, file, 1, 1)
location2 = SourceLocation.from_position(tu, file, 1, 8)
range1 = SourceRange.from_locations(location1, location2)
range2 = SourceRange.from_locations(location1, location2)
self.assertEqual(range1, range2)
location3 = SourceLocation.from_position(tu, file, 1, 6)
range3 = SourceRange.from_locations(location1, location3)
self.assertNotEqual(range1, range3)

View File

@ -1,54 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import TLSKind
from clang.cindex import Cursor
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
import unittest
class TestTLSKind(unittest.TestCase):
def test_tls_kind(self):
"""Ensure that thread-local storage kinds are available on cursors."""
tu = get_tu("""
int tls_none;
thread_local int tls_dynamic;
_Thread_local int tls_static;
""", lang = 'cpp')
tls_none = get_cursor(tu.cursor, 'tls_none')
self.assertEqual(tls_none.tls_kind, TLSKind.NONE)
tls_dynamic = get_cursor(tu.cursor, 'tls_dynamic')
self.assertEqual(tls_dynamic.tls_kind, TLSKind.DYNAMIC)
tls_static = get_cursor(tu.cursor, 'tls_static')
self.assertEqual(tls_static.tls_kind, TLSKind.STATIC)
# The following case tests '__declspec(thread)'. Since it is a Microsoft
# specific extension, specific flags are required for the parser to pick
# these up.
flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32',
'-fms-compatibility-version=18']
tu = get_tu("""
__declspec(thread) int tls_declspec_msvc18;
""", lang = 'cpp', flags=flags)
tls_declspec_msvc18 = get_cursor(tu.cursor, 'tls_declspec_msvc18')
self.assertEqual(tls_declspec_msvc18.tls_kind, TLSKind.STATIC)
flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32',
'-fms-compatibility-version=19']
tu = get_tu("""
__declspec(thread) int tls_declspec_msvc19;
""", lang = 'cpp', flags=flags)
tls_declspec_msvc19 = get_cursor(tu.cursor, 'tls_declspec_msvc19')
self.assertEqual(tls_declspec_msvc19.tls_kind, TLSKind.DYNAMIC)

View File

@ -1,49 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import TokenKind
import unittest
class TestTokenKind(unittest.TestCase):
def test_constructor(self):
"""Ensure TokenKind constructor works as expected."""
t = TokenKind(5, 'foo')
self.assertEqual(t.value, 5)
self.assertEqual(t.name, 'foo')
def test_bad_register(self):
"""Ensure a duplicate value is rejected for registration."""
with self.assertRaises(ValueError):
TokenKind.register(2, 'foo')
def test_unknown_value(self):
"""Ensure trying to fetch an unknown value raises."""
with self.assertRaises(ValueError):
TokenKind.from_value(-1)
def test_registration(self):
"""Ensure that items registered appear as class attributes."""
self.assertTrue(hasattr(TokenKind, 'LITERAL'))
literal = TokenKind.LITERAL
self.assertIsInstance(literal, TokenKind)
def test_from_value(self):
"""Ensure registered values can be obtained from from_value()."""
t = TokenKind.from_value(3)
self.assertIsInstance(t, TokenKind)
self.assertEqual(t, TokenKind.LITERAL)
def test_repr(self):
"""Ensure repr() works."""
r = repr(TokenKind.LITERAL)
self.assertEqual(r, 'TokenKind.LITERAL')

View File

@ -1,59 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from clang.cindex import CursorKind
from clang.cindex import Index
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from clang.cindex import TokenKind
from .util import get_tu
import unittest
class TestTokens(unittest.TestCase):
def test_token_to_cursor(self):
"""Ensure we can obtain a Cursor from a Token instance."""
tu = get_tu('int i = 5;')
r = tu.get_extent('t.c', (0, 9))
tokens = list(tu.get_tokens(extent=r))
self.assertEqual(len(tokens), 4)
self.assertEqual(tokens[1].spelling, 'i')
self.assertEqual(tokens[1].kind, TokenKind.IDENTIFIER)
cursor = tokens[1].cursor
self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
self.assertEqual(tokens[1].cursor, tokens[2].cursor)
def test_token_location(self):
"""Ensure Token.location works."""
tu = get_tu('int foo = 10;')
r = tu.get_extent('t.c', (0, 11))
tokens = list(tu.get_tokens(extent=r))
self.assertEqual(len(tokens), 4)
loc = tokens[1].location
self.assertIsInstance(loc, SourceLocation)
self.assertEqual(loc.line, 1)
self.assertEqual(loc.column, 5)
self.assertEqual(loc.offset, 4)
def test_token_extent(self):
"""Ensure Token.extent works."""
tu = get_tu('int foo = 10;')
r = tu.get_extent('t.c', (0, 11))
tokens = list(tu.get_tokens(extent=r))
self.assertEqual(len(tokens), 4)
extent = tokens[1].extent
self.assertIsInstance(extent, SourceRange)
self.assertEqual(extent.start.offset, 4)
self.assertEqual(extent.end.offset, 7)

View File

@ -1,338 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
from contextlib import contextmanager
import gc
import os
import sys
import tempfile
import unittest
from clang.cindex import CursorKind
from clang.cindex import Cursor
from clang.cindex import File
from clang.cindex import Index
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from clang.cindex import TranslationUnitSaveError
from clang.cindex import TranslationUnitLoadError
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
from .util import skip_if_no_fspath
from .util import str_to_path
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
@contextmanager
def save_tu(tu):
"""Convenience API to save a TranslationUnit to a file.
Returns the filename it was saved to.
"""
with tempfile.NamedTemporaryFile() as t:
tu.save(t.name)
yield t.name
@contextmanager
def save_tu_pathlike(tu):
"""Convenience API to save a TranslationUnit to a file.
Returns the filename it was saved to.
"""
with tempfile.NamedTemporaryFile() as t:
tu.save(str_to_path(t.name))
yield t.name
class TestTranslationUnit(unittest.TestCase):
def test_spelling(self):
path = os.path.join(kInputsDir, 'hello.cpp')
tu = TranslationUnit.from_source(path)
self.assertEqual(tu.spelling, path)
def test_cursor(self):
path = os.path.join(kInputsDir, 'hello.cpp')
tu = get_tu(path)
c = tu.cursor
self.assertIsInstance(c, Cursor)
self.assertIs(c.kind, CursorKind.TRANSLATION_UNIT)
def test_parse_arguments(self):
path = os.path.join(kInputsDir, 'parse_arguments.c')
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-2], 'hello')
self.assertEqual(spellings[-1], 'hi')
def test_reparse_arguments(self):
path = os.path.join(kInputsDir, 'parse_arguments.c')
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
tu.reparse()
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-2], 'hello')
self.assertEqual(spellings[-1], 'hi')
def test_unsaved_files(self):
tu = TranslationUnit.from_source('fake.c', ['-I./'], unsaved_files = [
('fake.c', """
#include "fake.h"
int x;
int SOME_DEFINE;
"""),
('./fake.h', """
#define SOME_DEFINE y
""")
])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-2], 'x')
self.assertEqual(spellings[-1], 'y')
def test_unsaved_files_2(self):
if sys.version_info.major >= 3:
from io import StringIO
else:
from io import BytesIO as StringIO
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
('fake.c', StringIO('int x;'))])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-1], 'x')
@skip_if_no_fspath
def test_from_source_accepts_pathlike(self):
tu = TranslationUnit.from_source(str_to_path('fake.c'), ['-Iincludes'], unsaved_files = [
(str_to_path('fake.c'), """
#include "fake.h"
int x;
int SOME_DEFINE;
"""),
(str_to_path('includes/fake.h'), """
#define SOME_DEFINE y
""")
])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-2], 'x')
self.assertEqual(spellings[-1], 'y')
def assert_normpaths_equal(self, path1, path2):
""" Compares two paths for equality after normalizing them with
os.path.normpath
"""
self.assertEqual(os.path.normpath(path1),
os.path.normpath(path2))
def test_includes(self):
def eq(expected, actual):
if not actual.is_input_file:
self.assert_normpaths_equal(expected[0], actual.source.name)
self.assert_normpaths_equal(expected[1], actual.include.name)
else:
self.assert_normpaths_equal(expected[1], actual.include.name)
src = os.path.join(kInputsDir, 'include.cpp')
h1 = os.path.join(kInputsDir, "header1.h")
h2 = os.path.join(kInputsDir, "header2.h")
h3 = os.path.join(kInputsDir, "header3.h")
inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)]
tu = TranslationUnit.from_source(src)
for i in zip(inc, tu.get_includes()):
eq(i[0], i[1])
def test_inclusion_directive(self):
src = os.path.join(kInputsDir, 'include.cpp')
h1 = os.path.join(kInputsDir, "header1.h")
h2 = os.path.join(kInputsDir, "header2.h")
h3 = os.path.join(kInputsDir, "header3.h")
inc = [h1, h3, h2, h3, h1]
tu = TranslationUnit.from_source(src, options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD)
inclusion_directive_files = [c.get_included_file().name for c in tu.cursor.get_children() if c.kind == CursorKind.INCLUSION_DIRECTIVE]
for i in zip(inc, inclusion_directive_files):
self.assert_normpaths_equal(i[0], i[1])
def test_save(self):
"""Ensure TranslationUnit.save() works."""
tu = get_tu('int foo();')
with save_tu(tu) as path:
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)
@skip_if_no_fspath
def test_save_pathlike(self):
"""Ensure TranslationUnit.save() works with PathLike filename."""
tu = get_tu('int foo();')
with save_tu_pathlike(tu) as path:
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)
def test_save_translation_errors(self):
"""Ensure that saving to an invalid directory raises."""
tu = get_tu('int foo();')
path = '/does/not/exist/llvm-test.ast'
self.assertFalse(os.path.exists(os.path.dirname(path)))
with self.assertRaises(TranslationUnitSaveError) as cm:
tu.save(path)
ex = cm.exception
expected = TranslationUnitSaveError.ERROR_UNKNOWN
self.assertEqual(ex.save_error, expected)
def test_load(self):
"""Ensure TranslationUnits can be constructed from saved files."""
tu = get_tu('int foo();')
self.assertEqual(len(tu.diagnostics), 0)
with save_tu(tu) as path:
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)
tu2 = TranslationUnit.from_ast_file(filename=path)
self.assertEqual(len(tu2.diagnostics), 0)
foo = get_cursor(tu2, 'foo')
self.assertIsNotNone(foo)
# Just in case there is an open file descriptor somewhere.
del tu2
@skip_if_no_fspath
def test_load_pathlike(self):
"""Ensure TranslationUnits can be constructed from saved files -
PathLike variant."""
tu = get_tu('int foo();')
self.assertEqual(len(tu.diagnostics), 0)
with save_tu(tu) as path:
tu2 = TranslationUnit.from_ast_file(filename=str_to_path(path))
self.assertEqual(len(tu2.diagnostics), 0)
foo = get_cursor(tu2, 'foo')
self.assertIsNotNone(foo)
# Just in case there is an open file descriptor somewhere.
del tu2
def test_index_parse(self):
path = os.path.join(kInputsDir, 'hello.cpp')
index = Index.create()
tu = index.parse(path)
self.assertIsInstance(tu, TranslationUnit)
def test_get_file(self):
"""Ensure tu.get_file() works appropriately."""
tu = get_tu('int foo();')
f = tu.get_file('t.c')
self.assertIsInstance(f, File)
self.assertEqual(f.name, 't.c')
with self.assertRaises(Exception):
f = tu.get_file('foobar.cpp')
@skip_if_no_fspath
def test_get_file_pathlike(self):
"""Ensure tu.get_file() works appropriately with PathLike filenames."""
tu = get_tu('int foo();')
f = tu.get_file(str_to_path('t.c'))
self.assertIsInstance(f, File)
self.assertEqual(f.name, 't.c')
with self.assertRaises(Exception):
f = tu.get_file(str_to_path('foobar.cpp'))
def test_get_source_location(self):
"""Ensure tu.get_source_location() works."""
tu = get_tu('int foo();')
location = tu.get_location('t.c', 2)
self.assertIsInstance(location, SourceLocation)
self.assertEqual(location.offset, 2)
self.assertEqual(location.file.name, 't.c')
location = tu.get_location('t.c', (1, 3))
self.assertIsInstance(location, SourceLocation)
self.assertEqual(location.line, 1)
self.assertEqual(location.column, 3)
self.assertEqual(location.file.name, 't.c')
def test_get_source_range(self):
"""Ensure tu.get_source_range() works."""
tu = get_tu('int foo();')
r = tu.get_extent('t.c', (1,4))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.offset, 1)
self.assertEqual(r.end.offset, 4)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(r.end.file.name, 't.c')
r = tu.get_extent('t.c', ((1,2), (1,3)))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.line, 1)
self.assertEqual(r.start.column, 2)
self.assertEqual(r.end.line, 1)
self.assertEqual(r.end.column, 3)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(r.end.file.name, 't.c')
start = tu.get_location('t.c', 0)
end = tu.get_location('t.c', 5)
r = tu.get_extent('t.c', (start, end))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.offset, 0)
self.assertEqual(r.end.offset, 5)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(r.end.file.name, 't.c')
def test_get_tokens_gc(self):
"""Ensures get_tokens() works properly with garbage collection."""
tu = get_tu('int foo();')
r = tu.get_extent('t.c', (0, 10))
tokens = list(tu.get_tokens(extent=r))
self.assertEqual(tokens[0].spelling, 'int')
gc.collect()
self.assertEqual(tokens[0].spelling, 'int')
del tokens[1]
gc.collect()
self.assertEqual(tokens[0].spelling, 'int')
# May trigger segfault if we don't do our job properly.
del tokens
gc.collect()
gc.collect() # Just in case.
def test_fail_from_source(self):
path = os.path.join(kInputsDir, 'non-existent.cpp')
try:
tu = TranslationUnit.from_source(path)
except TranslationUnitLoadError:
tu = None
self.assertEqual(tu, None)
def test_fail_from_ast_file(self):
path = os.path.join(kInputsDir, 'non-existent.ast')
try:
tu = TranslationUnit.from_ast_file(path)
except TranslationUnitLoadError:
tu = None
self.assertEqual(tu, None)

View File

@ -1,468 +0,0 @@
import os
from clang.cindex import Config
if 'CLANG_LIBRARY_PATH' in os.environ:
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
import gc
import unittest
from clang.cindex import CursorKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
from .util import get_cursor
from .util import get_tu
kInput = """\
typedef int I;
struct teststruct {
int a;
I b;
long c;
unsigned long d;
signed long e;
const int f;
int *g;
int ***h;
};
"""
constarrayInput="""
struct teststruct {
void *A[2];
};
"""
class TestType(unittest.TestCase):
def test_a_struct(self):
tu = get_tu(kInput)
teststruct = get_cursor(tu, 'teststruct')
self.assertIsNotNone(teststruct, "Could not find teststruct.")
fields = list(teststruct.get_children())
self.assertEqual(fields[0].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[0].translation_unit)
self.assertEqual(fields[0].spelling, 'a')
self.assertFalse(fields[0].type.is_const_qualified())
self.assertEqual(fields[0].type.kind, TypeKind.INT)
self.assertEqual(fields[0].type.get_canonical().kind, TypeKind.INT)
self.assertEqual(fields[0].type.get_typedef_name(), '')
self.assertEqual(fields[1].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[1].translation_unit)
self.assertEqual(fields[1].spelling, 'b')
self.assertFalse(fields[1].type.is_const_qualified())
self.assertEqual(fields[1].type.kind, TypeKind.TYPEDEF)
self.assertEqual(fields[1].type.get_canonical().kind, TypeKind.INT)
self.assertEqual(fields[1].type.get_declaration().spelling, 'I')
self.assertEqual(fields[1].type.get_typedef_name(), 'I')
self.assertEqual(fields[2].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[2].translation_unit)
self.assertEqual(fields[2].spelling, 'c')
self.assertFalse(fields[2].type.is_const_qualified())
self.assertEqual(fields[2].type.kind, TypeKind.LONG)
self.assertEqual(fields[2].type.get_canonical().kind, TypeKind.LONG)
self.assertEqual(fields[2].type.get_typedef_name(), '')
self.assertEqual(fields[3].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[3].translation_unit)
self.assertEqual(fields[3].spelling, 'd')
self.assertFalse(fields[3].type.is_const_qualified())
self.assertEqual(fields[3].type.kind, TypeKind.ULONG)
self.assertEqual(fields[3].type.get_canonical().kind, TypeKind.ULONG)
self.assertEqual(fields[3].type.get_typedef_name(), '')
self.assertEqual(fields[4].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[4].translation_unit)
self.assertEqual(fields[4].spelling, 'e')
self.assertFalse(fields[4].type.is_const_qualified())
self.assertEqual(fields[4].type.kind, TypeKind.LONG)
self.assertEqual(fields[4].type.get_canonical().kind, TypeKind.LONG)
self.assertEqual(fields[4].type.get_typedef_name(), '')
self.assertEqual(fields[5].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[5].translation_unit)
self.assertEqual(fields[5].spelling, 'f')
self.assertTrue(fields[5].type.is_const_qualified())
self.assertEqual(fields[5].type.kind, TypeKind.INT)
self.assertEqual(fields[5].type.get_canonical().kind, TypeKind.INT)
self.assertEqual(fields[5].type.get_typedef_name(), '')
self.assertEqual(fields[6].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[6].translation_unit)
self.assertEqual(fields[6].spelling, 'g')
self.assertFalse(fields[6].type.is_const_qualified())
self.assertEqual(fields[6].type.kind, TypeKind.POINTER)
self.assertEqual(fields[6].type.get_pointee().kind, TypeKind.INT)
self.assertEqual(fields[6].type.get_typedef_name(), '')
self.assertEqual(fields[7].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[7].translation_unit)
self.assertEqual(fields[7].spelling, 'h')
self.assertFalse(fields[7].type.is_const_qualified())
self.assertEqual(fields[7].type.kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().get_pointee().kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().get_pointee().get_pointee().kind, TypeKind.INT)
self.assertEqual(fields[7].type.get_typedef_name(), '')
def test_references(self):
"""Ensure that a Type maintains a reference to a TranslationUnit."""
tu = get_tu('int x;')
children = list(tu.cursor.get_children())
self.assertGreater(len(children), 0)
cursor = children[0]
t = cursor.type
self.assertIsInstance(t.translation_unit, TranslationUnit)
# Delete main TranslationUnit reference and force a GC.
del tu
gc.collect()
self.assertIsInstance(t.translation_unit, TranslationUnit)
# If the TU was destroyed, this should cause a segfault.
decl = t.get_declaration()
def testConstantArray(self):
tu = get_tu(constarrayInput)
teststruct = get_cursor(tu, 'teststruct')
self.assertIsNotNone(teststruct, "Didn't find teststruct??")
fields = list(teststruct.get_children())
self.assertEqual(fields[0].spelling, 'A')
self.assertEqual(fields[0].type.kind, TypeKind.CONSTANTARRAY)
self.assertIsNotNone(fields[0].type.get_array_element_type())
self.assertEqual(fields[0].type.get_array_element_type().kind, TypeKind.POINTER)
self.assertEqual(fields[0].type.get_array_size(), 2)
def test_equal(self):
"""Ensure equivalence operators work on Type."""
source = 'int a; int b; void *v;'
tu = get_tu(source)
a = get_cursor(tu, 'a')
b = get_cursor(tu, 'b')
v = get_cursor(tu, 'v')
self.assertIsNotNone(a)
self.assertIsNotNone(b)
self.assertIsNotNone(v)
self.assertEqual(a.type, b.type)
self.assertNotEqual(a.type, v.type)
self.assertNotEqual(a.type, None)
self.assertNotEqual(a.type, 'foo')
def test_type_spelling(self):
"""Ensure Type.spelling works."""
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
x = get_cursor(tu, 'x')
v = get_cursor(tu, 'v')
self.assertIsNotNone(c)
self.assertIsNotNone(i)
self.assertIsNotNone(x)
self.assertIsNotNone(v)
self.assertEqual(c.type.spelling, "int [5]")
self.assertEqual(i.type.spelling, "int []")
self.assertEqual(x.type.spelling, "int")
self.assertEqual(v.type.spelling, "int [x]")
def test_typekind_spelling(self):
"""Ensure TypeKind.spelling works."""
tu = get_tu('int a;')
a = get_cursor(tu, 'a')
self.assertIsNotNone(a)
self.assertEqual(a.type.kind.spelling, 'Int')
def test_function_argument_types(self):
"""Ensure that Type.argument_types() works as expected."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
self.assertIsNotNone(f)
args = f.type.argument_types()
self.assertIsNotNone(args)
self.assertEqual(len(args), 2)
t0 = args[0]
self.assertIsNotNone(t0)
self.assertEqual(t0.kind, TypeKind.INT)
t1 = args[1]
self.assertIsNotNone(t1)
self.assertEqual(t1.kind, TypeKind.INT)
args2 = list(args)
self.assertEqual(len(args2), 2)
self.assertEqual(t0, args2[0])
self.assertEqual(t1, args2[1])
def test_argument_types_string_key(self):
"""Ensure that non-int keys raise a TypeError."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
self.assertIsNotNone(f)
args = f.type.argument_types()
self.assertEqual(len(args), 2)
with self.assertRaises(TypeError):
args['foo']
def test_argument_types_negative_index(self):
"""Ensure that negative indexes on argument_types Raises an IndexError."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
args = f.type.argument_types()
with self.assertRaises(IndexError):
args[-1]
def test_argument_types_overflow_index(self):
"""Ensure that indexes beyond the length of Type.argument_types() raise."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
args = f.type.argument_types()
with self.assertRaises(IndexError):
args[2]
def test_argument_types_invalid_type(self):
"""Ensure that obtaining argument_types on a Type without them raises."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
with self.assertRaises(Exception):
i.type.argument_types()
def test_is_pod(self):
"""Ensure Type.is_pod() works."""
tu = get_tu('int i; void f();')
i = get_cursor(tu, 'i')
f = get_cursor(tu, 'f')
self.assertIsNotNone(i)
self.assertIsNotNone(f)
self.assertTrue(i.type.is_pod())
self.assertFalse(f.type.is_pod())
def test_function_variadic(self):
"""Ensure Type.is_function_variadic works."""
source ="""
#include <stdarg.h>
void foo(int a, ...);
void bar(int a, int b);
"""
tu = get_tu(source)
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertIsInstance(foo.type.is_function_variadic(), bool)
self.assertTrue(foo.type.is_function_variadic())
self.assertFalse(bar.type.is_function_variadic())
def test_element_type(self):
"""Ensure Type.element_type works."""
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
v = get_cursor(tu, 'v')
self.assertIsNotNone(c)
self.assertIsNotNone(i)
self.assertIsNotNone(v)
self.assertEqual(c.type.kind, TypeKind.CONSTANTARRAY)
self.assertEqual(c.type.element_type.kind, TypeKind.INT)
self.assertEqual(i.type.kind, TypeKind.INCOMPLETEARRAY)
self.assertEqual(i.type.element_type.kind, TypeKind.INT)
self.assertEqual(v.type.kind, TypeKind.VARIABLEARRAY)
self.assertEqual(v.type.element_type.kind, TypeKind.INT)
def test_invalid_element_type(self):
"""Ensure Type.element_type raises if type doesn't have elements."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
with self.assertRaises(Exception):
i.element_type
def test_element_count(self):
"""Ensure Type.element_count works."""
tu = get_tu('int i[5]; int j;')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertEqual(i.type.element_count, 5)
with self.assertRaises(Exception):
j.type.element_count
def test_is_volatile_qualified(self):
"""Ensure Type.is_volatile_qualified works."""
tu = get_tu('volatile int i = 4; int j = 2;')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertIsInstance(i.type.is_volatile_qualified(), bool)
self.assertTrue(i.type.is_volatile_qualified())
self.assertFalse(j.type.is_volatile_qualified())
def test_is_restrict_qualified(self):
"""Ensure Type.is_restrict_qualified works."""
tu = get_tu('struct s { void * restrict i; void * j; };')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertIsInstance(i.type.is_restrict_qualified(), bool)
self.assertTrue(i.type.is_restrict_qualified())
self.assertFalse(j.type.is_restrict_qualified())
def test_record_layout(self):
"""Ensure Cursor.type.get_size, Cursor.type.get_align and
Cursor.type.get_offset works."""
source ="""
struct a {
long a1;
long a2:3;
long a3:4;
long long a4;
};
"""
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,35,64)),
(['-target','nvptx64-unknown-unknown'],(8,24,0,64,67,128)),
(['-target','i386-pc-win32'],(8,16,0,32,35,64)),
(['-target','msp430-none-none'],(2,14,0,32,35,48))]
for flags, values in tries:
align,total,a1,a2,a3,a4 = values
tu = get_tu(source, flags=flags)
teststruct = get_cursor(tu, 'a')
fields = list(teststruct.get_children())
self.assertEqual(teststruct.type.get_align(), align)
self.assertEqual(teststruct.type.get_size(), total)
self.assertEqual(teststruct.type.get_offset(fields[0].spelling), a1)
self.assertEqual(teststruct.type.get_offset(fields[1].spelling), a2)
self.assertEqual(teststruct.type.get_offset(fields[2].spelling), a3)
self.assertEqual(teststruct.type.get_offset(fields[3].spelling), a4)
self.assertEqual(fields[0].is_bitfield(), False)
self.assertEqual(fields[1].is_bitfield(), True)
self.assertEqual(fields[1].get_bitfield_width(), 3)
self.assertEqual(fields[2].is_bitfield(), True)
self.assertEqual(fields[2].get_bitfield_width(), 4)
self.assertEqual(fields[3].is_bitfield(), False)
def test_offset(self):
"""Ensure Cursor.get_record_field_offset works in anonymous records"""
source="""
struct Test {
struct {int a;} typeanon;
struct {
int bariton;
union {
int foo;
};
};
int bar;
};"""
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64,96)),
(['-target','nvptx64-unknown-unknown'],(8,24,0,32,64,96)),
(['-target','i386-pc-win32'],(8,16,0,32,64,96)),
(['-target','msp430-none-none'],(2,14,0,32,64,96))]
for flags, values in tries:
align,total,f1,bariton,foo,bar = values
tu = get_tu(source)
teststruct = get_cursor(tu, 'Test')
children = list(teststruct.get_children())
fields = list(teststruct.type.get_fields())
self.assertEqual(children[0].kind, CursorKind.STRUCT_DECL)
self.assertNotEqual(children[0].spelling, "typeanon")
self.assertEqual(children[1].spelling, "typeanon")
self.assertEqual(fields[0].kind, CursorKind.FIELD_DECL)
self.assertEqual(fields[1].kind, CursorKind.FIELD_DECL)
self.assertTrue(fields[1].is_anonymous())
self.assertEqual(teststruct.type.get_offset("typeanon"), f1)
self.assertEqual(teststruct.type.get_offset("bariton"), bariton)
self.assertEqual(teststruct.type.get_offset("foo"), foo)
self.assertEqual(teststruct.type.get_offset("bar"), bar)
def test_decay(self):
"""Ensure decayed types are handled as the original type"""
tu = get_tu("void foo(int a[]);")
foo = get_cursor(tu, 'foo')
a = foo.type.argument_types()[0]
self.assertEqual(a.kind, TypeKind.INCOMPLETEARRAY)
self.assertEqual(a.element_type.kind, TypeKind.INT)
self.assertEqual(a.get_canonical().kind, TypeKind.INCOMPLETEARRAY)
def test_addrspace(self):
"""Ensure the address space can be queried"""
tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c')
testInteger = get_cursor(tu, 'testInteger')
self.assertIsNotNone(testInteger, "Could not find testInteger.")
self.assertEqual(testInteger.type.get_address_space(), 2)
def test_template_arguments(self):
source = """
class Foo {
};
template <typename T>
class Template {
};
Template<Foo> instance;
int bar;
"""
tu = get_tu(source, lang='cpp')
# Varible with a template argument.
cursor = get_cursor(tu, 'instance')
cursor_type = cursor.type
self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
self.assertEqual(cursor_type.spelling, 'Template<Foo>')
self.assertEqual(cursor_type.get_num_template_arguments(), 1)
template_type = cursor_type.get_template_argument_type(0)
self.assertEqual(template_type.spelling, 'Foo')
# Variable without a template argument.
cursor = get_cursor(tu, 'bar')
self.assertEqual(cursor.get_num_template_arguments(), -1)

View File

@ -1,90 +0,0 @@
# This file provides common utility functions for the test suite.
import os
HAS_FSPATH = hasattr(os, 'fspath')
if HAS_FSPATH:
from pathlib import Path as str_to_path
else:
str_to_path = None
import unittest
from clang.cindex import Cursor
from clang.cindex import TranslationUnit
def get_tu(source, lang='c', all_warnings=False, flags=[]):
"""Obtain a translation unit from source and language.
By default, the translation unit is created from source file "t.<ext>"
where <ext> is the default file extension for the specified language. By
default it is C, so "t.c" is the default file name.
Supported languages are {c, cpp, objc}.
all_warnings is a convenience argument to enable all compiler warnings.
"""
args = list(flags)
name = 't.c'
if lang == 'cpp':
name = 't.cpp'
args.append('-std=c++11')
elif lang == 'objc':
name = 't.m'
elif lang != 'c':
raise Exception('Unknown language: %s' % lang)
if all_warnings:
args += ['-Wall', '-Wextra']
return TranslationUnit.from_source(name, args, unsaved_files=[(name,
source)])
def get_cursor(source, spelling):
"""Obtain a cursor from a source object.
This provides a convenient search mechanism to find a cursor with specific
spelling within a source. The first argument can be either a
TranslationUnit or Cursor instance.
If the cursor is not found, None is returned.
"""
# Convenience for calling on a TU.
root_cursor = source if isinstance(source, Cursor) else source.cursor
for cursor in root_cursor.walk_preorder():
if cursor.spelling == spelling:
return cursor
return None
def get_cursors(source, spelling):
"""Obtain all cursors from a source object with a specific spelling.
This provides a convenient search mechanism to find all cursors with
specific spelling within a source. The first argument can be either a
TranslationUnit or Cursor instance.
If no cursors are found, an empty list is returned.
"""
# Convenience for calling on a TU.
root_cursor = source if isinstance(source, Cursor) else source.cursor
cursors = []
for cursor in root_cursor.walk_preorder():
if cursor.spelling == spelling:
cursors.append(cursor)
return cursors
skip_if_no_fspath = unittest.skipUnless(HAS_FSPATH,
"Requires file system path protocol / Python 3.6+")
__all__ = [
'get_cursor',
'get_cursors',
'get_tu',
'skip_if_no_fspath',
'str_to_path',
]

View File

@ -1,600 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<choice>
<!-- Everything else not explicitly mentioned below. -->
<ref name="Other" />
<ref name="Function" />
<ref name="Class" />
<ref name="Variable" />
<ref name="Namespace" />
<ref name="Typedef" />
<ref name="Enum" />
</choice>
</start>
<define name="Other">
<element name="Other">
<ref name="attrSourceLocation" />
<ref name="Name" />
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Headerfile" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
<optional>
<ref name="TemplateParameters" />
</optional>
<optional>
<ref name="Parameters" />
</optional>
<optional>
<ref name="ResultDiscussion" />
</optional>
<optional>
<ref name="Discussion" />
</optional>
</element>
</define>
<define name="Function">
<element name="Function">
<optional>
<attribute name="templateKind">
<choice>
<value>template</value>
<value>specialization</value>
</choice>
</attribute>
</optional>
<ref name="attrSourceLocation" />
<optional>
<attribute name="isInstanceMethod">
<data type="boolean" />
</attribute>
</optional>
<optional>
<attribute name="isClassMethod">
<data type="boolean" />
</attribute>
</optional>
<ref name="Name" />
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Headerfile" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
<optional>
<ref name="TemplateParameters" />
</optional>
<optional>
<ref name="Parameters" />
</optional>
<optional>
<ref name="Exceptions" />
</optional>
<zeroOrMore>
<ref name="Availability" />
</zeroOrMore>
<zeroOrMore>
<ref name="Deprecated" />
</zeroOrMore>
<zeroOrMore>
<ref name="Unavailable" />
</zeroOrMore>
<optional>
<ref name="ResultDiscussion" />
</optional>
<optional>
<ref name="Discussion" />
</optional>
</element>
</define>
<define name="Class">
<element name="Class">
<optional>
<attribute name="templateKind">
<choice>
<value>template</value>
<value>specialization</value>
<value>partialSpecialization</value>
</choice>
</attribute>
</optional>
<ref name="attrSourceLocation" />
<ref name="Name" />
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Headerfile" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
<optional>
<ref name="TemplateParameters" />
</optional>
<!-- Parameters and results don't make sense for classes, but the user
can specify \param or \returns in a comment anyway. -->
<optional>
<ref name="Parameters" />
</optional>
<optional>
<ref name="ResultDiscussion" />
</optional>
<optional>
<ref name="Discussion" />
</optional>
</element>
</define>
<define name="Variable">
<element name="Variable">
<ref name="attrSourceLocation" />
<ref name="Name" />
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Headerfile" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
<!-- Template parameters, parameters and results don't make sense for
variables, but the user can specify \tparam \param or \returns
in a comment anyway. -->
<optional>
<ref name="TemplateParameters" />
</optional>
<optional>
<ref name="Parameters" />
</optional>
<optional>
<ref name="ResultDiscussion" />
</optional>
<optional>
<ref name="Discussion" />
</optional>
</element>
</define>
<define name="Namespace">
<element name="Namespace">
<ref name="attrSourceLocation" />
<ref name="Name" />
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Headerfile" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
<!-- Template parameters, parameters and results don't make sense for
namespaces, but the user can specify \tparam, \param or \returns
in a comment anyway. -->
<optional>
<ref name="TemplateParameters" />
</optional>
<optional>
<ref name="Parameters" />
</optional>
<optional>
<ref name="ResultDiscussion" />
</optional>
<optional>
<ref name="Discussion" />
</optional>
</element>
</define>
<define name="Typedef">
<element name="Typedef">
<ref name="attrSourceLocation" />
<ref name="Name" />
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Headerfile" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
<optional>
<ref name="TemplateParameters" />
</optional>
<!-- Parameters and results might make sense for typedefs if the type is
a function pointer type. -->
<optional>
<ref name="Parameters" />
</optional>
<optional>
<ref name="ResultDiscussion" />
</optional>
<optional>
<ref name="Discussion" />
</optional>
</element>
</define>
<define name="Enum">
<element name="Enum">
<ref name="attrSourceLocation" />
<ref name="Name" />
<optional>
<ref name="USR" />
</optional>
<optional>
<ref name="Headerfile" />
</optional>
<optional>
<ref name="Declaration" />
</optional>
<optional>
<ref name="Abstract" />
</optional>
<!-- Template parameters, parameters and results don't make sense for
enums, but the user can specify \tparam \param or \returns in a
comment anyway. -->
<optional>
<ref name="TemplateParameters" />
</optional>
<optional>
<ref name="Parameters" />
</optional>
<optional>
<ref name="ResultDiscussion" />
</optional>
<optional>
<ref name="Discussion" />
</optional>
</element>
</define>
<define name="attrSourceLocation">
<optional>
<attribute name="file">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</attribute>
</optional>
<optional>
<attribute name="line">
<data type="positiveInteger" />
</attribute>
<attribute name="column">
<data type="positiveInteger" />
</attribute>
</optional>
</define>
<define name="Name">
<element name="Name">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
</define>
<define name="USR">
<element name="USR">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
</define>
<define name="Abstract">
<element name="Abstract">
<zeroOrMore>
<ref name="TextBlockContent" />
</zeroOrMore>
</element>
</define>
<define name="Declaration">
<element name="Declaration">
<!-- Non-empty text content. -->
<data type="string"/>
</element>
</define>
<define name="Headerfile">
<element name="Headerfile">
<oneOrMore>
<ref name="TextBlockContent" />
</oneOrMore>
</element>
</define>
<define name="Discussion">
<element name="Discussion">
<zeroOrMore>
<ref name="TextBlockContent" />
</zeroOrMore>
</element>
</define>
<define name="TemplateParameters">
<element name="TemplateParameters">
<!-- Parameter elements should be sorted according to position. -->
<oneOrMore>
<element name="Parameter">
<element name="Name">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
<optional>
<!-- This is index at depth 0. libclang API can return more
information about position, but we expose only essential
information here, since "Parameter" elements are already
sorted.
"Position" element could be added in future if needed. -->
<element name="Index">
<data type="nonNegativeInteger" />
</element>
</optional>
<!-- In general, template parameters with whitespace discussion
should not be emitted. Schema might be more strict here. -->
<element name="Discussion">
<ref name="TextBlockContent" />
</element>
</element>
</oneOrMore>
</element>
</define>
<define name="Parameters">
<element name="Parameters">
<!-- Parameter elements should be sorted according to index. -->
<oneOrMore>
<element name="Parameter">
<element name="Name">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
<optional>
<choice>
<element name="Index">
<data type="nonNegativeInteger" />
</element>
<element name="IsVarArg">
<empty />
</element>
</choice>
</optional>
<element name="Direction">
<attribute name="isExplicit">
<data type="boolean" />
</attribute>
<choice>
<value>in</value>
<value>out</value>
<value>in,out</value>
</choice>
</element>
<!-- In general, template parameters with whitespace discussion
should not be emitted, unless direction is explicitly specified.
Schema might be more strict here. -->
<element name="Discussion">
<ref name="TextBlockContent" />
</element>
</element>
</oneOrMore>
</element>
</define>
<define name="Exceptions">
<element name="Exceptions">
<oneOrMore>
<ref name="TextBlockContent" />
</oneOrMore>
</element>
</define>
<define name="Availability">
<element name="Availability">
<attribute name="distribution">
<data type="string" />
</attribute>
<optional>
<element name="IntroducedInVersion">
<data type="string">
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
</data>
</element>
</optional>
<optional>
<element name="DeprecatedInVersion">
<data type="string">
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
</data>
</element>
</optional>
<optional>
<element name="RemovedAfterVersion">
<data type="string">
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
</data>
</element>
</optional>
<optional>
<element name="DeprecationSummary">
<data type="string" />
</element>
</optional>
<optional>
<ref name="Unavailable" />
</optional>
</element>
</define>
<define name="Deprecated">
<element name="Deprecated">
<optional>
<data type="string" />
</optional>
</element>
</define>
<define name="Unavailable">
<element name="Unavailable">
<optional>
<data type="string" />
</optional>
</element>
</define>
<define name="ResultDiscussion">
<element name="ResultDiscussion">
<zeroOrMore>
<ref name="TextBlockContent" />
</zeroOrMore>
</element>
</define>
<define name="TextBlockContent">
<choice>
<element name="Para">
<optional>
<attribute name="kind">
<choice>
<value>attention</value>
<value>author</value>
<value>authors</value>
<value>bug</value>
<value>copyright</value>
<value>date</value>
<value>invariant</value>
<value>note</value>
<value>post</value>
<value>pre</value>
<value>remark</value>
<value>remarks</value>
<value>sa</value>
<value>see</value>
<value>since</value>
<value>todo</value>
<value>version</value>
<value>warning</value>
</choice>
</attribute>
</optional>
<zeroOrMore>
<ref name="TextInlineContent" />
</zeroOrMore>
</element>
<element name="Verbatim">
<attribute name="xml:space">
<value>preserve</value>
</attribute>
<attribute name="kind">
<!-- TODO: add all Doxygen verbatim kinds -->
<choice>
<value>code</value>
<value>verbatim</value>
</choice>
</attribute>
<text />
</element>
</choice>
</define>
<define name="TextInlineContent">
<choice>
<text />
<element name="bold">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
<element name="monospaced">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
<element name="emphasized">
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
<element name="rawHTML">
<optional>
<!-- If not specified, the default value is 'false'. -->
<!-- The value 'false' or absence of the attribute does not imply
that the HTML is actually well-formed. -->
<attribute name="isMalformed">
<data type="boolean" />
</attribute>
</optional>
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
</choice>
</define>
</grammar>

View File

@ -1,15 +0,0 @@
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")
set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_TARGETS
clang
check-all
check-llvm
check-clang
test-suite CACHE STRING "")
set(CLANG_BOOTSTRAP_CMAKE_ARGS
-C ${CMAKE_CURRENT_LIST_DIR}/3-stage-base.cmake
CACHE STRING "")

View File

@ -1,16 +0,0 @@
set(CLANG_BOOTSTRAP_TARGETS
clang
check-all
check-llvm
check-clang
test-suite
stage3
stage3-clang
stage3-check-all
stage3-check-llvm
stage3-check-clang
stage3-test-suite CACHE STRING "")
set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
include(${CMAKE_CURRENT_LIST_DIR}/3-stage-base.cmake)

View File

@ -1,52 +0,0 @@
set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "")
set(CLANG_VENDOR Android CACHE STRING "")
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
set(LLVM_ENABLE_THREADS OFF CACHE BOOL "")
set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(LLVM_LIBDIR_SUFFIX 64 CACHE STRING "")
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
set(ANDROID_RUNTIMES_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(ANDROID_RUNTIMES_BUILD_TYPE Release CACHE STRING "")
set(ANDROID_BUILTINS_BUILD_TYPE Release CACHE STRING "")
set(LLVM_BUILTIN_TARGETS "i686-linux-android;x86_64-linux-android;aarch64-linux-android;armv7-linux-android" CACHE STRING "")
foreach(target i686;x86_64;aarch64;armv7)
set(BUILTINS_${target}-linux-android_ANDROID 1 CACHE STRING "")
set(BUILTINS_${target}-linux-android_CMAKE_BUILD_TYPE ${ANDROID_BUILTINS_BUILD_TYPE} CACHE STRING "")
set(BUILTINS_${target}-linux-android_CMAKE_ASM_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_C_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_SYSROOT ${ANDROID_${target}_SYSROOT} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_EXE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_SHARED_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_MOUDLE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
endforeach()
set(LLVM_RUNTIME_TARGETS "i686-linux-android;x86_64-linux-android;aarch64-linux-android;armv7-linux-android" CACHE STRING "")
foreach(target i686;x86_64;aarch64;armv7)
set(RUNTIMES_${target}-linux-android_ANDROID 1 CACHE STRING "")
set(RUNTIMES_${target}-linux-android_CMAKE_ASM_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_BUILD_TYPE ${ANDROID_RUNTIMES_BUILD_TYPE} CACHE STRING "")
set(RUNTIMES_${target}-linux-android_CMAKE_C_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_CXX_FLAGS ${ANDROID_${target}_CXX_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_SYSROOT ${ANDROID_${target}_SYSROOT} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_EXE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_SHARED_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_MODULE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_COMPILER_RT_ENABLE_WERROR ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_COMPILER_RT_TEST_COMPILER_CFLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_ASSERTIONS ${ANDROID_RUNTIMES_ENABLE_ASSERTIONS} CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_THREADS OFF CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBUNWIND_HAS_NO_EXCEPTIONS_FLAG ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBUNWIND_HAS_FUNWIND_TABLES ON CACHE BOOL "")
endforeach()
set(RUNTIMES_armv7-linux-android_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")

View File

@ -1,43 +0,0 @@
# This file sets up a CMakeCache for an Android toolchain build.
set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
set(CLANG_ENABLE_ARCMT OFF CACHE BOOL "")
set(CLANG_ENABLE_STATIC_ANALYZER OFF CACHE BOOL "")
set(CLANG_VENDOR Android CACHE STRING "")
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(HAVE_LIBCXXABI ON CACHE BOOL "")
set(LLVM_BUILD_TOOLS OFF CACHE BOOL "")
set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(LLVM_ENABLE_THREADS OFF CACHE BOOL "")
set(LLVM_LIBDIR_SUFFIX 64 CACHE STRING "")
set(LLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD OFF CACHE BOOL "")
set(LLVM_TOOL_OPENMP_BUILD OFF CACHE BOOL "")
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
list(APPEND EXTRA_ARGS -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT=${LIBCXX_ENABLE_ABI_LINKER_SCRIPT})
endif()
if (LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
list(APPEND EXTRA_ARGS -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=${LIBCXX_ENABLE_STATIC_ABI_LIBRARY})
endif()
if (LLVM_BUILD_EXTERNAL_COMPILER_RT)
set(APPEND EXTRA_ARGS -DLLVM_BUILD_EXTERNAL_COMPILER_RT=${LLVM_BUILD_EXTERNAL_COMPILER_RT})
endif()
get_cmake_property(variableNames VARIABLES)
foreach(variableName ${variableNames})
if(variableName MATCHES "^STAGE2_")
string(REPLACE "STAGE2_" "" new_name ${variableName})
list(APPEND EXTRA_ARGS "-D${new_name}=${${variableName}}")
endif()
endforeach()
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_CMAKE_ARGS
${EXTRA_ARGS}
-C${CMAKE_CURRENT_LIST_DIR}/Android-stage2.cmake CACHE STRING "")

View File

@ -1,56 +0,0 @@
# This file sets up a CMakeCache for Apple-style bootstrap builds. It can be
# used on any Darwin system to approximate Apple Clang builds.
if($ENV{DT_TOOLCHAIN_DIR})
set(CMAKE_INSTALL_PREFIX $ENV{DT_TOOLCHAIN_DIR}/usr/)
else()
set(CMAKE_INSTALL_PREFIX /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.toolchain/usr/)
endif()
set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
set(CLANG_VENDOR Apple CACHE STRING "")
set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LLVM_INCLUDE_UTILS OFF CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(CLANG_INCLUDE_TESTS OFF CACHE BOOL "")
set(COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
set(COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "")
set(CMAKE_MACOSX_RPATH ON CACHE BOOL "")
set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(CLANG_BOOTSTRAP_PASSTHROUGH
CMAKE_OSX_ARCHITECTURES
CACHE STRING "")
# Disabling embedded darwin compiler-rt on stage1 builds is required because we
# don't build stage1 to support arm code generation.
set(COMPILER_RT_ENABLE_IOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_WATCHOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_TVOS OFF CACHE BOOL "")
set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(CLANG_BOOTSTRAP_TARGETS
generate-order-file
check-all
check-llvm
check-clang
llvm-config
test-suite
test-depends
llvm-test-depends
clang-test-depends
distribution
install-distribution
install-xcode-toolchain
install-distribution-toolchain
clang CACHE STRING "")
#bootstrap
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_CMAKE_ARGS
-C ${CMAKE_CURRENT_LIST_DIR}/Apple-stage2.cmake
CACHE STRING "")

View File

@ -1,6 +0,0 @@
# This file sets up a CMakeCache for Apple-style stage2 ThinLTO bootstrap. It is
# specified by the stage1 build.
set(LLVM_ENABLE_LTO THIN CACHE BOOL "")
include(${CMAKE_CURRENT_LIST_DIR}/Apple-stage2.cmake)

View File

@ -1,70 +0,0 @@
# This file sets up a CMakeCache for Apple-style stage2 bootstrap. It is
# specified by the stage1 build.
set(LLVM_TARGETS_TO_BUILD X86 ARM AArch64 CACHE STRING "")
set(PACKAGE_VENDOR Apple CACHE STRING "")
set(CLANG_VENDOR_UTI com.apple.clang CACHE STRING "")
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(LLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD OFF CACHE BOOL "")
set(CLANG_TOOL_SCAN_BUILD_BUILD OFF CACHE BOOL "")
set(CLANG_TOOL_SCAN_VIEW_BUILD OFF CACHE BOOL "")
set(CLANG_LINKS_TO_CREATE clang++ cc c++ CACHE STRING "")
set(CMAKE_MACOSX_RPATH ON CACHE BOOL "")
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_MODULES ON CACHE BOOL "")
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(BUG_REPORT_URL "http://developer.apple.com/bugreporter/" CACHE STRING "")
set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "Build Compiler-RT with just-built clang")
set(COMPILER_RT_ENABLE_IOS ON CACHE BOOL "Build iOS Compiler-RT libraries")
set(LLVM_CREATE_XCODE_TOOLCHAIN ON CACHE BOOL "Generate targets to create and install an Xcode compatible toolchain")
# Make unit tests (if present) part of the ALL target
set(LLVM_BUILD_TESTS ON CACHE BOOL "")
set(LLVM_ENABLE_LTO ON CACHE BOOL "")
set(CMAKE_C_FLAGS "-fno-stack-protector -fno-common -Wno-profile-instr-unprofiled" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-fno-stack-protector -fno-common -Wno-profile-instr-unprofiled" CACHE STRING "")
if(LLVM_ENABLE_LTO AND NOT LLVM_ENABLE_LTO STREQUAL "THIN")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
endif()
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(LIBCXX_INSTALL_LIBRARY OFF CACHE BOOL "")
set(LIBCXX_INSTALL_HEADERS ON CACHE BOOL "")
set(LIBCXX_INCLUDE_TESTS OFF CACHE BOOL "")
set(LLVM_LTO_VERSION_OFFSET 3000 CACHE STRING "")
# Generating Xcode toolchains is useful for developers wanting to build and use
# clang without installing over existing tools.
set(LLVM_CREATE_XCODE_TOOLCHAIN ON CACHE BOOL "")
# setup toolchain
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
set(LLVM_TOOLCHAIN_TOOLS
dsymutil
llvm-cov
llvm-dwarfdump
llvm-profdata
llvm-objdump
llvm-nm
llvm-size
CACHE STRING "")
set(LLVM_DISTRIBUTION_COMPONENTS
clang
LTO
clang-format
clang-headers
cxx-headers
${LLVM_TOOLCHAIN_TOOLS}
CACHE STRING "")
# test args
set(LLVM_LIT_ARGS "--xunit-xml-output=testresults.xunit.xml -v" CACHE STRING "")

View File

@ -1,50 +0,0 @@
set(LLVM_TARGETS_TO_BUILD ARM;X86 CACHE STRING "")
# Builtins
set(LLVM_BUILTIN_TARGETS "armv7m-none-eabi;armv6m-none-eabi;armv7em-none-eabi" CACHE STRING "Builtin Targets")
set(BUILTINS_armv6m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV6M_SYSROOT} CACHE STRING "armv6m-none-eabi Sysroot")
set(BUILTINS_armv6m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv6m-none-eabi System Name")
set(BUILTINS_armv6m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv6m-none-eabi Baremetal build")
set(BUILTINS_armv6m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv6m-none-eabi os dir")
set(BUILTINS_armv7m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7M_SYSROOT} CACHE STRING "armv7m-none-eabi Sysroot")
set(BUILTINS_armv7m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7m-none-eabi System Name")
set(BUILTINS_armv7m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7m-none-eabi Baremetal build")
set(BUILTINS_armv7m-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi C Flags")
set(BUILTINS_armv7m-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi ASM Flags")
set(BUILTINS_armv7m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7m-none-eabi os dir")
set(BUILTINS_armv7em-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7EM_SYSROOT} CACHE STRING "armv7em-none-eabi Sysroot")
set(BUILTINS_armv7em-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7em-none-eabi System Name")
set(BUILTINS_armv7em-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7em-none-eabi Baremetal build")
set(BUILTINS_armv7em-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi C Flags")
set(BUILTINS_armv7em-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi ASM Flags")
set(BUILTINS_armv7em-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7em-none-eabi os dir")
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
set(LLVM_TOOLCHAIN_TOOLS
dsymutil
llc
llvm-ar
llvm-cxxfilt
llvm-dwarfdump
llvm-nm
llvm-objdump
llvm-ranlib
llvm-readobj
llvm-size
llvm-symbolizer
opt
CACHE STRING "")
set(LLVM_DISTRIBUTION_COMPONENTS
clang
lld
clang-headers
builtins-armv6m-none-eabi
builtins-armv7m-none-eabi
builtins-armv7em-none-eabi
runtimes
${LLVM_TOOLCHAIN_TOOLS}
CACHE STRING "")

View File

@ -1,30 +0,0 @@
# This file sets up a CMakeCache for the second stage of a simple distribution
# bootstrap build.
set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
# setup toolchain
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
set(LLVM_TOOLCHAIN_TOOLS
dsymutil
llvm-cov
llvm-dwarfdump
llvm-profdata
llvm-objdump
llvm-nm
llvm-size
CACHE STRING "")
set(LLVM_DISTRIBUTION_COMPONENTS
clang
LTO
clang-format
clang-headers
builtins
runtimes
${LLVM_TOOLCHAIN_TOOLS}
CACHE STRING "")

View File

@ -1,41 +0,0 @@
# This file sets up a CMakeCache for a simple distribution bootstrap build.
# Only build the native target in stage1 since it is a throwaway build.
set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
# Optimize the stage1 compiler, but don't LTO it because that wastes time.
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
# Setup vendor-specific settings.
set(PACKAGE_VENDOR LLVM.org CACHE STRING "")
# Setting up the stage2 LTO option needs to be done on the stage1 build so that
# the proper LTO library dependencies can be connected.
set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
# Expose stage2 targets through the stage1 build configuration.
set(CLANG_BOOTSTRAP_TARGETS
check-all
check-llvm
check-clang
llvm-config
test-suite
test-depends
llvm-test-depends
clang-test-depends
distribution
install-distribution
clang CACHE STRING "")
# Setup the bootstrap build.
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
if(STAGE2_CACHE_FILE)
set(CLANG_BOOTSTRAP_CMAKE_ARGS
-C ${STAGE2_CACHE_FILE}
CACHE STRING "")
else()
set(CLANG_BOOTSTRAP_CMAKE_ARGS
-C ${CMAKE_CURRENT_LIST_DIR}/DistributionExample-stage2.cmake
CACHE STRING "")
endif()

View File

@ -1,179 +0,0 @@
# This file sets up a CMakeCache for the second stage of a Fuchsia toolchain build.
set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "")
set(PACKAGE_VENDOR Fuchsia CACHE STRING "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
if(NOT APPLE)
set(LLVM_ENABLE_LLD ON CACHE BOOL "")
endif()
set(LLVM_ENABLE_LTO ON CACHE BOOL "")
set(LLVM_ENABLE_MODULES ON CACHE BOOL "")
set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "")
set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(CLANG_DEFAULT_CXX_STDLIB libc++ CACHE STRING "")
if(NOT APPLE)
set(CLANG_DEFAULT_LINKER lld CACHE STRING "")
set(CLANG_DEFAULT_OBJCOPY llvm-objcopy CACHE STRING "")
endif()
set(CLANG_DEFAULT_RTLIB compiler-rt CACHE STRING "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(ENABLE_LINKER_BUILD_ID ON CACHE BOOL "")
set(ENABLE_X86_RELAX_RELOCATIONS ON CACHE BOOL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
if(APPLE)
list(APPEND BUILTIN_TARGETS "default")
list(APPEND RUNTIME_TARGETS "default")
set(COMPILER_RT_ENABLE_IOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_TVOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_WATCHOS OFF CACHE BOOL "")
endif()
foreach(target aarch64-linux-gnu;armv7-linux-gnueabihf;i386-linux-gnu;x86_64-linux-gnu)
if(LINUX_${target}_SYSROOT)
# Set the per-target builtins options.
list(APPEND BUILTIN_TARGETS "${target}")
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Linux CACHE STRING "")
set(BUILTINS_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT ${LINUX_${target}_SYSROOT} CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_MODULE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_EXE_LINKER_FLAG "-fuse-ld=lld" CACHE STRING "")
# Set the per-target runtimes options.
list(APPEND RUNTIME_TARGETS "${target}")
set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Linux CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSROOT ${LINUX_${target}_SYSROOT} CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_MODULE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBUNWIND_INSTALL_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_INSTALL_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_SANITIZER_CXX_ABI "libc++" CACHE STRING "")
set(RUNTIMES_${target}_SANITIZER_CXX_ABI_INTREE ON CACHE BOOL "")
set(RUNTIMES_${target}_COMPILER_RT_USE_BUILTINS_LIBRARY ON CACHE BOOL "")
endif()
endforeach()
if(FUCHSIA_SDK)
set(FUCHSIA_aarch64_NAME arm64)
set(FUCHSIA_x86_64_NAME x64)
foreach(target x86_64;aarch64)
set(FUCHSIA_${target}_COMPILER_FLAGS "-I${FUCHSIA_SDK}/pkg/fdio/include")
set(FUCHSIA_${target}_LINKER_FLAGS "-L${FUCHSIA_SDK}/arch/${FUCHSIA_${target}_NAME}/lib")
set(FUCHSIA_${target}_SYSROOT "${FUCHSIA_SDK}/arch/${FUCHSIA_${target}_NAME}/sysroot")
endforeach()
foreach(target x86_64;aarch64)
# Set the per-target builtins options.
list(APPEND BUILTIN_TARGETS "${target}-fuchsia")
set(BUILTINS_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_ASM_FLAGS ${FUCHSIA_${target}_COMPILER_FLAGS} CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_C_FLAGS ${FUCHSIA_${target}_COMPILER_FLAGS} CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_CXX_FLAGS ${FUCHSIA_${target}_COMPILER_FLAGS} CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_SHARED_LINKER_FLAGS ${FUCHSIA_${target}_LINKER_FLAGS} CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_MODULE_LINKER_FLAGS ${FUCHSIA_${target}_LINKER_FLAGS} CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_EXE_LINKER_FLAGS ${FUCHSIA_${target}_LINKER_FLAGS} CACHE STRING "")
set(BUILTINS_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
# Set the per-target runtimes options.
list(APPEND RUNTIME_TARGETS "${target}-fuchsia")
set(RUNTIMES_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_CMAKE_ASM_FLAGS ${FUCHSIA_${target}_COMPILER_FLAGS} CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_C_FLAGS ${FUCHSIA_${target}_COMPILER_FLAGS} CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_CXX_FLAGS ${FUCHSIA_${target}_COMPILER_FLAGS} CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_SHARED_LINKER_FLAGS ${FUCHSIA_${target}_LINKER_FLAGS} CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_MODULE_LINKER_FLAGS ${FUCHSIA_${target}_LINKER_FLAGS} CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_EXE_LINKER_FLAGS ${FUCHSIA_${target}_LINKER_FLAGS} CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
set(RUNTIMES_${target}-fuchsia_LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBUNWIND_INSTALL_STATIC_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_INSTALL_STATIC_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_ABI_VERSION 2 CACHE STRING "")
endforeach()
set(LLVM_RUNTIME_SANITIZERS "Address" CACHE STRING "")
set(LLVM_RUNTIME_SANITIZER_Address_TARGETS "x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "")
endif()
set(LLVM_BUILTIN_TARGETS "${BUILTIN_TARGETS}" CACHE STRING "")
set(LLVM_RUNTIME_TARGETS "${RUNTIME_TARGETS}" CACHE STRING "")
# Setup toolchain.
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
set(LLVM_TOOLCHAIN_TOOLS
dsymutil
llc
llvm-ar
llvm-cov
llvm-cxxfilt
llvm-dwarfdump
llvm-dwp
llvm-lib
llvm-nm
llvm-objcopy
llvm-objdump
llvm-profdata
llvm-ranlib
llvm-readelf
llvm-readobj
llvm-size
llvm-strip
llvm-symbolizer
llvm-xray
opt
sancov
CACHE STRING "")
set(LLVM_DISTRIBUTION_COMPONENTS
clang
libclang
lld
LTO
clang-apply-replacements
clang-format
clang-headers
clang-include-fixer
clang-refactor
clang-tidy
clangd
builtins
runtimes
${LLVM_TOOLCHAIN_TOOLS}
CACHE STRING "")

View File

@ -1,116 +0,0 @@
# This file sets up a CMakeCache for a Fuchsia toolchain build.
set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "")
set(PACKAGE_VENDOR Fuchsia CACHE STRING "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "")
set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(CLANG_DEFAULT_CXX_STDLIB libc++ CACHE STRING "")
if(NOT APPLE)
set(CLANG_DEFAULT_LINKER lld CACHE STRING "")
set(CLANG_DEFAULT_OBJCOPY llvm-objcopy CACHE STRING "")
endif()
set(CLANG_DEFAULT_RTLIB compiler-rt CACHE STRING "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(ENABLE_LINKER_BUILD_ID ON CACHE BOOL "")
set(ENABLE_X86_RELAX_RELOCATIONS ON CACHE BOOL "")
set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
if(APPLE)
set(COMPILER_RT_ENABLE_IOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_TVOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_WATCHOS OFF CACHE BOOL "")
elseif(UNIX)
set(LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "")
set(LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
set(LIBUNWIND_INSTALL_LIBRARY OFF CACHE BOOL "")
set(LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
set(LIBCXXABI_INSTALL_LIBRARY OFF CACHE BOOL "")
set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
endif()
if(BOOTSTRAP_CMAKE_SYSTEM_NAME)
set(target "${BOOTSTRAP_CMAKE_CXX_COMPILER_TARGET}")
if(STAGE2_LINUX_${target}_SYSROOT)
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Linux CACHE STRING "")
set(BUILTINS_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT ${STAGE2_LINUX_${target}_SYSROOT} CACHE STRING "")
set(LLVM_BUILTIN_TARGETS "${target}" CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Linux CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSROOT ${STAGE2_LINUX_${target}_SYSROOT} CACHE STRING "")
set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBUNWIND_INSTALL_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXXABI_INSTALL_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_SANITIZER_CXX_ABI "libc++" CACHE STRING "")
set(RUNTIMES_${target}_SANITIZER_CXX_ABI_INTREE ON CACHE BOOL "")
set(RUNTIMES_${target}_COMPILER_RT_USE_BUILTINS_LIBRARY ON CACHE BOOL "")
set(LLVM_RUNTIME_TARGETS "${target}" CACHE STRING "")
endif()
endif()
set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
if(NOT APPLE)
set(BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "")
endif()
set(CLANG_BOOTSTRAP_TARGETS
check-all
check-llvm
check-clang
check-lld
llvm-config
test-suite
test-depends
llvm-test-depends
clang-test-depends
lld-test-depends
distribution
install-distribution
install-distribution-stripped
install-distribution-toolchain
clang CACHE STRING "")
get_cmake_property(variableNames VARIABLES)
foreach(variableName ${variableNames})
if(variableName MATCHES "^STAGE2_")
string(REPLACE "STAGE2_" "" new_name ${variableName})
list(APPEND EXTRA_ARGS "-D${new_name}=${${variableName}}")
endif()
endforeach()
# Setup the bootstrap build.
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_EXTRA_DEPS
builtins
runtimes
CACHE STRING "")
set(CLANG_BOOTSTRAP_CMAKE_ARGS
${EXTRA_ARGS}
-C ${CMAKE_CURRENT_LIST_DIR}/Fuchsia-stage2.cmake
CACHE STRING "")

View File

@ -1,22 +0,0 @@
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_TARGETS
distribution
install-distribution
install-distribution-toolchain
check-all
check-llvm
check-clang
test-suite CACHE STRING "")
if(PGO_BUILD_CONFIGURATION)
include(${PGO_BUILD_CONFIGURATION})
set(CLANG_BOOTSTRAP_CMAKE_ARGS
-C ${PGO_BUILD_CONFIGURATION}
CACHE STRING "")
else()
include(${CMAKE_CURRENT_LIST_DIR}/PGO-stage2.cmake)
set(CLANG_BOOTSTRAP_CMAKE_ARGS
-C ${CMAKE_CURRENT_LIST_DIR}/PGO-stage2.cmake
CACHE STRING "")
endif()

View File

@ -1,2 +0,0 @@
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")

View File

@ -1,30 +0,0 @@
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(LLVM_BUILD_EXTERNAL_COMPILER_RT ON CACHE BOOL "")
set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
set(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_TARGETS
generate-profdata
stage2
stage2-distribution
stage2-install-distribution
stage2-install-distribution-toolchain
stage2-check-all
stage2-check-llvm
stage2-check-clang
stage2-test-suite CACHE STRING "")
if(PGO_INSTRUMENT_LTO)
set(BOOTSTRAP_LLVM_ENABLE_LTO ${PGO_INSTRUMENT_LTO} CACHE BOOL "")
set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LTO ${PGO_INSTRUMENT_LTO} CACHE BOOL "")
endif()
if(PGO_BUILD_CONFIGURATION)
set(EXTRA_ARGS -DPGO_BUILD_CONFIGURATION=${PGO_BUILD_CONFIGURATION})
endif()
set(CLANG_BOOTSTRAP_CMAKE_ARGS
${EXTRA_ARGS}
-C ${CMAKE_CURRENT_LIST_DIR}/PGO-stage2-instrumented.cmake
CACHE STRING "")

View File

@ -1,74 +0,0 @@
CMake Caches
============
This directory contains CMake cache scripts that pre-populate the CMakeCache in
a build directory with commonly used settings.
You can use the caches files with the following CMake invocation:
cmake -G <build system>
-C <path to cache file>
[additional CMake options (i.e. -DCMAKE_INSTALL_PREFIX=<install path>)]
<path to llvm>
Options specified on the command line will override options in the cache files.
The following cache files exist.
Apple-stage1
------------
The Apple stage1 cache configures a two stage build similar to how Apple builds
the clang shipped with Xcode. The build files generated from this invocation has
a target named "stage2" which performs an LTO build of clang.
The Apple-stage2 cache can be used directly to match the build settings Apple
uses in shipping builds without doing a full bootstrap build.
PGO
---
The PGO CMake cache can be used to generate a multi-stage instrumented compiler.
You can configure your build directory with the following invocation of CMake:
cmake -G <generator> -C <path_to_clang>/cmake/caches/PGO.cmake <source dir>
After configuration the following additional targets will be generated:
stage2-instrumented:
Builds a stage1 x86 compiler, runtime, and required tools (llvm-config,
llvm-profdata) then uses that compiler to build an instrumented stage2 compiler.
stage2-instrumented-generate-profdata:
Depends on "stage2-instrumented" and will use the instrumented compiler to
generate profdata based on the training files in <clang>/utils/perf-training
stage2:
Depends on "stage2-instrumented-generate-profdata" and will use the stage1
compiler with the stage2 profdata to build a PGO-optimized compiler.
stage2-check-llvm:
Depends on stage2 and runs check-llvm using the stage3 compiler.
stage2-check-clang:
Depends on stage2 and runs check-clang using the stage3 compiler.
stage2-check-all:
Depends on stage2 and runs check-all using the stage3 compiler.
stage2-test-suite:
Depends on stage2 and runs the test-suite using the stage3 compiler (requires
in-tree test-suite).
3-stage
-------
This cache file can be used to generate a 3-stage clang build. You can configure
using the following CMake command:
cmake -C <path to clang>/cmake/caches/3-stage.cmake -G Ninja <path to llvm>
You can then run "ninja stage3-clang" to build stage1, stage2 and stage3 clangs.
This is useful for finding non-determinism the compiler by verifying that stage2
and stage3 are identical.

View File

@ -1,161 +0,0 @@
function(clang_tablegen)
# Syntax:
# clang_tablegen output-file [tablegen-arg ...] SOURCE source-file
# [[TARGET cmake-target-name] [DEPENDS extra-dependency ...]]
#
# Generates a custom command for invoking tblgen as
#
# tblgen source-file -o=output-file tablegen-arg ...
#
# and, if cmake-target-name is provided, creates a custom target for
# executing the custom command depending on output-file. It is
# possible to list more files to depend after DEPENDS.
cmake_parse_arguments(CTG "" "SOURCE;TARGET" "" ${ARGN})
if( NOT CTG_SOURCE )
message(FATAL_ERROR "SOURCE source-file required by clang_tablegen")
endif()
set( LLVM_TARGET_DEFINITIONS ${CTG_SOURCE} )
tablegen(CLANG ${CTG_UNPARSED_ARGUMENTS})
if(CTG_TARGET)
add_public_tablegen_target(${CTG_TARGET})
set_target_properties( ${CTG_TARGET} PROPERTIES FOLDER "Clang tablegenning")
set_property(GLOBAL APPEND PROPERTY CLANG_TABLEGEN_TARGETS ${CTG_TARGET})
endif()
endfunction(clang_tablegen)
macro(set_clang_windows_version_resource_properties name)
if(DEFINED windows_resource_file)
set_windows_version_resource_properties(${name} ${windows_resource_file}
VERSION_MAJOR ${CLANG_VERSION_MAJOR}
VERSION_MINOR ${CLANG_VERSION_MINOR}
VERSION_PATCHLEVEL ${CLANG_VERSION_PATCHLEVEL}
VERSION_STRING "${CLANG_VERSION} (${BACKEND_PACKAGE_STRING})"
PRODUCT_NAME "clang")
endif()
endmacro()
macro(add_clang_subdirectory name)
add_llvm_subdirectory(CLANG TOOL ${name})
endmacro()
macro(add_clang_library name)
cmake_parse_arguments(ARG
"SHARED"
""
"ADDITIONAL_HEADERS"
${ARGN})
set(srcs)
if(MSVC_IDE OR XCODE)
# Add public headers
file(RELATIVE_PATH lib_path
${CLANG_SOURCE_DIR}/lib/
${CMAKE_CURRENT_SOURCE_DIR}
)
if(NOT lib_path MATCHES "^[.][.]")
file( GLOB_RECURSE headers
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.h
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.def
)
set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
file( GLOB_RECURSE tds
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.td
)
source_group("TableGen descriptions" FILES ${tds})
set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
if(headers OR tds)
set(srcs ${headers} ${tds})
endif()
endif()
endif(MSVC_IDE OR XCODE)
if(srcs OR ARG_ADDITIONAL_HEADERS)
set(srcs
ADDITIONAL_HEADERS
${srcs}
${ARG_ADDITIONAL_HEADERS} # It may contain unparsed unknown args.
)
endif()
if(ARG_SHARED)
set(ARG_ENABLE_SHARED SHARED)
endif()
llvm_add_library(${name} ${ARG_ENABLE_SHARED} ${ARG_UNPARSED_ARGUMENTS} ${srcs})
if(TARGET ${name})
target_link_libraries(${name} INTERFACE ${LLVM_COMMON_LIBS})
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "libclang")
if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
NOT LLVM_DISTRIBUTION_COMPONENTS)
set(export_to_clangtargets EXPORT ClangTargets)
set_property(GLOBAL PROPERTY CLANG_HAS_EXPORTS True)
endif()
install(TARGETS ${name}
COMPONENT ${name}
${export_to_clangtargets}
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
RUNTIME DESTINATION bin)
if (${ARG_SHARED} AND NOT CMAKE_CONFIGURATION_TYPES)
add_llvm_install_targets(install-${name}
DEPENDS ${name}
COMPONENT ${name})
endif()
endif()
set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name})
else()
# Add empty "phony" target
add_custom_target(${name})
endif()
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
set_clang_windows_version_resource_properties(${name})
endmacro(add_clang_library)
macro(add_clang_executable name)
add_llvm_executable( ${name} ${ARGN} )
set_target_properties(${name} PROPERTIES FOLDER "Clang executables")
set_clang_windows_version_resource_properties(${name})
endmacro(add_clang_executable)
macro(add_clang_tool name)
if (NOT CLANG_BUILD_TOOLS)
set(EXCLUDE_FROM_ALL ON)
endif()
add_clang_executable(${name} ${ARGN})
add_dependencies(${name} clang-headers)
if (CLANG_BUILD_TOOLS)
if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
NOT LLVM_DISTRIBUTION_COMPONENTS)
set(export_to_clangtargets EXPORT ClangTargets)
set_property(GLOBAL PROPERTY CLANG_HAS_EXPORTS True)
endif()
install(TARGETS ${name}
${export_to_clangtargets}
RUNTIME DESTINATION bin
COMPONENT ${name})
if(NOT CMAKE_CONFIGURATION_TYPES)
add_llvm_install_targets(install-${name}
DEPENDS ${name}
COMPONENT ${name})
endif()
set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name})
endif()
endmacro()
macro(add_clang_symlink name dest)
add_llvm_tool_symlink(${name} ${dest} ALWAYS_GENERATE)
# Always generate install targets
llvm_install_symlink(${name} ${dest} ALWAYS_GENERATE)
endmacro()

View File

@ -1,64 +0,0 @@
# Generate a list of CMake library targets so that other CMake projects can
# link against them. LLVM calls its version of this file LLVMExports.cmake, but
# the usual CMake convention seems to be ${Project}Targets.cmake.
set(CLANG_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/clang)
set(clang_cmake_builddir "${CMAKE_BINARY_DIR}/${CLANG_INSTALL_PACKAGE_DIR}")
# Keep this in sync with llvm/cmake/CMakeLists.txt!
set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm)
set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}")
get_property(CLANG_EXPORTS GLOBAL PROPERTY CLANG_EXPORTS)
export(TARGETS ${CLANG_EXPORTS} FILE ${clang_cmake_builddir}/ClangTargets.cmake)
# Generate ClangConfig.cmake for the build tree.
set(CLANG_CONFIG_CMAKE_DIR "${clang_cmake_builddir}")
set(CLANG_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}")
set(CLANG_CONFIG_EXPORTS_FILE "${clang_cmake_builddir}/ClangTargets.cmake")
set(CLANG_CONFIG_INCLUDE_DIRS
"${CLANG_SOURCE_DIR}/include"
"${CLANG_BINARY_DIR}/include"
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/ClangConfig.cmake.in
${clang_cmake_builddir}/ClangConfig.cmake
@ONLY)
set(CLANG_CONFIG_CMAKE_DIR)
set(CLANG_CONFIG_LLVM_CMAKE_DIR)
set(CLANG_CONFIG_EXPORTS_FILE)
# Generate ClangConfig.cmake for the install tree.
set(CLANG_CONFIG_CODE "
# Compute the installation prefix from this LLVMConfig.cmake file location.
get_filename_component(CLANG_INSTALL_PREFIX \"\${CMAKE_CURRENT_LIST_FILE}\" PATH)")
# Construct the proper number of get_filename_component(... PATH)
# calls to compute the installation prefix.
string(REGEX REPLACE "/" ";" _count "${CLANG_INSTALL_PACKAGE_DIR}")
foreach(p ${_count})
set(CLANG_CONFIG_CODE "${CLANG_CONFIG_CODE}
get_filename_component(CLANG_INSTALL_PREFIX \"\${CLANG_INSTALL_PREFIX}\" PATH)")
endforeach(p)
set(CLANG_CONFIG_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${CLANG_INSTALL_PACKAGE_DIR}")
set(CLANG_CONFIG_LLVM_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}")
set(CLANG_CONFIG_EXPORTS_FILE "\${CLANG_CMAKE_DIR}/ClangTargets.cmake")
set(CLANG_CONFIG_INCLUDE_DIRS
"\${CLANG_INSTALL_PREFIX}/include"
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/ClangConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ClangConfig.cmake
@ONLY)
set(CLANG_CONFIG_CODE)
set(CLANG_CONFIG_CMAKE_DIR)
set(CLANG_CONFIG_EXPORTS_FILE)
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
get_property(clang_has_exports GLOBAL PROPERTY CLANG_HAS_EXPORTS)
if(clang_has_exports)
install(EXPORT ClangTargets DESTINATION ${CLANG_INSTALL_PACKAGE_DIR})
endif()
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ClangConfig.cmake
DESTINATION ${CLANG_INSTALL_PACKAGE_DIR})
endif()

View File

@ -1,20 +0,0 @@
# This file allows users to call find_package(Clang) and pick up our targets.
@CLANG_CONFIG_CODE@
find_package(LLVM REQUIRED CONFIG
HINTS "@CLANG_CONFIG_LLVM_CMAKE_DIR@")
set(CLANG_EXPORTED_TARGETS "@CLANG_EXPORTS@")
set(CLANG_CMAKE_DIR "@CLANG_CONFIG_CMAKE_DIR@")
set(CLANG_INCLUDE_DIRS "@CLANG_CONFIG_INCLUDE_DIRS@")
# Provide all our library targets to users.
include("@CLANG_CONFIG_EXPORTS_FILE@")
# By creating clang-tablegen-targets here, subprojects that depend on Clang's
# tablegen-generated headers can always depend on this target whether building
# in-tree with Clang or not.
if(NOT TARGET clang-tablegen-targets)
add_custom_target(clang-tablegen-targets)
endif()

View File

@ -1,51 +0,0 @@
# Looking for Z3 in CLANG_ANALYZER_Z3_INSTALL_DIR
find_path(Z3_INCLUDE_DIR NAMES z3.h
NO_DEFAULT_PATH
PATHS ${CLANG_ANALYZER_Z3_INSTALL_DIR}/include
PATH_SUFFIXES libz3 z3
)
find_library(Z3_LIBRARIES NAMES z3 libz3
NO_DEFAULT_PATH
PATHS ${CLANG_ANALYZER_Z3_INSTALL_DIR}
PATH_SUFFIXES lib bin
)
find_program(Z3_EXECUTABLE z3
NO_DEFAULT_PATH
PATHS ${CLANG_ANALYZER_Z3_INSTALL_DIR}
PATH_SUFFIXES bin
)
# If Z3 has not been found in CLANG_ANALYZER_Z3_INSTALL_DIR look in the default directories
find_path(Z3_INCLUDE_DIR NAMES z3.h
PATH_SUFFIXES libz3 z3
)
find_library(Z3_LIBRARIES NAMES z3 libz3
PATH_SUFFIXES lib bin
)
find_program(Z3_EXECUTABLE z3
PATH_SUFFIXES bin
)
if(Z3_INCLUDE_DIR AND Z3_LIBRARIES AND Z3_EXECUTABLE)
execute_process (COMMAND ${Z3_EXECUTABLE} -version
OUTPUT_VARIABLE libz3_version_str
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REGEX REPLACE "^Z3 version ([0-9.]+)" "\\1"
Z3_VERSION_STRING "${libz3_version_str}")
unset(libz3_version_str)
endif()
# handle the QUIETLY and REQUIRED arguments and set Z3_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Z3
REQUIRED_VARS Z3_LIBRARIES Z3_INCLUDE_DIR
VERSION_VAR Z3_VERSION_STRING)
mark_as_advanced(Z3_INCLUDE_DIR Z3_LIBRARIES)

View File

@ -1,19 +0,0 @@
set(PBM_PREFIX protobuf_mutator)
set(PBM_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PBM_PREFIX}/src/${PBM_PREFIX})
set(PBM_LIB_PATH ${PBM_PATH}-build/src/libprotobuf-mutator.a)
set(PBM_FUZZ_LIB_PATH ${PBM_PATH}-build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a)
ExternalProject_Add(${PBM_PREFIX}
PREFIX ${PBM_PREFIX}
GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git
GIT_TAG master
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
BUILD_BYPRODUCTS ${PBM_LIB_PATH} ${PBM_FUZZ_LIB_PATH}
UPDATE_COMMAND ""
INSTALL_COMMAND ""
)
set(ProtobufMutator_INCLUDE_DIRS ${PBM_PATH})
set(ProtobufMutator_LIBRARIES ${PBM_FUZZ_LIB_PATH} ${PBM_LIB_PATH})

View File

@ -1,298 +0,0 @@
================
AddressSanitizer
================
.. contents::
:local:
Introduction
============
AddressSanitizer is a fast memory error detector. It consists of a compiler
instrumentation module and a run-time library. The tool can detect the
following types of bugs:
* Out-of-bounds accesses to heap, stack and globals
* Use-after-free
* Use-after-return (runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1`)
* Use-after-scope (clang flag `-fsanitize-address-use-after-scope`)
* Double-free, invalid free
* Memory leaks (experimental)
Typical slowdown introduced by AddressSanitizer is **2x**.
How to build
============
Build LLVM/Clang with `CMake <https://llvm.org/docs/CMake.html>`_.
Usage
=====
Simply compile and link your program with ``-fsanitize=address`` flag. The
AddressSanitizer run-time library should be linked to the final executable, so
make sure to use ``clang`` (not ``ld``) for the final link step. When linking
shared libraries, the AddressSanitizer run-time is not linked, so
``-Wl,-z,defs`` may cause link errors (don't use it with AddressSanitizer). To
get a reasonable performance add ``-O1`` or higher. To get nicer stack traces
in error messages add ``-fno-omit-frame-pointer``. To get perfect stack traces
you may need to disable inlining (just use ``-O1``) and tail call elimination
(``-fno-optimize-sibling-calls``).
.. code-block:: console
% cat example_UseAfterFree.cc
int main(int argc, char **argv) {
int *array = new int[100];
delete [] array;
return array[argc]; // BOOM
}
# Compile and link
% clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc
or:
.. code-block:: console
# Compile
% clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
# Link
% clang++ -g -fsanitize=address example_UseAfterFree.o
If a bug is detected, the program will print an error message to stderr and
exit with a non-zero exit code. AddressSanitizer exits on the first detected error.
This is by design:
* This approach allows AddressSanitizer to produce faster and smaller generated code
(both by ~5%).
* Fixing bugs becomes unavoidable. AddressSanitizer does not produce
false alarms. Once a memory corruption occurs, the program is in an inconsistent
state, which could lead to confusing results and potentially misleading
subsequent reports.
If your process is sandboxed and you are running on OS X 10.10 or earlier, you
will need to set ``DYLD_INSERT_LIBRARIES`` environment variable and point it to
the ASan library that is packaged with the compiler used to build the
executable. (You can find the library by searching for dynamic libraries with
``asan`` in their name.) If the environment variable is not set, the process will
try to re-exec. Also keep in mind that when moving the executable to another machine,
the ASan library will also need to be copied over.
Symbolizing the Reports
=========================
To make AddressSanitizer symbolize its output
you need to set the ``ASAN_SYMBOLIZER_PATH`` environment variable to point to
the ``llvm-symbolizer`` binary (or make sure ``llvm-symbolizer`` is in your
``$PATH``):
.. code-block:: console
% ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer ./a.out
==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
READ of size 4 at 0x7f7ddab8c084 thread T0
#0 0x403c8c in main example_UseAfterFree.cc:4
#1 0x7f7ddabcac4d in __libc_start_main ??:0
0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
freed by thread T0 here:
#0 0x404704 in operator delete[](void*) ??:0
#1 0x403c53 in main example_UseAfterFree.cc:4
#2 0x7f7ddabcac4d in __libc_start_main ??:0
previously allocated by thread T0 here:
#0 0x404544 in operator new[](unsigned long) ??:0
#1 0x403c43 in main example_UseAfterFree.cc:2
#2 0x7f7ddabcac4d in __libc_start_main ??:0
==9442== ABORTING
If that does not work for you (e.g. your process is sandboxed), you can use a
separate script to symbolize the result offline (online symbolization can be
force disabled by setting ``ASAN_OPTIONS=symbolize=0``):
.. code-block:: console
% ASAN_OPTIONS=symbolize=0 ./a.out 2> log
% projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt
==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
READ of size 4 at 0x7f7ddab8c084 thread T0
#0 0x403c8c in main example_UseAfterFree.cc:4
#1 0x7f7ddabcac4d in __libc_start_main ??:0
...
Note that on OS X you may need to run ``dsymutil`` on your binary to have the
file\:line info in the AddressSanitizer reports.
Additional Checks
=================
Initialization order checking
-----------------------------
AddressSanitizer can optionally detect dynamic initialization order problems,
when initialization of globals defined in one translation unit uses
globals defined in another translation unit. To enable this check at runtime,
you should set environment variable
``ASAN_OPTIONS=check_initialization_order=1``.
Note that this option is not supported on OS X.
Memory leak detection
---------------------
For more information on leak detector in AddressSanitizer, see
:doc:`LeakSanitizer`. The leak detection is turned on by default on Linux,
and can be enabled using ``ASAN_OPTIONS=detect_leaks=1`` on OS X;
however, it is not yet supported on other platforms.
Issue Suppression
=================
AddressSanitizer is not expected to produce false positives. If you see one,
look again; most likely it is a true positive!
Suppressing Reports in External Libraries
-----------------------------------------
Runtime interposition allows AddressSanitizer to find bugs in code that is
not being recompiled. If you run into an issue in external libraries, we
recommend immediately reporting it to the library maintainer so that it
gets addressed. However, you can use the following suppression mechanism
to unblock yourself and continue on with the testing. This suppression
mechanism should only be used for suppressing issues in external code; it
does not work on code recompiled with AddressSanitizer. To suppress errors
in external libraries, set the ``ASAN_OPTIONS`` environment variable to point
to a suppression file. You can either specify the full path to the file or the
path of the file relative to the location of your executable.
.. code-block:: bash
ASAN_OPTIONS=suppressions=MyASan.supp
Use the following format to specify the names of the functions or libraries
you want to suppress. You can see these in the error report. Remember that
the narrower the scope of the suppression, the more bugs you will be able to
catch.
.. code-block:: bash
interceptor_via_fun:NameOfCFunctionToSuppress
interceptor_via_fun:-[ClassName objCMethodToSuppress:]
interceptor_via_lib:NameOfTheLibraryToSuppress
Conditional Compilation with ``__has_feature(address_sanitizer)``
-----------------------------------------------------------------
In some cases one may need to execute different code depending on whether
AddressSanitizer is enabled.
:ref:`\_\_has\_feature <langext-__has_feature-__has_extension>` can be used for
this purpose.
.. code-block:: c
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
// code that builds only under AddressSanitizer
# endif
#endif
Disabling Instrumentation with ``__attribute__((no_sanitize("address")))``
--------------------------------------------------------------------------
Some code should not be instrumented by AddressSanitizer. One may use
the attribute ``__attribute__((no_sanitize("address")))`` (which has
deprecated synonyms `no_sanitize_address` and
`no_address_safety_analysis`) to disable instrumentation of a
particular function. This attribute may not be supported by other
compilers, so we suggest to use it together with
``__has_feature(address_sanitizer)``.
The same attribute used on a global variable prevents AddressSanitizer
from adding redzones around it and detecting out of bounds accesses.
Suppressing Errors in Recompiled Code (Blacklist)
-------------------------------------------------
AddressSanitizer supports ``src`` and ``fun`` entity types in
:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
in the specified source files or functions. Additionally, AddressSanitizer
introduces ``global`` and ``type`` entity types that can be used to
suppress error reports for out-of-bound access to globals with certain
names and types (you may only specify class or struct types).
You may use an ``init`` category to suppress reports about initialization-order
problems happening in certain source files or with certain global variables.
.. code-block:: bash
# Suppress error reports for code in a file or in a function:
src:bad_file.cpp
# Ignore all functions with names containing MyFooBar:
fun:*MyFooBar*
# Disable out-of-bound checks for global:
global:bad_array
# Disable out-of-bound checks for global instances of a given class ...
type:Namespace::BadClassName
# ... or a given struct. Use wildcard to deal with anonymous namespace.
type:Namespace2::*::BadStructName
# Disable initialization-order checks for globals:
global:bad_init_global=init
type:*BadInitClassSubstring*=init
src:bad/init/files/*=init
Suppressing memory leaks
------------------------
Memory leak reports produced by :doc:`LeakSanitizer` (if it is run as a part
of AddressSanitizer) can be suppressed by a separate file passed as
.. code-block:: bash
LSAN_OPTIONS=suppressions=MyLSan.supp
which contains lines of the form `leak:<pattern>`. Memory leak will be
suppressed if pattern matches any function name, source file name, or
library name in the symbolized stack trace of the leak report. See
`full documentation
<https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#suppressions>`_
for more details.
Limitations
===========
* AddressSanitizer uses more real memory than a native run. Exact overhead
depends on the allocations sizes. The smaller the allocations you make the
bigger the overhead is.
* AddressSanitizer uses more stack memory. We have seen up to 3x increase.
* On 64-bit platforms AddressSanitizer maps (but not reserves) 16+ Terabytes of
virtual address space. This means that tools like ``ulimit`` may not work as
usually expected.
* Static linking of executables is not supported.
Supported Platforms
===================
AddressSanitizer is supported on:
* Linux i386/x86\_64 (tested on Ubuntu 12.04)
* OS X 10.7 - 10.11 (i386/x86\_64)
* iOS Simulator
* Android ARM
* NetBSD i386/x86\_64
* FreeBSD i386/x86\_64 (tested on FreeBSD 11-current)
* Windows 8.1+ (i386/x86\_64)
Ports to various other platforms are in progress.
Current Status
==============
AddressSanitizer is fully functional on supported platforms starting from LLVM
3.1. The test suite is integrated into CMake build and can be run with ``make
check-asan`` command.
The Windows port is functional and is used by Chrome and Firefox, but it is not
as well supported as the other ports.
More Information
================
`<https://github.com/google/sanitizers/wiki/AddressSanitizer>`_

View File

@ -1,13 +0,0 @@
..
-------------------------------------------------------------------
NOTE: This file is automatically generated by running clang-tblgen
-gen-attr-docs. Do not edit this file by hand!! The contents for
this file are automatically generated by a server-side process.
Please do not commit this file. The file exists for local testing
purposes only.
-------------------------------------------------------------------
===================
Attributes in Clang
===================

File diff suppressed because it is too large Load Diff

View File

@ -1,943 +0,0 @@
==================================
Block Implementation Specification
==================================
.. contents::
:local:
History
=======
* 2008/7/14 - created.
* 2008/8/21 - revised, C++.
* 2008/9/24 - add ``NULL`` ``isa`` field to ``__block`` storage.
* 2008/10/1 - revise block layout to use a ``static`` descriptor structure.
* 2008/10/6 - revise block layout to use an unsigned long int flags.
* 2008/10/28 - specify use of ``_Block_object_assign`` and
``_Block_object_dispose`` for all "Object" types in helper functions.
* 2008/10/30 - revise new layout to have invoke function in same place.
* 2008/10/30 - add ``__weak`` support.
* 2010/3/16 - rev for stret return, signature field.
* 2010/4/6 - improved wording.
* 2013/1/6 - improved wording and converted to rst.
This document describes the Apple ABI implementation specification of Blocks.
The first shipping version of this ABI is found in Mac OS X 10.6, and shall be
referred to as 10.6.ABI. As of 2010/3/16, the following describes the ABI
contract with the runtime and the compiler, and, as necessary, will be referred
to as ABI.2010.3.16.
Since the Apple ABI references symbols from other elements of the system, any
attempt to use this ABI on systems prior to SnowLeopard is undefined.
High Level
==========
The ABI of ``Blocks`` consist of their layout and the runtime functions required
by the compiler. A ``Block`` consists of a structure of the following form:
.. code-block:: c
struct Block_literal_1 {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};
The following flags bits are in use thusly for a possible ABI.2010.3.16:
.. code-block:: c
enum {
// Set to true on blocks that have captures (and thus are not true
// global blocks) but are known not to escape for various other
// reasons. For backward compatiblity with old runtimes, whenever
// BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
// non-escaping block returns the original block and releasing such a
// block is a no-op, which is exactly how global blocks are handled.
BLOCK_IS_NOESCAPE = (1 << 23),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30),
};
In 10.6.ABI the (1<<29) was usually set and was always ignored by the runtime -
it had been a transitional marker that did not get deleted after the
transition. This bit is now paired with (1<<30), and represented as the pair
(3<<30), for the following combinations of valid bit settings, and their
meanings:
.. code-block:: c
switch (flags & (3<<29)) {
case (0<<29): 10.6.ABI, no signature field available
case (1<<29): 10.6.ABI, no signature field available
case (2<<29): ABI.2010.3.16, regular calling convention, presence of signature field
case (3<<29): ABI.2010.3.16, stret calling convention, presence of signature field,
}
The signature field is not always populated.
The following discussions are presented as 10.6.ABI otherwise.
``Block`` literals may occur within functions where the structure is created in
stack local memory. They may also appear as initialization expressions for
``Block`` variables of global or ``static`` local variables.
When a ``Block`` literal expression is evaluated the stack based structure is
initialized as follows:
1. A ``static`` descriptor structure is declared and initialized as follows:
a. The ``invoke`` function pointer is set to a function that takes the
``Block`` structure as its first argument and the rest of the arguments (if
any) to the ``Block`` and executes the ``Block`` compound statement.
b. The ``size`` field is set to the size of the following ``Block`` literal
structure.
c. The ``copy_helper`` and ``dispose_helper`` function pointers are set to
respective helper functions if they are required by the ``Block`` literal.
2. A stack (or global) ``Block`` literal data structure is created and
initialized as follows:
a. The ``isa`` field is set to the address of the external
``_NSConcreteStackBlock``, which is a block of uninitialized memory supplied
in ``libSystem``, or ``_NSConcreteGlobalBlock`` if this is a static or file
level ``Block`` literal.
b. The ``flags`` field is set to zero unless there are variables imported
into the ``Block`` that need helper functions for program level
``Block_copy()`` and ``Block_release()`` operations, in which case the
(1<<25) flags bit is set.
As an example, the ``Block`` literal expression:
.. code-block:: c
^ { printf("hello world\n"); }
would cause the following to be created on a 32-bit system:
.. code-block:: c
struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *);
struct __block_descriptor_1 *descriptor;
};
void __block_invoke_1(struct __block_literal_1 *_block) {
printf("hello world\n");
}
static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };
and where the ``Block`` literal itself appears:
.. code-block:: c
struct __block_literal_1 _block_literal = {
&_NSConcreteStackBlock,
(1<<29), <uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
A ``Block`` imports other ``Block`` references, ``const`` copies of other
variables, and variables marked ``__block``. In Objective-C, variables may
additionally be objects.
When a ``Block`` literal expression is used as the initial value of a global
or ``static`` local variable, it is initialized as follows:
.. code-block:: c
struct __block_literal_1 __block_literal_1 = {
&_NSConcreteGlobalBlock,
(1<<28)|(1<<29), <uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
that is, a different address is provided as the first value and a particular
(1<<28) bit is set in the ``flags`` field, and otherwise it is the same as for
stack based ``Block`` literals. This is an optimization that can be used for
any ``Block`` literal that imports no ``const`` or ``__block`` storage
variables.
Imported Variables
==================
Variables of ``auto`` storage class are imported as ``const`` copies. Variables
of ``__block`` storage class are imported as a pointer to an enclosing data
structure. Global variables are simply referenced and not considered as
imported.
Imported ``const`` copy variables
---------------------------------
Automatic storage variables not marked with ``__block`` are imported as
``const`` copies.
The simplest example is that of importing a variable of type ``int``:
.. code-block:: c
int x = 10;
void (^vv)(void) = ^{ printf("x is %d\n", x); }
x = 11;
vv();
which would be compiled to:
.. code-block:: c
struct __block_literal_2 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_2 *);
struct __block_descriptor_2 *descriptor;
const int x;
};
void __block_invoke_2(struct __block_literal_2 *_block) {
printf("x is %d\n", _block->x);
}
static struct __block_descriptor_2 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };
and:
.. code-block:: c
struct __block_literal_2 __block_literal_2 = {
&_NSConcreteStackBlock,
(1<<29), <uninitialized>,
__block_invoke_2,
&__block_descriptor_2,
x
};
In summary, scalars, structures, unions, and function pointers are generally
imported as ``const`` copies with no need for helper functions.
Imported ``const`` copy of ``Block`` reference
----------------------------------------------
The first case where copy and dispose helper functions are required is for the
case of when a ``Block`` itself is imported. In this case both a
``copy_helper`` function and a ``dispose_helper`` function are needed. The
``copy_helper`` function is passed both the existing stack based pointer and the
pointer to the new heap version and should call back into the runtime to
actually do the copy operation on the imported fields within the ``Block``. The
runtime functions are all described in :ref:`RuntimeHelperFunctions`.
A quick example:
.. code-block:: c
void (^existingBlock)(void) = ...;
void (^vv)(void) = ^{ existingBlock(); }
vv();
struct __block_literal_3 {
...; // existing block
};
struct __block_literal_4 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_4 *);
struct __block_literal_3 *const existingBlock;
};
void __block_invoke_4(struct __block_literal_2 *_block) {
__block->existingBlock->invoke(__block->existingBlock);
}
void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
//_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
_Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}
void __block_dispose_4(struct __block_literal_4 *src) {
// was _Block_destroy
_Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}
static struct __block_descriptor_4 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
void (*dispose_helper)(struct __block_literal_4 *);
} __block_descriptor_4 = {
0,
sizeof(struct __block_literal_4),
__block_copy_4,
__block_dispose_4,
};
and where said ``Block`` is used:
.. code-block:: c
struct __block_literal_4 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), <uninitialized>
__block_invoke_4,
& __block_descriptor_4
existingBlock,
};
Importing ``__attribute__((NSObject))`` variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
GCC introduces ``__attribute__((NSObject))`` on structure pointers to mean "this
is an object". This is useful because many low level data structures are
declared as opaque structure pointers, e.g. ``CFStringRef``, ``CFArrayRef``,
etc. When used from C, however, these are still really objects and are the
second case where that requires copy and dispose helper functions to be
generated. The copy helper functions generated by the compiler should use the
``_Block_object_assign`` runtime helper function and in the dispose helper the
``_Block_object_dispose`` runtime helper function should be called.
For example, ``Block`` foo in the following:
.. code-block:: c
struct Opaque *__attribute__((NSObject)) objectPointer = ...;
...
void (^foo)(void) = ^{ CFPrint(objectPointer); };
would have the following helper functions generated:
.. code-block:: c
void __block_copy_foo(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
_Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
}
void __block_dispose_foo(struct __block_literal_5 *src) {
_Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
}
Imported ``__block`` marked variables
-------------------------------------
Layout of ``__block`` marked variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The compiler must embed variables that are marked ``__block`` in a specialized
structure of the form:
.. code-block:: c
struct _block_byref_foo {
void *isa;
struct Block_byref *forwarding;
int flags; //refcount;
int size;
typeof(marked_variable) marked_variable;
};
Variables of certain types require helper functions for when ``Block_copy()``
and ``Block_release()`` are performed upon a referencing ``Block``. At the "C"
level only variables that are of type ``Block`` or ones that have
``__attribute__((NSObject))`` marked require helper functions. In Objective-C
objects require helper functions and in C++ stack based objects require helper
functions. Variables that require helper functions use the form:
.. code-block:: c
struct _block_byref_foo {
void *isa;
struct _block_byref_foo *forwarding;
int flags; //refcount;
int size;
// helper functions called via Block_copy() and Block_release()
void (*byref_keep)(void *dst, void *src);
void (*byref_dispose)(void *);
typeof(marked_variable) marked_variable;
};
The structure is initialized such that:
a. The ``forwarding`` pointer is set to the beginning of its enclosing
structure.
b. The ``size`` field is initialized to the total size of the enclosing
structure.
c. The ``flags`` field is set to either 0 if no helper functions are needed
or (1<<25) if they are.
d. The helper functions are initialized (if present).
e. The variable itself is set to its initial value.
f. The ``isa`` field is set to ``NULL``.
Access to ``__block`` variables from within its lexical scope
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In order to "move" the variable to the heap upon a ``copy_helper`` operation the
compiler must rewrite access to such a variable to be indirect through the
structures ``forwarding`` pointer. For example:
.. code-block:: c
int __block i = 10;
i = 11;
would be rewritten to be:
.. code-block:: c
struct _block_byref_i {
void *isa;
struct _block_byref_i *forwarding;
int flags; //refcount;
int size;
int captured_i;
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };
i.forwarding->captured_i = 11;
In the case of a ``Block`` reference variable being marked ``__block`` the
helper code generated must use the ``_Block_object_assign`` and
``_Block_object_dispose`` routines supplied by the runtime to make the
copies. For example:
.. code-block:: c
__block void (voidBlock)(void) = blockA;
voidBlock = blockB;
would translate into:
.. code-block:: c
struct _block_byref_voidBlock {
void *isa;
struct _block_byref_voidBlock *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
void (*byref_dispose)(struct _block_byref_voidBlock *);
void (^captured_voidBlock)(void);
};
void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
//_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
_Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
}
void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
//_Block_destroy(param->captured_voidBlock, 0);
_Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
and:
.. code-block:: c
struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
.byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
.captured_voidBlock=blockA )};
voidBlock.forwarding->captured_voidBlock = blockB;
Importing ``__block`` variables into ``Blocks``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A ``Block`` that uses a ``__block`` variable in its compound statement body must
import the variable and emit ``copy_helper`` and ``dispose_helper`` helper
functions that, in turn, call back into the runtime to actually copy or release
the ``byref`` data block using the functions ``_Block_object_assign`` and
``_Block_object_dispose``.
For example:
.. code-block:: c
int __block i = 2;
functioncall(^{ i = 10; });
would translate to:
.. code-block:: c
struct _block_byref_i {
void *isa; // set to NULL
struct _block_byref_voidBlock *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
void (*byref_dispose)(struct _block_byref_i *);
int captured_i;
};
struct __block_literal_5 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_5 *);
struct __block_descriptor_5 *descriptor;
struct _block_byref_i *i_holder;
};
void __block_invoke_5(struct __block_literal_5 *_block) {
_block->forwarding->captured_i = 10;
}
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
//_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
_Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
void __block_dispose_5(struct __block_literal_5 *src) {
//_Block_byref_release(src->captured_i);
_Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
static struct __block_descriptor_5 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
and:
.. code-block:: c
struct _block_byref_i i = {( .isa=NULL, .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i), .captured_i=2 )};
struct __block_literal_5 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), <uninitialized>,
__block_invoke_5,
&__block_descriptor_5,
&i,
};
Importing ``__attribute__((NSObject))`` ``__block`` variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A ``__block`` variable that is also marked ``__attribute__((NSObject))`` should
have ``byref_keep`` and ``byref_dispose`` helper functions that use
``_Block_object_assign`` and ``_Block_object_dispose``.
``__block`` escapes
^^^^^^^^^^^^^^^^^^^
Because ``Blocks`` referencing ``__block`` variables may have ``Block_copy()``
performed upon them the underlying storage for the variables may move to the
heap. In Objective-C Garbage Collection Only compilation environments the heap
used is the garbage collected one and no further action is required. Otherwise
the compiler must issue a call to potentially release any heap storage for
``__block`` variables at all escapes or terminations of their scope. The call
should be:
.. code-block:: c
_Block_object_dispose(&_block_byref_foo, BLOCK_FIELD_IS_BYREF);
Nesting
^^^^^^^
``Blocks`` may contain ``Block`` literal expressions. Any variables used within
inner blocks are imported into all enclosing ``Block`` scopes even if the
variables are not used. This includes ``const`` imports as well as ``__block``
variables.
Objective C Extensions to ``Blocks``
====================================
Importing Objects
-----------------
Objects should be treated as ``__attribute__((NSObject))`` variables; all
``copy_helper``, ``dispose_helper``, ``byref_keep``, and ``byref_dispose``
helper functions should use ``_Block_object_assign`` and
``_Block_object_dispose``. There should be no code generated that uses
``*-retain`` or ``*-release`` methods.
``Blocks`` as Objects
---------------------
The compiler will treat ``Blocks`` as objects when synthesizing property setters
and getters, will characterize them as objects when generating garbage
collection strong and weak layout information in the same manner as objects, and
will issue strong and weak write-barrier assignments in the same manner as
objects.
``__weak __block`` Support
--------------------------
Objective-C (and Objective-C++) support the ``__weak`` attribute on ``__block``
variables. Under normal circumstances the compiler uses the Objective-C runtime
helper support functions ``objc_assign_weak`` and ``objc_read_weak``. Both
should continue to be used for all reads and writes of ``__weak __block``
variables:
.. code-block:: c
objc_read_weak(&block->byref_i->forwarding->i)
The ``__weak`` variable is stored in a ``_block_byref_foo`` structure and the
``Block`` has copy and dispose helpers for this structure that call:
.. code-block:: c
_Block_object_assign(&dest->_block_byref_i, src-> _block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
and:
.. code-block:: c
_Block_object_dispose(src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
In turn, the ``block_byref`` copy support helpers distinguish between whether
the ``__block`` variable is a ``Block`` or not and should either call:
.. code-block:: c
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLER);
for something declared as an object or:
.. code-block:: c
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
for something declared as a ``Block``.
A full example follows:
.. code-block:: c
__block __weak id obj = <initialization expression>;
functioncall(^{ [obj somemessage]; });
would translate to:
.. code-block:: c
struct _block_byref_obj {
void *isa; // uninitialized
struct _block_byref_obj *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
void (*byref_dispose)(struct _block_byref_i *);
id captured_obj;
};
void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
//_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
_Block_object_assign(&dst->captured_obj, src->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
}
void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
//_Block_destroy(param->captured_obj, 0);
_Block_object_dispose(param->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
};
for the block ``byref`` part and:
.. code-block:: c
struct __block_literal_5 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_5 *);
struct __block_descriptor_5 *descriptor;
struct _block_byref_obj *byref_obj;
};
void __block_invoke_5(struct __block_literal_5 *_block) {
[objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
}
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
//_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
_Block_object_assign(&dst->byref_obj, src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
}
void __block_dispose_5(struct __block_literal_5 *src) {
//_Block_byref_release(src->byref_obj);
_Block_object_dispose(src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
}
static struct __block_descriptor_5 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5), __block_copy_5, __block_dispose_5 };
and within the compound statement:
.. code-block:: c
truct _block_byref_obj obj = {( .forwarding=&obj, .flags=(1<<25), .size=sizeof(struct _block_byref_obj),
.byref_keep=_block_byref_obj_keep, .byref_dispose=_block_byref_obj_dispose,
.captured_obj = <initialization expression> )};
truct __block_literal_5 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), <uninitialized>,
__block_invoke_5,
&__block_descriptor_5,
&obj, // a reference to the on-stack structure containing "captured_obj"
};
functioncall(_block_literal->invoke(&_block_literal));
C++ Support
===========
Within a block stack based C++ objects are copied into ``const`` copies using
the copy constructor. It is an error if a stack based C++ object is used within
a block if it does not have a copy constructor. In addition both copy and
destroy helper routines must be synthesized for the block to support the
``Block_copy()`` operation, and the flags work marked with the (1<<26) bit in
addition to the (1<<25) bit. The copy helper should call the constructor using
appropriate offsets of the variable within the supplied stack based block source
and heap based destination for all ``const`` constructed copies, and similarly
should call the destructor in the destroy routine.
As an example, suppose a C++ class ``FOO`` existed with a copy constructor.
Within a code block a stack version of a ``FOO`` object is declared and used
within a ``Block`` literal expression:
.. code-block:: c++
{
FOO foo;
void (^block)(void) = ^{ printf("%d\n", foo.value()); };
}
The compiler would synthesize:
.. code-block:: c++
struct __block_literal_10 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_10 *);
struct __block_descriptor_10 *descriptor;
const FOO foo;
};
void __block_invoke_10(struct __block_literal_10 *_block) {
printf("%d\n", _block->foo.value());
}
void __block_literal_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
FOO_ctor(&dst->foo, &src->foo);
}
void __block_dispose_10(struct __block_literal_10 *src) {
FOO_dtor(&src->foo);
}
static struct __block_descriptor_10 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_10 *dst, struct __block_literal_10 *src);
void (*dispose_helper)(struct __block_literal_10 *);
} __block_descriptor_10 = { 0, sizeof(struct __block_literal_10), __block_copy_10, __block_dispose_10 };
and the code would be:
.. code-block:: c++
{
FOO foo;
comp_ctor(&foo); // default constructor
struct __block_literal_10 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<26)|(1<<29), <uninitialized>,
__block_invoke_10,
&__block_descriptor_10,
};
comp_ctor(&_block_literal->foo, &foo); // const copy into stack version
struct __block_literal_10 &block = &_block_literal; // assign literal to block variable
block->invoke(block); // invoke block
comp_dtor(&_block_literal->foo); // destroy stack version of const block copy
comp_dtor(&foo); // destroy original version
}
C++ objects stored in ``__block`` storage start out on the stack in a
``block_byref`` data structure as do other variables. Such objects (if not
``const`` objects) must support a regular copy constructor. The ``block_byref``
data structure will have copy and destroy helper routines synthesized by the
compiler. The copy helper will have code created to perform the copy
constructor based on the initial stack ``block_byref`` data structure, and will
also set the (1<<26) bit in addition to the (1<<25) bit. The destroy helper
will have code to do the destructor on the object stored within the supplied
``block_byref`` heap data structure. For example,
.. code-block:: c++
__block FOO blockStorageFoo;
requires the normal constructor for the embedded ``blockStorageFoo`` object:
.. code-block:: c++
FOO_ctor(& _block_byref_blockStorageFoo->blockStorageFoo);
and at scope termination the destructor:
.. code-block:: c++
FOO_dtor(& _block_byref_blockStorageFoo->blockStorageFoo);
Note that the forwarding indirection is *NOT* used.
The compiler would need to generate (if used from a block literal) the following
copy/dispose helpers:
.. code-block:: c++
void _block_byref_obj_keep(struct _block_byref_blockStorageFoo *dst, struct _block_byref_blockStorageFoo *src) {
FOO_ctor(&dst->blockStorageFoo, &src->blockStorageFoo);
}
void _block_byref_obj_dispose(struct _block_byref_blockStorageFoo *src) {
FOO_dtor(&src->blockStorageFoo);
}
for the appropriately named constructor and destructor for the class/struct
``FOO``.
To support member variable and function access the compiler will synthesize a
``const`` pointer to a block version of the ``this`` pointer.
.. _RuntimeHelperFunctions:
Runtime Helper Functions
========================
The runtime helper functions are described in
``/usr/local/include/Block_private.h``. To summarize their use, a ``Block``
requires copy/dispose helpers if it imports any block variables, ``__block``
storage variables, ``__attribute__((NSObject))`` variables, or C++ ``const``
copied objects with constructor/destructors. The (1<<26) bit is set and
functions are generated.
The block copy helper function should, for each of the variables of the type
mentioned above, call:
.. code-block:: c
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<apropos>);
in the copy helper and:
.. code-block:: c
_Block_object_dispose(->target, BLOCK_FIELD_<apropos>);
in the dispose helper where ``<apropos>`` is:
.. code-block:: c
enum {
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
};
and of course the constructors/destructors for ``const`` copied C++ objects.
The ``block_byref`` data structure similarly requires copy/dispose helpers for
block variables, ``__attribute__((NSObject))`` variables, or C++ ``const``
copied objects with constructor/destructors, and again the (1<<26) bit is set
and functions are generated in the same manner.
Under ObjC we allow ``__weak`` as an attribute on ``__block`` variables, and
this causes the addition of ``BLOCK_FIELD_IS_WEAK`` orred onto the
``BLOCK_FIELD_IS_BYREF`` flag when copying the ``block_byref`` structure in the
``Block`` copy helper, and onto the ``BLOCK_FIELD_<apropos>`` field within the
``block_byref`` copy/dispose helper calls.
The prototypes, and summary, of the helper functions are:
.. code-block:: c
/* Certain field types require runtime assistance when being copied to the
heap. The following function is used to copy fields of types: blocks,
pointers to byref structures, and objects (including
__attribute__((NSObject)) pointers. BLOCK_FIELD_IS_WEAK is orthogonal to
the other choices which are mutually exclusive. Only in a Block copy
helper will one see BLOCK_FIELD_IS_BYREF.
*/
void _Block_object_assign(void *destAddr, const void *object, const int flags);
/* Similarly a compiler generated dispose helper needs to call back for each
field of the byref data structure. (Currently the implementation only
packs one field into the byref structure but in principle there could be
more). The same flags used in the copy helper should be used for each
call generated to this function:
*/
void _Block_object_dispose(const void *object, const int flags);
Copyright
=========
Copyright 2008-2010 Apple, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1 +0,0 @@
*NOTE* This document has moved to https://clang.llvm.org/docs/Block-ABI-Apple.html.

View File

@ -1,361 +0,0 @@
.. role:: block-term
=================================
Language Specification for Blocks
=================================
.. contents::
:local:
Revisions
=========
- 2008/2/25 --- created
- 2008/7/28 --- revised, ``__block`` syntax
- 2008/8/13 --- revised, Block globals
- 2008/8/21 --- revised, C++ elaboration
- 2008/11/1 --- revised, ``__weak`` support
- 2009/1/12 --- revised, explicit return types
- 2009/2/10 --- revised, ``__block`` objects need retain
Overview
========
A new derived type is introduced to C and, by extension, Objective-C,
C++, and Objective-C++
The Block Type
==============
Like function types, the :block-term:`Block type` is a pair consisting
of a result value type and a list of parameter types very similar to a
function type. Blocks are intended to be used much like functions with
the key distinction being that in addition to executable code they
also contain various variable bindings to automatic (stack) or managed
(heap) memory.
The abstract declarator,
.. code-block:: c
int (^)(char, float)
describes a reference to a Block that, when invoked, takes two
parameters, the first of type char and the second of type float, and
returns a value of type int. The Block referenced is of opaque data
that may reside in automatic (stack) memory, global memory, or heap
memory.
Block Variable Declarations
===========================
A :block-term:`variable with Block type` is declared using function
pointer style notation substituting ``^`` for ``*``. The following are
valid Block variable declarations:
.. code-block:: c
void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int, char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
Variadic ``...`` arguments are supported. [variadic.c] A Block that
takes no arguments must specify void in the argument list [voidarg.c].
An empty parameter list does not represent, as K&R provide, an
unspecified argument list. Note: both gcc and clang support K&R style
as a convenience.
A Block reference may be cast to a pointer of arbitrary type and vice
versa. [cast.c] A Block reference may not be dereferenced via the
pointer dereference operator ``*``, and thus a Block's size may not be
computed at compile time. [sizeof.c]
Block Literal Expressions
=========================
A :block-term:`Block literal expression` produces a reference to a
Block. It is introduced by the use of the ``^`` token as a unary
operator.
.. code-block:: c
Block_literal_expression ::= ^ block_decl compound_statement_body
block_decl ::=
block_decl ::= parameter_list
block_decl ::= type_expression
where type expression is extended to allow ``^`` as a Block reference
(pointer) where ``*`` is allowed as a function reference (pointer).
The following Block literal:
.. code-block:: c
^ void (void) { printf("hello world\n"); }
produces a reference to a Block with no arguments with no return value.
The return type is optional and is inferred from the return
statements. If the return statements return a value, they all must
return a value of the same type. If there is no value returned the
inferred type of the Block is void; otherwise it is the type of the
return statement value.
If the return type is omitted and the argument list is ``( void )``,
the ``( void )`` argument list may also be omitted.
So:
.. code-block:: c
^ ( void ) { printf("hello world\n"); }
and:
.. code-block:: c
^ { printf("hello world\n"); }
are exactly equivalent constructs for the same expression.
The type_expression extends C expression parsing to accommodate Block
reference declarations as it accommodates function pointer
declarations.
Given:
.. code-block:: c
typedef int (*pointerToFunctionThatReturnsIntWithCharArg)(char);
pointerToFunctionThatReturnsIntWithCharArg functionPointer;
^ pointerToFunctionThatReturnsIntWithCharArg (float x) { return functionPointer; }
and:
.. code-block:: c
^ int ((*)(float x))(char) { return functionPointer; }
are equivalent expressions, as is:
.. code-block:: c
^(float x) { return functionPointer; }
[returnfunctionptr.c]
The compound statement body establishes a new lexical scope within
that of its parent. Variables used within the scope of the compound
statement are bound to the Block in the normal manner with the
exception of those in automatic (stack) storage. Thus one may access
functions and global variables as one would expect, as well as static
local variables. [testme]
Local automatic (stack) variables referenced within the compound
statement of a Block are imported and captured by the Block as const
copies. The capture (binding) is performed at the time of the Block
literal expression evaluation.
The compiler is not required to capture a variable if it can prove
that no references to the variable will actually be evaluated.
Programmers can force a variable to be captured by referencing it in a
statement at the beginning of the Block, like so:
.. code-block:: c
(void) foo;
This matters when capturing the variable has side-effects, as it can
in Objective-C or C++.
The lifetime of variables declared in a Block is that of a function;
each activation frame contains a new copy of variables declared within
the local scope of the Block. Such variable declarations should be
allowed anywhere [testme] rather than only when C99 parsing is
requested, including for statements. [testme]
Block literal expressions may occur within Block literal expressions
(nest) and all variables captured by any nested blocks are implicitly
also captured in the scopes of their enclosing Blocks.
A Block literal expression may be used as the initialization value for
Block variables at global or local static scope.
The Invoke Operator
===================
Blocks are :block-term:`invoked` using function call syntax with a
list of expression parameters of types corresponding to the
declaration and returning a result type also according to the
declaration. Given:
.. code-block:: c
int (^x)(char);
void (^z)(void);
int (^(*y))(char) = &x;
the following are all legal Block invocations:
.. code-block:: c
x('a');
(*y)('a');
(true ? x : *y)('a')
The Copy and Release Operations
===============================
The compiler and runtime provide :block-term:`copy` and
:block-term:`release` operations for Block references that create and,
in matched use, release allocated storage for referenced Blocks.
The copy operation ``Block_copy()`` is styled as a function that takes
an arbitrary Block reference and returns a Block reference of the same
type. The release operation, ``Block_release()``, is styled as a
function that takes an arbitrary Block reference and, if dynamically
matched to a Block copy operation, allows recovery of the referenced
allocated memory.
The ``__block`` Storage Qualifier
=================================
In addition to the new Block type we also introduce a new storage
qualifier, :block-term:`__block`, for local variables. [testme: a
__block declaration within a block literal] The ``__block`` storage
qualifier is mutually exclusive to the existing local storage
qualifiers auto, register, and static. [testme] Variables qualified by
``__block`` act as if they were in allocated storage and this storage
is automatically recovered after last use of said variable. An
implementation may choose an optimization where the storage is
initially automatic and only "moved" to allocated (heap) storage upon
a Block_copy of a referencing Block. Such variables may be mutated as
normal variables are.
In the case where a ``__block`` variable is a Block one must assume
that the ``__block`` variable resides in allocated storage and as such
is assumed to reference a Block that is also in allocated storage
(that it is the result of a ``Block_copy`` operation). Despite this
there is no provision to do a ``Block_copy`` or a ``Block_release`` if
an implementation provides initial automatic storage for Blocks. This
is due to the inherent race condition of potentially several threads
trying to update the shared variable and the need for synchronization
around disposing of older values and copying new ones. Such
synchronization is beyond the scope of this language specification.
Control Flow
============
The compound statement of a Block is treated much like a function body
with respect to control flow in that goto, break, and continue do not
escape the Block. Exceptions are treated *normally* in that when
thrown they pop stack frames until a catch clause is found.
Objective-C Extensions
======================
Objective-C extends the definition of a Block reference type to be
that also of id. A variable or expression of Block type may be
messaged or used as a parameter wherever an id may be. The converse is
also true. Block references may thus appear as properties and are
subject to the assign, retain, and copy attribute logic that is
reserved for objects.
All Blocks are constructed to be Objective-C objects regardless of
whether the Objective-C runtime is operational in the program or
not. Blocks using automatic (stack) memory are objects and may be
messaged, although they may not be assigned into ``__weak`` locations
if garbage collection is enabled.
Within a Block literal expression within a method definition
references to instance variables are also imported into the lexical
scope of the compound statement. These variables are implicitly
qualified as references from self, and so self is imported as a const
copy. The net effect is that instance variables can be mutated.
The :block-term:`Block_copy` operator retains all objects held in
variables of automatic storage referenced within the Block expression
(or form strong references if running under garbage collection).
Object variables of ``__block`` storage type are assumed to hold
normal pointers with no provision for retain and release messages.
Foundation defines (and supplies) ``-copy`` and ``-release`` methods for
Blocks.
In the Objective-C and Objective-C++ languages, we allow the
``__weak`` specifier for ``__block`` variables of object type. If
garbage collection is not enabled, this qualifier causes these
variables to be kept without retain messages being sent. This
knowingly leads to dangling pointers if the Block (or a copy) outlives
the lifetime of this object.
In garbage collected environments, the ``__weak`` variable is set to
nil when the object it references is collected, as long as the
``__block`` variable resides in the heap (either by default or via
``Block_copy()``). The initial Apple implementation does in fact
start ``__block`` variables on the stack and migrate them to the heap
only as a result of a ``Block_copy()`` operation.
It is a runtime error to attempt to assign a reference to a
stack-based Block into any storage marked ``__weak``, including
``__weak`` ``__block`` variables.
C++ Extensions
==============
Block literal expressions within functions are extended to allow const
use of C++ objects, pointers, or references held in automatic storage.
As usual, within the block, references to captured variables become
const-qualified, as if they were references to members of a const
object. Note that this does not change the type of a variable of
reference type.
For example, given a class Foo:
.. code-block:: c
Foo foo;
Foo &fooRef = foo;
Foo *fooPtr = &foo;
A Block that referenced these variables would import the variables as
const variations:
.. code-block:: c
const Foo block_foo = foo;
Foo &block_fooRef = fooRef;
Foo *const block_fooPtr = fooPtr;
Captured variables are copied into the Block at the instant of
evaluating the Block literal expression. They are also copied when
calling ``Block_copy()`` on a Block allocated on the stack. In both
cases, they are copied as if the variable were const-qualified, and
it's an error if there's no such constructor.
Captured variables in Blocks on the stack are destroyed when control
leaves the compound statement that contains the Block literal
expression. Captured variables in Blocks on the heap are destroyed
when the reference count of the Block drops to zero.
Variables declared as residing in ``__block`` storage may be initially
allocated in the heap or may first appear on the stack and be copied
to the heap as a result of a ``Block_copy()`` operation. When copied
from the stack, ``__block`` variables are copied using their normal
qualification (i.e. without adding const). In C++11, ``__block``
variables are copied as x-values if that is possible, then as l-values
if not; if both fail, it's an error. The destructor for any initial
stack-based version is called at the variable's normal end of scope.
References to ``this``, as well as references to non-static members of
any enclosing class, are evaluated by capturing ``this`` just like a
normal variable of C pointer type.
Member variables that are Blocks may not be overloaded by the types of
their arguments.

View File

@ -1,107 +0,0 @@
if (DOXYGEN_FOUND)
if (LLVM_ENABLE_DOXYGEN)
set(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR})
set(abs_builddir ${CMAKE_CURRENT_BINARY_DIR})
if (HAVE_DOT)
set(DOT ${LLVM_PATH_DOT})
endif()
if (LLVM_DOXYGEN_EXTERNAL_SEARCH)
set(enable_searchengine "YES")
set(searchengine_url "${LLVM_DOXYGEN_SEARCHENGINE_URL}")
set(enable_server_based_search "YES")
set(enable_external_search "YES")
set(extra_search_mappings "${LLVM_DOXYGEN_SEARCH_MAPPINGS}")
else()
set(enable_searchengine "NO")
set(searchengine_url "")
set(enable_server_based_search "NO")
set(enable_external_search "NO")
set(extra_search_mappings "")
endif()
# If asked, configure doxygen for the creation of a Qt Compressed Help file.
if (LLVM_ENABLE_DOXYGEN_QT_HELP)
set(CLANG_DOXYGEN_QCH_FILENAME "org.llvm.clang.qch" CACHE STRING
"Filename of the Qt Compressed help file")
set(CLANG_DOXYGEN_QHP_NAMESPACE "org.llvm.clang" CACHE STRING
"Namespace under which the intermediate Qt Help Project file lives")
set(CLANG_DOXYGEN_QHP_CUST_FILTER_NAME "Clang ${CLANG_VERSION}" CACHE STRING
"See http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-filters")
set(CLANG_DOXYGEN_QHP_CUST_FILTER_ATTRS "Clang,${CLANG_VERSION}" CACHE STRING
"See http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes")
set(clang_doxygen_generate_qhp "YES")
set(clang_doxygen_qch_filename "${CLANG_DOXYGEN_QCH_FILENAME}")
set(clang_doxygen_qhp_namespace "${CLANG_DOXYGEN_QHP_NAMESPACE}")
set(clang_doxygen_qhelpgenerator_path "${LLVM_DOXYGEN_QHELPGENERATOR_PATH}")
set(clang_doxygen_qhp_cust_filter_name "${CLANG_DOXYGEN_QHP_CUST_FILTER_NAME}")
set(clang_doxygen_qhp_cust_filter_attrs "${CLANG_DOXYGEN_QHP_CUST_FILTER_ATTRS}")
else()
set(clang_doxygen_generate_qhp "NO")
set(clang_doxygen_qch_filename "")
set(clang_doxygen_qhp_namespace "")
set(clang_doxygen_qhelpgenerator_path "")
set(clang_doxygen_qhp_cust_filter_name "")
set(clang_doxygen_qhp_cust_filter_attrs "")
endif()
option(LLVM_DOXYGEN_SVG
"Use svg instead of png files for doxygen graphs." OFF)
if (LLVM_DOXYGEN_SVG)
set(DOT_IMAGE_FORMAT "svg")
else()
set(DOT_IMAGE_FORMAT "png")
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY)
set(abs_top_srcdir)
set(abs_top_builddir)
set(DOT)
set(enable_searchengine)
set(searchengine_url)
set(enable_server_based_search)
set(enable_external_search)
set(extra_search_mappings)
set(clang_doxygen_generate_qhp)
set(clang_doxygen_qch_filename)
set(clang_doxygen_qhp_namespace)
set(clang_doxygen_qhelpgenerator_path)
set(clang_doxygen_qhp_cust_filter_name)
set(clang_doxygen_qhp_cust_filter_attrs)
set(DOT_IMAGE_FORMAT)
add_custom_target(doxygen-clang
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating clang doxygen documentation." VERBATIM)
if (LLVM_BUILD_DOCS)
add_dependencies(doxygen doxygen-clang)
endif()
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doxygen/html
DESTINATION docs/html)
endif()
endif()
endif()
if (LLVM_ENABLE_SPHINX)
include(AddSphinxTarget)
if (SPHINX_FOUND)
if (${SPHINX_OUTPUT_HTML})
add_sphinx_target(html clang)
add_custom_command(TARGET docs-clang-html POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/LibASTMatchersReference.html"
"${CMAKE_CURRENT_BINARY_DIR}/html/LibASTMatchersReference.html")
endif()
if (${SPHINX_OUTPUT_MAN})
add_sphinx_target(man clang)
endif()
endif()
endif()

View File

@ -1,36 +0,0 @@
==========
ClangCheck
==========
`ClangCheck` is a small wrapper around :doc:`LibTooling` which can be used to
do basic error checking and AST dumping.
.. code-block:: console
$ cat <<EOF > snippet.cc
> void f() {
> int a = 0
> }
> EOF
$ ~/clang/build/bin/clang-check snippet.cc -ast-dump --
Processing: /Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc.
/Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc:2:12: error: expected ';' at end of
declaration
int a = 0
^
;
(TranslationUnitDecl 0x7ff3a3029ed0 <<invalid sloc>>
(TypedefDecl 0x7ff3a302a410 <<invalid sloc>> __int128_t '__int128')
(TypedefDecl 0x7ff3a302a470 <<invalid sloc>> __uint128_t 'unsigned __int128')
(TypedefDecl 0x7ff3a302a830 <<invalid sloc>> __builtin_va_list '__va_list_tag [1]')
(FunctionDecl 0x7ff3a302a8d0 </Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc:1:1, line:3:1> f 'void (void)'
(CompoundStmt 0x7ff3a302aa10 <line:1:10, line:3:1>
(DeclStmt 0x7ff3a302a9f8 <line:2:3, line:3:1>
(VarDecl 0x7ff3a302a980 <line:2:3, col:11> a 'int'
(IntegerLiteral 0x7ff3a302a9d8 <col:11> 'int' 0))))))
1 error generated.
Error while processing snippet.cc.
The '--' at the end is important as it prevents :program:`clang-check` from
searching for a compilation database. For more information on how to setup and
use :program:`clang-check` in a project, see :doc:`HowToSetupToolingForLLVM`.

File diff suppressed because it is too large Load Diff

View File

@ -1,216 +0,0 @@
===========
ClangFormat
===========
`ClangFormat` describes a set of tools that are built on top of
:doc:`LibFormat`. It can support your workflow in a variety of ways including a
standalone tool and editor integrations.
Standalone Tool
===============
:program:`clang-format` is located in `clang/tools/clang-format` and can be used
to format C/C++/Java/JavaScript/Objective-C/Protobuf code.
.. code-block:: console
$ clang-format -help
OVERVIEW: A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf code.
If no arguments are specified, it formats the code from standard input
and writes the result to the standard output.
If <file>s are given, it reformats the files. If -i is specified
together with <file>s, the files are edited in-place. Otherwise, the
result is written to the standard output.
USAGE: clang-format [options] [<file> ...]
OPTIONS:
Clang-format options:
-assume-filename=<string> - When reading from stdin, clang-format assumes this
filename to look for a style config file (with
-style=file) and to determine the language.
-cursor=<uint> - The position of the cursor when invoking
clang-format from an editor integration
-dump-config - Dump configuration options to stdout and exit.
Can be used with -style option.
-fallback-style=<string> - The name of the predefined style used as a
fallback in case clang-format is invoked with
-style=file, but can not find the .clang-format
file to use.
Use -fallback-style=none to skip formatting.
-i - Inplace edit <file>s, if specified.
-length=<uint> - Format a range of this length (in bytes).
Multiple ranges can be formatted by specifying
several -offset and -length pairs.
When only a single -offset is specified without
-length, clang-format will format up to the end
of the file.
Can only be used with one input file.
-lines=<string> - <start line>:<end line> - format a range of
lines (both 1-based).
Multiple ranges can be formatted by specifying
several -lines arguments.
Can't be used with -offset and -length.
Can only be used with one input file.
-offset=<uint> - Format a range starting at this byte offset.
Multiple ranges can be formatted by specifying
several -offset and -length pairs.
Can only be used with one input file.
-output-replacements-xml - Output replacements as XML.
-sort-includes - Sort touched include lines
-style=<string> - Coding style, currently supports:
LLVM, Google, Chromium, Mozilla, WebKit.
Use -style=file to load style configuration from
.clang-format file located in one of the parent
directories of the source file (or current
directory for stdin).
Use -style="{key: value, ...}" to set specific
parameters, e.g.:
-style="{BasedOnStyle: llvm, IndentWidth: 8}"
-verbose - If set, shows the list of processed files
Generic Options:
-help - Display available options (-help-hidden for more)
-help-list - Display list of available options (-help-list-hidden for more)
-version - Display the version of this program
When the desired code formatting style is different from the available options,
the style can be customized using the ``-style="{key: value, ...}"`` option or
by putting your style configuration in the ``.clang-format`` or ``_clang-format``
file in your project's directory and using ``clang-format -style=file``.
An easy way to create the ``.clang-format`` file is:
.. code-block:: console
clang-format -style=llvm -dump-config > .clang-format
Available style options are described in :doc:`ClangFormatStyleOptions`.
Vim Integration
===============
There is an integration for :program:`vim` which lets you run the
:program:`clang-format` standalone tool on your current buffer, optionally
selecting regions to reformat. The integration has the form of a `python`-file
which can be found under `clang/tools/clang-format/clang-format.py`.
This can be integrated by adding the following to your `.vimrc`:
.. code-block:: vim
map <C-K> :pyf <path-to-this-file>/clang-format.py<cr>
imap <C-K> <c-o>:pyf <path-to-this-file>/clang-format.py<cr>
The first line enables :program:`clang-format` for NORMAL and VISUAL mode, the
second line adds support for INSERT mode. Change "C-K" to another binding if
you need :program:`clang-format` on a different key (C-K stands for Ctrl+k).
With this integration you can press the bound key and clang-format will
format the current line in NORMAL and INSERT mode or the selected region in
VISUAL mode. The line or region is extended to the next bigger syntactic
entity.
It operates on the current, potentially unsaved buffer and does not create
or save any files. To revert a formatting, just undo.
An alternative option is to format changes when saving a file and thus to
have a zero-effort integration into the coding workflow. To do this, add this to
your `.vimrc`:
.. code-block:: vim
function! Formatonsave()
let l:formatdiff = 1
pyf ~/llvm/tools/clang/tools/clang-format/clang-format.py
endfunction
autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave()
Emacs Integration
=================
Similar to the integration for :program:`vim`, there is an integration for
:program:`emacs`. It can be found at `clang/tools/clang-format/clang-format.el`
and used by adding this to your `.emacs`:
.. code-block:: common-lisp
(load "<path-to-clang>/tools/clang-format/clang-format.el")
(global-set-key [C-M-tab] 'clang-format-region)
This binds the function `clang-format-region` to C-M-tab, which then formats the
current line or selected region.
BBEdit Integration
==================
:program:`clang-format` cannot be used as a text filter with BBEdit, but works
well via a script. The AppleScript to do this integration can be found at
`clang/tools/clang-format/clang-format-bbedit.applescript`; place a copy in
`~/Library/Application Support/BBEdit/Scripts`, and edit the path within it to
point to your local copy of :program:`clang-format`.
With this integration you can select the script from the Script menu and
:program:`clang-format` will format the selection. Note that you can rename the
menu item by renaming the script, and can assign the menu item a keyboard
shortcut in the BBEdit preferences, under Menus & Shortcuts.
Visual Studio Integration
=========================
Download the latest Visual Studio extension from the `alpha build site
<https://llvm.org/builds/>`_. The default key-binding is Ctrl-R,Ctrl-F.
Script for patch reformatting
=============================
The python script `clang/tools/clang-format/clang-format-diff.py` parses the
output of a unified diff and reformats all contained lines with
:program:`clang-format`.
.. code-block:: console
usage: clang-format-diff.py [-h] [-i] [-p NUM] [-regex PATTERN] [-style STYLE]
Reformat changed lines in diff. Without -i option just output the diff that
would be introduced.
optional arguments:
-h, --help show this help message and exit
-i apply edits to files instead of displaying a diff
-p NUM strip the smallest prefix containing P slashes
-regex PATTERN custom pattern selecting file paths to reformat
-style STYLE formatting style to apply (LLVM, Google, Chromium, Mozilla,
WebKit)
So to reformat all the lines in the latest :program:`git` commit, just do:
.. code-block:: console
git diff -U0 --no-color HEAD^ | clang-format-diff.py -i -p1
With Mercurial/:program:`hg`:
.. code-block:: console
hg diff -U0 --color=never | clang-format-diff.py -i -p1
In an SVN client, you can do:
.. code-block:: console
svn diff --diff-cmd=diff -x -U0 | clang-format-diff.py -i
The option `-U0` will create a diff without context lines (the script would format
those as well).

File diff suppressed because it is too large Load Diff

View File

@ -1,130 +0,0 @@
=============
Clang Plugins
=============
Clang Plugins make it possible to run extra user defined actions during a
compilation. This document will provide a basic walkthrough of how to write and
run a Clang Plugin.
Introduction
============
Clang Plugins run FrontendActions over code. See the :doc:`FrontendAction
tutorial <RAVFrontendAction>` on how to write a ``FrontendAction`` using the
``RecursiveASTVisitor``. In this tutorial, we'll demonstrate how to write a
simple clang plugin.
Writing a ``PluginASTAction``
=============================
The main difference from writing normal ``FrontendActions`` is that you can
handle plugin command line options. The ``PluginASTAction`` base class declares
a ``ParseArgs`` method which you have to implement in your plugin.
.. code-block:: c++
bool ParseArgs(const CompilerInstance &CI,
const std::vector<std::string>& args) {
for (unsigned i = 0, e = args.size(); i != e; ++i) {
if (args[i] == "-some-arg") {
// Handle the command line argument.
}
}
return true;
}
Registering a plugin
====================
A plugin is loaded from a dynamic library at runtime by the compiler. To
register a plugin in a library, use ``FrontendPluginRegistry::Add<>``:
.. code-block:: c++
static FrontendPluginRegistry::Add<MyPlugin> X("my-plugin-name", "my plugin description");
Defining pragmas
================
Plugins can also define pragmas by declaring a ``PragmaHandler`` and
registering it using ``PragmaHandlerRegistry::Add<>``:
.. code-block:: c++
// Define a pragma handler for #pragma example_pragma
class ExamplePragmaHandler : public PragmaHandler {
public:
ExamplePragmaHandler() : PragmaHandler("example_pragma") { }
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &PragmaTok) {
// Handle the pragma
}
};
static PragmaHandlerRegistry::Add<ExamplePragmaHandler> Y("example_pragma","example pragma description");
Putting it all together
=======================
Let's look at an example plugin that prints top-level function names. This
example is checked into the clang repository; please take a look at
the `latest version of PrintFunctionNames.cpp
<https://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp?view=markup>`_.
Running the plugin
==================
Using the cc1 command line
--------------------------
To run a plugin, the dynamic library containing the plugin registry must be
loaded via the `-load` command line option. This will load all plugins
that are registered, and you can select the plugins to run by specifying the
`-plugin` option. Additional parameters for the plugins can be passed with
`-plugin-arg-<plugin-name>`.
Note that those options must reach clang's cc1 process. There are two
ways to do so:
* Directly call the parsing process by using the `-cc1` option; this
has the downside of not configuring the default header search paths, so
you'll need to specify the full system path configuration on the command
line.
* Use clang as usual, but prefix all arguments to the cc1 process with
`-Xclang`.
For example, to run the ``print-function-names`` plugin over a source file in
clang, first build the plugin, and then call clang with the plugin from the
source tree:
.. code-block:: console
$ export BD=/path/to/build/directory
$ (cd $BD && make PrintFunctionNames )
$ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
-D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
-I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
-Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
-plugin -Xclang print-fns
Also see the print-function-name plugin example's
`README <https://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/README.txt?view=markup>`_
Using the clang command line
----------------------------
Using `-fplugin=plugin` on the clang command line passes the plugin
through as an argument to `-load` on the cc1 command line. If the plugin
class implements the ``getActionType`` method then the plugin is run
automatically. For example, to run the plugin automatically after the main AST
action (i.e. the same as using `-add-plugin`):
.. code-block:: c++
// Automatically run the plugin after the main AST action
PluginASTAction::ActionType getActionType() override {
return AddAfterMainAction;
}

View File

@ -1,167 +0,0 @@
========
Overview
========
Clang Tools are standalone command line (and potentially GUI) tools
designed for use by C++ developers who are already using and enjoying
Clang as their compiler. These tools provide developer-oriented
functionality such as fast syntax checking, automatic formatting,
refactoring, etc.
Only a couple of the most basic and fundamental tools are kept in the
primary Clang Subversion project. The rest of the tools are kept in a
side-project so that developers who don't want or need to build them
don't. If you want to get access to the extra Clang Tools repository,
simply check it out into the tools tree of your Clang checkout and
follow the usual process for building and working with a combined
LLVM/Clang checkout:
- With Subversion:
- ``cd llvm/tools/clang/tools``
- ``svn co https://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra``
- Or with Git:
- ``cd llvm/tools/clang/tools``
- ``git clone https://llvm.org/git/clang-tools-extra.git extra``
This document describes a high-level overview of the organization of
Clang Tools within the project as well as giving an introduction to some
of the more important tools. However, it should be noted that this
document is currently focused on Clang and Clang Tool developers, not on
end users of these tools.
Clang Tools Organization
========================
Clang Tools are CLI or GUI programs that are intended to be directly
used by C++ developers. That is they are *not* primarily for use by
Clang developers, although they are hopefully useful to C++ developers
who happen to work on Clang, and we try to actively dogfood their
functionality. They are developed in three components: the underlying
infrastructure for building a standalone tool based on Clang, core
shared logic used by many different tools in the form of refactoring and
rewriting libraries, and the tools themselves.
The underlying infrastructure for Clang Tools is the
:doc:`LibTooling <LibTooling>` platform. See its documentation for much
more detailed information about how this infrastructure works. The
common refactoring and rewriting toolkit-style library is also part of
LibTooling organizationally.
A few Clang Tools are developed along side the core Clang libraries as
examples and test cases of fundamental functionality. However, most of
the tools are developed in a side repository to provide easy separation
from the core libraries. We intentionally do not support public
libraries in the side repository, as we want to carefully review and
find good APIs for libraries as they are lifted out of a few tools and
into the core Clang library set.
Regardless of which repository Clang Tools' code resides in, the
development process and practices for all Clang Tools are exactly those
of Clang itself. They are entirely within the Clang *project*,
regardless of the version control scheme.
Core Clang Tools
================
The core set of Clang tools that are within the main repository are
tools that very specifically complement, and allow use and testing of
*Clang* specific functionality.
``clang-check``
---------------
:doc:`ClangCheck` combines the LibTooling framework for running a
Clang tool with the basic Clang diagnostics by syntax checking specific files
in a fast, command line interface. It can also accept flags to re-display the
diagnostics in different formats with different flags, suitable for use driving
an IDE or editor. Furthermore, it can be used in fixit-mode to directly apply
fixit-hints offered by clang. See :doc:`HowToSetupToolingForLLVM` for
instructions on how to setup and used `clang-check`.
``clang-format``
----------------
Clang-format is both a :doc:`library <LibFormat>` and a :doc:`stand-alone tool
<ClangFormat>` with the goal of automatically reformatting C++ sources files
according to configurable style guides. To do so, clang-format uses Clang's
``Lexer`` to transform an input file into a token stream and then changes all
the whitespace around those tokens. The goal is for clang-format to serve both
as a user tool (ideally with powerful IDE integrations) and as part of other
refactoring tools, e.g. to do a reformatting of all the lines changed during a
renaming.
Extra Clang Tools
=================
As various categories of Clang Tools are added to the extra repository,
they'll be tracked here. The focus of this documentation is on the scope
and features of the tools for other tool developers; each tool should
provide its own user-focused documentation.
``clang-tidy``
--------------
`clang-tidy <https://clang.llvm.org/extra/clang-tidy/>`_ is a clang-based C++
linter tool. It provides an extensible framework for building compiler-based
static analyses detecting and fixing bug-prone patterns, performance,
portability and maintainability issues.
Ideas for new Tools
===================
* C++ cast conversion tool. Will convert C-style casts (``(type) value``) to
appropriate C++ cast (``static_cast``, ``const_cast`` or
``reinterpret_cast``).
* Non-member ``begin()`` and ``end()`` conversion tool. Will convert
``foo.begin()`` into ``begin(foo)`` and similarly for ``end()``, where
``foo`` is a standard container. We could also detect similar patterns for
arrays.
* ``tr1`` removal tool. Will migrate source code from using TR1 library
features to C++11 library. For example:
.. code-block:: c++
#include <tr1/unordered_map>
int main()
{
std::tr1::unordered_map <int, int> ma;
std::cout << ma.size () << std::endl;
return 0;
}
should be rewritten to:
.. code-block:: c++
#include <unordered_map>
int main()
{
std::unordered_map <int, int> ma;
std::cout << ma.size () << std::endl;
return 0;
}
* A tool to remove ``auto``. Will convert ``auto`` to an explicit type or add
comments with deduced types. The motivation is that there are developers
that don't want to use ``auto`` because they are afraid that they might lose
control over their code.
* C++14: less verbose operator function objects (`N3421
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421.htm>`_).
For example:
.. code-block:: c++
sort(v.begin(), v.end(), greater<ValueType>());
should be rewritten to:
.. code-block:: c++
sort(v.begin(), v.end(), greater<>());

View File

@ -1,635 +0,0 @@
clang - the Clang C, C++, and Objective-C compiler
==================================================
SYNOPSIS
--------
:program:`clang` [*options*] *filename ...*
DESCRIPTION
-----------
:program:`clang` is a C, C++, and Objective-C compiler which encompasses
preprocessing, parsing, optimization, code generation, assembly, and linking.
Depending on which high-level mode setting is passed, Clang will stop before
doing a full link. While Clang is highly integrated, it is important to
understand the stages of compilation, to understand how to invoke it. These
stages are:
Driver
The clang executable is actually a small driver which controls the overall
execution of other tools such as the compiler, assembler and linker.
Typically you do not need to interact with the driver, but you
transparently use it to run the other tools.
Preprocessing
This stage handles tokenization of the input source file, macro expansion,
#include expansion and handling of other preprocessor directives. The
output of this stage is typically called a ".i" (for C), ".ii" (for C++),
".mi" (for Objective-C), or ".mii" (for Objective-C++) file.
Parsing and Semantic Analysis
This stage parses the input file, translating preprocessor tokens into a
parse tree. Once in the form of a parse tree, it applies semantic
analysis to compute types for expressions as well and determine whether
the code is well formed. This stage is responsible for generating most of
the compiler warnings as well as parse errors. The output of this stage is
an "Abstract Syntax Tree" (AST).
Code Generation and Optimization
This stage translates an AST into low-level intermediate code (known as
"LLVM IR") and ultimately to machine code. This phase is responsible for
optimizing the generated code and handling target-specific code generation.
The output of this stage is typically called a ".s" file or "assembly" file.
Clang also supports the use of an integrated assembler, in which the code
generator produces object files directly. This avoids the overhead of
generating the ".s" file and of calling the target assembler.
Assembler
This stage runs the target assembler to translate the output of the
compiler into a target object file. The output of this stage is typically
called a ".o" file or "object" file.
Linker
This stage runs the target linker to merge multiple object files into an
executable or dynamic library. The output of this stage is typically called
an "a.out", ".dylib" or ".so" file.
:program:`Clang Static Analyzer`
The Clang Static Analyzer is a tool that scans source code to try to find bugs
through code analysis. This tool uses many parts of Clang and is built into
the same driver. Please see <https://clang-analyzer.llvm.org> for more details
on how to use the static analyzer.
OPTIONS
-------
Stage Selection Options
~~~~~~~~~~~~~~~~~~~~~~~
.. option:: -E
Run the preprocessor stage.
.. option:: -fsyntax-only
Run the preprocessor, parser and type checking stages.
.. option:: -S
Run the previous stages as well as LLVM generation and optimization stages
and target-specific code generation, producing an assembly file.
.. option:: -c
Run all of the above, plus the assembler, generating a target ".o" object file.
.. option:: no stage selection option
If no stage selection option is specified, all stages above are run, and the
linker is run to combine the results into an executable or shared library.
Language Selection and Mode Options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. option:: -x <language>
Treat subsequent input files as having type language.
.. option:: -std=<standard>
Specify the language standard to compile for.
Supported values for the C language are:
| ``c89``
| ``c90``
| ``iso9899:1990``
ISO C 1990
| ``iso9899:199409``
ISO C 1990 with amendment 1
| ``gnu89``
| ``gnu90``
ISO C 1990 with GNU extensions
| ``c99``
| ``iso9899:1999``
ISO C 1999
| ``gnu99``
ISO C 1999 with GNU extensions
| ``c11``
| ``iso9899:2011``
ISO C 2011
| ``gnu11``
ISO C 2011 with GNU extensions
| ``c17``
| ``iso9899:2017``
ISO C 2017
| ``gnu17``
ISO C 2017 with GNU extensions
The default C language standard is ``gnu11``, except on PS4, where it is
``gnu99``.
Supported values for the C++ language are:
| ``c++98``
| ``c++03``
ISO C++ 1998 with amendments
| ``gnu++98``
| ``gnu++03``
ISO C++ 1998 with amendments and GNU extensions
| ``c++11``
ISO C++ 2011 with amendments
| ``gnu++11``
ISO C++ 2011 with amendments and GNU extensions
| ``c++14``
ISO C++ 2014 with amendments
| ``gnu++14``
ISO C++ 2014 with amendments and GNU extensions
| ``c++17``
ISO C++ 2017 with amendments
| ``gnu++17``
ISO C++ 2017 with amendments and GNU extensions
| ``c++2a``
Working draft for ISO C++ 2020
| ``gnu++2a``
Working draft for ISO C++ 2020 with GNU extensions
The default C++ language standard is ``gnu++14``.
Supported values for the OpenCL language are:
| ``cl1.0``
OpenCL 1.0
| ``cl1.1``
OpenCL 1.1
| ``cl1.2``
OpenCL 1.2
| ``cl2.0``
OpenCL 2.0
The default OpenCL language standard is ``cl1.0``.
Supported values for the CUDA language are:
| ``cuda``
NVIDIA CUDA(tm)
.. option:: -stdlib=<library>
Specify the C++ standard library to use; supported options are libstdc++ and
libc++. If not specified, platform default will be used.
.. option:: -rtlib=<library>
Specify the compiler runtime library to use; supported options are libgcc and
compiler-rt. If not specified, platform default will be used.
.. option:: -ansi
Same as -std=c89.
.. option:: -ObjC, -ObjC++
Treat source input files as Objective-C and Object-C++ inputs respectively.
.. option:: -trigraphs
Enable trigraphs.
.. option:: -ffreestanding
Indicate that the file should be compiled for a freestanding, not a hosted,
environment.
.. option:: -fno-builtin
Disable special handling and optimizations of builtin functions like
:c:func:`strlen` and :c:func:`malloc`.
.. option:: -fmath-errno
Indicate that math functions should be treated as updating :c:data:`errno`.
.. option:: -fpascal-strings
Enable support for Pascal-style strings with "\\pfoo".
.. option:: -fms-extensions
Enable support for Microsoft extensions.
.. option:: -fmsc-version=
Set _MSC_VER. Defaults to 1300 on Windows. Not set otherwise.
.. option:: -fborland-extensions
Enable support for Borland extensions.
.. option:: -fwritable-strings
Make all string literals default to writable. This disables uniquing of
strings and other optimizations.
.. option:: -flax-vector-conversions
Allow loose type checking rules for implicit vector conversions.
.. option:: -fblocks
Enable the "Blocks" language feature.
.. option:: -fobjc-abi-version=version
Select the Objective-C ABI version to use. Available versions are 1 (legacy
"fragile" ABI), 2 (non-fragile ABI 1), and 3 (non-fragile ABI 2).
.. option:: -fobjc-nonfragile-abi-version=<version>
Select the Objective-C non-fragile ABI version to use by default. This will
only be used as the Objective-C ABI when the non-fragile ABI is enabled
(either via :option:`-fobjc-nonfragile-abi`, or because it is the platform
default).
.. option:: -fobjc-nonfragile-abi, -fno-objc-nonfragile-abi
Enable use of the Objective-C non-fragile ABI. On platforms for which this is
the default ABI, it can be disabled with :option:`-fno-objc-nonfragile-abi`.
Target Selection Options
~~~~~~~~~~~~~~~~~~~~~~~~
Clang fully supports cross compilation as an inherent part of its design.
Depending on how your version of Clang is configured, it may have support for a
number of cross compilers, or may only support a native target.
.. option:: -arch <architecture>
Specify the architecture to build for.
.. option:: -mmacosx-version-min=<version>
When building for Mac OS X, specify the minimum version supported by your
application.
.. option:: -miphoneos-version-min
When building for iPhone OS, specify the minimum version supported by your
application.
.. option:: -march=<cpu>
Specify that Clang should generate code for a specific processor family
member and later. For example, if you specify -march=i486, the compiler is
allowed to generate instructions that are valid on i486 and later processors,
but which may not exist on earlier ones.
Code Generation Options
~~~~~~~~~~~~~~~~~~~~~~~
.. option:: -O0, -O1, -O2, -O3, -Ofast, -Os, -Oz, -Og, -O, -O4
Specify which optimization level to use:
:option:`-O0` Means "no optimization": this level compiles the fastest and
generates the most debuggable code.
:option:`-O1` Somewhere between :option:`-O0` and :option:`-O2`.
:option:`-O2` Moderate level of optimization which enables most
optimizations.
:option:`-O3` Like :option:`-O2`, except that it enables optimizations that
take longer to perform or that may generate larger code (in an attempt to
make the program run faster).
:option:`-Ofast` Enables all the optimizations from :option:`-O3` along
with other aggressive optimizations that may violate strict compliance with
language standards.
:option:`-Os` Like :option:`-O2` with extra optimizations to reduce code
size.
:option:`-Oz` Like :option:`-Os` (and thus :option:`-O2`), but reduces code
size further.
:option:`-Og` Like :option:`-O1`. In future versions, this option might
disable different optimizations in order to improve debuggability.
:option:`-O` Equivalent to :option:`-O2`.
:option:`-O4` and higher
Currently equivalent to :option:`-O3`
.. option:: -g, -gline-tables-only, -gmodules
Control debug information output. Note that Clang debug information works
best at :option:`-O0`. When more than one option starting with `-g` is
specified, the last one wins:
:option:`-g` Generate debug information.
:option:`-gline-tables-only` Generate only line table debug information. This
allows for symbolicated backtraces with inlining information, but does not
include any information about variables, their locations or types.
:option:`-gmodules` Generate debug information that contains external
references to types defined in Clang modules or precompiled headers instead
of emitting redundant debug type information into every object file. This
option transparently switches the Clang module format to object file
containers that hold the Clang module together with the debug information.
When compiling a program that uses Clang modules or precompiled headers,
this option produces complete debug information with faster compile
times and much smaller object files.
This option should not be used when building static libraries for
distribution to other machines because the debug info will contain
references to the module cache on the machine the object files in the
library were built on.
.. option:: -fstandalone-debug -fno-standalone-debug
Clang supports a number of optimizations to reduce the size of debug
information in the binary. They work based on the assumption that the
debug type information can be spread out over multiple compilation units.
For instance, Clang will not emit type definitions for types that are not
needed by a module and could be replaced with a forward declaration.
Further, Clang will only emit type info for a dynamic C++ class in the
module that contains the vtable for the class.
The :option:`-fstandalone-debug` option turns off these optimizations.
This is useful when working with 3rd-party libraries that don't come with
debug information. This is the default on Darwin. Note that Clang will
never emit type information for types that are not referenced at all by the
program.
.. option:: -fexceptions
Enable generation of unwind information. This allows exceptions to be thrown
through Clang compiled stack frames. This is on by default in x86-64.
.. option:: -ftrapv
Generate code to catch integer overflow errors. Signed integer overflow is
undefined in C. With this flag, extra code is generated to detect this and
abort when it happens.
.. option:: -fvisibility
This flag sets the default visibility level.
.. option:: -fcommon, -fno-common
This flag specifies that variables without initializers get common linkage.
It can be disabled with :option:`-fno-common`.
.. option:: -ftls-model=<model>
Set the default thread-local storage (TLS) model to use for thread-local
variables. Valid values are: "global-dynamic", "local-dynamic",
"initial-exec" and "local-exec". The default is "global-dynamic". The default
model can be overridden with the tls_model attribute. The compiler will try
to choose a more efficient model if possible.
.. option:: -flto, -flto=full, -flto=thin, -emit-llvm
Generate output files in LLVM formats, suitable for link time optimization.
When used with :option:`-S` this generates LLVM intermediate language
assembly files, otherwise this generates LLVM bitcode format object files
(which may be passed to the linker depending on the stage selection options).
The default for :option:`-flto` is "full", in which the
LLVM bitcode is suitable for monolithic Link Time Optimization (LTO), where
the linker merges all such modules into a single combined module for
optimization. With "thin", :doc:`ThinLTO <../ThinLTO>`
compilation is invoked instead.
Driver Options
~~~~~~~~~~~~~~
.. option:: -###
Print (but do not run) the commands to run for this compilation.
.. option:: --help
Display available options.
.. option:: -Qunused-arguments
Do not emit any warnings for unused driver arguments.
.. option:: -Wa,<args>
Pass the comma separated arguments in args to the assembler.
.. option:: -Wl,<args>
Pass the comma separated arguments in args to the linker.
.. option:: -Wp,<args>
Pass the comma separated arguments in args to the preprocessor.
.. option:: -Xanalyzer <arg>
Pass arg to the static analyzer.
.. option:: -Xassembler <arg>
Pass arg to the assembler.
.. option:: -Xlinker <arg>
Pass arg to the linker.
.. option:: -Xpreprocessor <arg>
Pass arg to the preprocessor.
.. option:: -o <file>
Write output to file.
.. option:: -print-file-name=<file>
Print the full library path of file.
.. option:: -print-libgcc-file-name
Print the library path for the currently used compiler runtime library
("libgcc.a" or "libclang_rt.builtins.*.a").
.. option:: -print-prog-name=<name>
Print the full program path of name.
.. option:: -print-search-dirs
Print the paths used for finding libraries and programs.
.. option:: -save-temps
Save intermediate compilation results.
.. option:: -save-stats, -save-stats=cwd, -save-stats=obj
Save internal code generation (LLVM) statistics to a file in the current
directory (:option:`-save-stats`/"-save-stats=cwd") or the directory
of the output file ("-save-state=obj").
.. option:: -integrated-as, -no-integrated-as
Used to enable and disable, respectively, the use of the integrated
assembler. Whether the integrated assembler is on by default is target
dependent.
.. option:: -time
Time individual commands.
.. option:: -ftime-report
Print timing summary of each stage of compilation.
.. option:: -v
Show commands to run and use verbose output.
Diagnostics Options
~~~~~~~~~~~~~~~~~~~
.. option:: -fshow-column, -fshow-source-location, -fcaret-diagnostics, -fdiagnostics-fixit-info, -fdiagnostics-parseable-fixits, -fdiagnostics-print-source-range-info, -fprint-source-range-info, -fdiagnostics-show-option, -fmessage-length
These options control how Clang prints out information about diagnostics
(errors and warnings). Please see the Clang User's Manual for more information.
Preprocessor Options
~~~~~~~~~~~~~~~~~~~~
.. option:: -D<macroname>=<value>
Adds an implicit #define into the predefines buffer which is read before the
source file is preprocessed.
.. option:: -U<macroname>
Adds an implicit #undef into the predefines buffer which is read before the
source file is preprocessed.
.. option:: -include <filename>
Adds an implicit #include into the predefines buffer which is read before the
source file is preprocessed.
.. option:: -I<directory>
Add the specified directory to the search path for include files.
.. option:: -F<directory>
Add the specified directory to the search path for framework include files.
.. option:: -nostdinc
Do not search the standard system directories or compiler builtin directories
for include files.
.. option:: -nostdlibinc
Do not search the standard system directories for include files, but do
search compiler builtin include directories.
.. option:: -nobuiltininc
Do not search clang's builtin directory for include files.
ENVIRONMENT
-----------
.. envvar:: TMPDIR, TEMP, TMP
These environment variables are checked, in order, for the location to write
temporary files used during the compilation process.
.. envvar:: CPATH
If this environment variable is present, it is treated as a delimited list of
paths to be added to the default system include path list. The delimiter is
the platform dependent delimiter, as used in the PATH environment variable.
Empty components in the environment variable are ignored.
.. envvar:: C_INCLUDE_PATH, OBJC_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJCPLUS_INCLUDE_PATH
These environment variables specify additional paths, as for :envvar:`CPATH`, which are
only used when processing the appropriate language.
.. envvar:: MACOSX_DEPLOYMENT_TARGET
If :option:`-mmacosx-version-min` is unspecified, the default deployment
target is read from this environment variable. This option only affects
Darwin targets.
BUGS
----
To report bugs, please visit <https://bugs.llvm.org/>. Most bug reports should
include preprocessed source files (use the :option:`-E` option) and the full
output of the compiler, along with information to reproduce.
SEE ALSO
--------
:manpage:`as(1)`, :manpage:`ld(1)`

View File

@ -1,52 +0,0 @@
diagtool - clang diagnostics tool
=================================
SYNOPSIS
--------
:program:`diagtool` *command* [*args*]
DESCRIPTION
-----------
:program:`diagtool` is a combination of four tool for dealing with diagnostics in :program:`clang`.
SUBCOMMANDS
-----------
:program:`diagtool` is separated into several subcommands each tailored to a
different purpose. A brief summary of each command follows, with more detail in
the sections that follow.
* :ref:`find_diagnostic_id` - Print the id of the given diagnostic.
* :ref:`list_warnings` - List warnings and their corresponding flags.
* :ref:`show_enabled` - Show which warnings are enabled for a given command line.
* :ref:`tree` - Show warning flags in a tree view.
.. _find_diagnostic_id:
find-diagnostic-id
~~~~~~~~~~~~~~~~~~
:program:`diagtool` find-diagnostic-id *diagnostic-name*
.. _list_warnings:
list-warnings
~~~~~~~~~~~~~
:program:`diagtool` list-warnings
.. _show_enabled:
show-enabled
~~~~~~~~~~~~
:program:`diagtool` show-enabled [*options*] *filename ...*
.. _tree:
tree
~~~~
:program:`diagtool` tree [*diagnostic-group*]

View File

@ -1,18 +0,0 @@
Clang "man" pages
-----------------
The following documents are command descriptions for all of the Clang tools.
These pages describe how to use the Clang commands and what their options are.
Note that these pages do not describe all of the options available for all
tools. To get a complete listing, pass the ``--help`` (general options) or
``--help-hidden`` (general and debugging options) arguments to the tool you are
interested in.
Basic Commands
~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 1
clang
diagtool

View File

@ -1,343 +0,0 @@
======================
Control Flow Integrity
======================
.. toctree::
:hidden:
ControlFlowIntegrityDesign
.. contents::
:local:
Introduction
============
Clang includes an implementation of a number of control flow integrity (CFI)
schemes, which are designed to abort the program upon detecting certain forms
of undefined behavior that can potentially allow attackers to subvert the
program's control flow. These schemes have been optimized for performance,
allowing developers to enable them in release builds.
To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``.
You can also enable a subset of available :ref:`schemes <cfi-schemes>`.
As currently implemented, all schemes rely on link-time optimization (LTO);
so it is required to specify ``-flto``, and the linker used must support LTO,
for example via the `gold plugin`_.
To allow the checks to be implemented efficiently, the program must
be structured such that certain object files are compiled with CFI
enabled, and are statically linked into the program. This may preclude
the use of shared libraries in some cases.
The compiler will only produce CFI checks for a class if it can infer hidden
LTO visibility for that class. LTO visibility is a property of a class that
is inferred from flags and attributes. For more details, see the documentation
for :doc:`LTO visibility <LTOVisibility>`.
The ``-fsanitize=cfi-{vcall,nvcall,derived-cast,unrelated-cast}`` flags
require that a ``-fvisibility=`` flag also be specified. This is because the
default visibility setting is ``-fvisibility=default``, which would disable
CFI checks for classes without visibility attributes. Most users will want
to specify ``-fvisibility=hidden``, which enables CFI checks for such classes.
Experimental support for :ref:`cross-DSO control flow integrity
<cfi-cross-dso>` exists that does not require classes to have hidden LTO
visibility. This cross-DSO support has unstable ABI at this time.
.. _gold plugin: https://llvm.org/docs/GoldPlugin.html
.. _cfi-schemes:
Available schemes
=================
Available schemes are:
- ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
<cfi-strictness>`.
- ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
dynamic type.
- ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
unrelated type to the wrong dynamic type.
- ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
the wrong dynamic type.
- ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
wrong dynamic type.
- ``-fsanitize=cfi-icall``: Indirect call of a function with wrong dynamic
type.
- ``-fsanitize=cfi-mfcall``: Indirect call via a member function pointer with
wrong dynamic type.
You can use ``-fsanitize=cfi`` to enable all the schemes and use
``-fno-sanitize`` flag to narrow down the set of schemes as desired.
For example, you can build your program with
``-fsanitize=cfi -fno-sanitize=cfi-nvcall,cfi-icall``
to use all schemes except for non-virtual member function call and indirect call
checking.
Remember that you have to provide ``-flto`` if at least one CFI scheme is
enabled.
Trapping and Diagnostics
========================
By default, CFI will abort the program immediately upon detecting a control
flow integrity violation. You can use the :ref:`-fno-sanitize-trap=
<controlling-code-generation>` flag to cause CFI to print a diagnostic
similar to the one below before the program aborts.
.. code-block:: console
bad-cast.cpp:109:7: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast (vtable address 0x000000425a50)
0x000000425a50: note: vtable is of type 'A'
00 00 00 00 f0 f1 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 5a 42 00
^
If diagnostics are enabled, you can also configure CFI to continue program
execution instead of aborting by using the :ref:`-fsanitize-recover=
<controlling-code-generation>` flag.
Forward-Edge CFI for Virtual Calls
==================================
This scheme checks that virtual calls take place using a vptr of the correct
dynamic type; that is, the dynamic type of the called object must be a
derived class of the static type of the object used to make the call.
This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vcall``.
For this scheme to work, all translation units containing the definition
of a virtual member function (whether inline or not), other than members
of :ref:`blacklisted <cfi-blacklist>` types or types with public :doc:`LTO
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
enabled and be statically linked into the program.
Performance
-----------
A performance overhead of less than 1% has been measured by running the
Dromaeo benchmark suite against an instrumented version of the Chromium
web browser. Another good performance benchmark for this mechanism is the
virtual-call-heavy SPEC 2006 xalancbmk.
Note that this scheme has not yet been optimized for binary size; an increase
of up to 15% has been observed for Chromium.
Bad Cast Checking
=================
This scheme checks that pointer casts are made to an object of the correct
dynamic type; that is, the dynamic type of the object must be a derived class
of the pointee type of the cast. The checks are currently only introduced
where the class being casted to is a polymorphic class.
Bad casts are not in themselves control flow integrity violations, but they
can also create security vulnerabilities, and the implementation uses many
of the same mechanisms.
There are two types of bad cast that may be forbidden: bad casts
from a base class to a derived class (which can be checked with
``-fsanitize=cfi-derived-cast``), and bad casts from a pointer of
type ``void*`` or another unrelated type (which can be checked with
``-fsanitize=cfi-unrelated-cast``).
The difference between these two types of casts is that the first is defined
by the C++ standard to produce an undefined value, while the second is not
in itself undefined behavior (it is well defined to cast the pointer back
to its original type) unless the object is uninitialized and the cast is a
``static_cast`` (see C++14 [basic.life]p5).
If a program as a matter of policy forbids the second type of cast, that
restriction can normally be enforced. However it may in some cases be necessary
for a function to perform a forbidden cast to conform with an external API
(e.g. the ``allocate`` member function of a standard library allocator). Such
functions may be :ref:`blacklisted <cfi-blacklist>`.
For this scheme to work, all translation units containing the definition
of a virtual member function (whether inline or not), other than members
of :ref:`blacklisted <cfi-blacklist>` types or types with public :doc:`LTO
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
enabled and be statically linked into the program.
Non-Virtual Member Function Call Checking
=========================================
This scheme checks that non-virtual calls take place using an object of
the correct dynamic type; that is, the dynamic type of the called object
must be a derived class of the static type of the object used to make the
call. The checks are currently only introduced where the object is of a
polymorphic class type. This CFI scheme can be enabled on its own using
``-fsanitize=cfi-nvcall``.
For this scheme to work, all translation units containing the definition
of a virtual member function (whether inline or not), other than members
of :ref:`blacklisted <cfi-blacklist>` types or types with public :doc:`LTO
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
enabled and be statically linked into the program.
.. _cfi-strictness:
Strictness
----------
If a class has a single non-virtual base and does not introduce or override
virtual member functions or fields other than an implicitly defined virtual
destructor, it will have the same layout and virtual function semantics as
its base. By default, casts to such classes are checked as if they were made
to the least derived such class.
Casting an instance of a base class to such a derived class is technically
undefined behavior, but it is a relatively common hack for introducing
member functions on class instances with specific properties that works under
most compilers and should not have security implications, so we allow it by
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
Indirect Function Call Checking
===============================
This scheme checks that function calls take place using a function of the
correct dynamic type; that is, the dynamic type of the function must match
the static type used at the call. This CFI scheme can be enabled on its own
using ``-fsanitize=cfi-icall``.
For this scheme to work, each indirect function call in the program, other
than calls in :ref:`blacklisted <cfi-blacklist>` functions, must call a
function which was either compiled with ``-fsanitize=cfi-icall`` enabled,
or whose address was taken by a function in a translation unit compiled with
``-fsanitize=cfi-icall``.
If a function in a translation unit compiled with ``-fsanitize=cfi-icall``
takes the address of a function not compiled with ``-fsanitize=cfi-icall``,
that address may differ from the address taken by a function in a translation
unit not compiled with ``-fsanitize=cfi-icall``. This is technically a
violation of the C and C++ standards, but it should not affect most programs.
Each translation unit compiled with ``-fsanitize=cfi-icall`` must be
statically linked into the program or shared library, and calls across
shared library boundaries are handled as if the callee was not compiled with
``-fsanitize=cfi-icall``.
This scheme is currently only supported on the x86 and x86_64 architectures.
``-fsanitize-cfi-icall-generalize-pointers``
--------------------------------------------
Mismatched pointer types are a common cause of cfi-icall check failures.
Translation units compiled with the ``-fsanitize-cfi-icall-generalize-pointers``
flag relax pointer type checking for call sites in that translation unit,
applied across all functions compiled with ``-fsanitize=cfi-icall``.
Specifically, pointers in return and argument types are treated as equivalent as
long as the qualifiers for the type they point to match. For example, ``char*``,
``char**``, and ``int*`` are considered equivalent types. However, ``char*`` and
``const char*`` are considered separate types.
``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
``-fsanitize-cfi-cross-dso``.
``-fsanitize=cfi-icall`` and ``-fsanitize=function``
----------------------------------------------------
This tool is similar to ``-fsanitize=function`` in that both tools check
the types of function calls. However, the two tools occupy different points
on the design space; ``-fsanitize=function`` is a developer tool designed
to find bugs in local development builds, whereas ``-fsanitize=cfi-icall``
is a security hardening mechanism designed to be deployed in release builds.
``-fsanitize=function`` has a higher space and time overhead due to a more
complex type check at indirect call sites, as well as a need for run-time
type information (RTTI), which may make it unsuitable for deployment. Because
of the need for RTTI, ``-fsanitize=function`` can only be used with C++
programs, whereas ``-fsanitize=cfi-icall`` can protect both C and C++ programs.
On the other hand, ``-fsanitize=function`` conforms more closely with the C++
standard and user expectations around interaction with shared libraries;
the identity of function pointers is maintained, and calls across shared
library boundaries are no different from calls within a single program or
shared library.
Member Function Pointer Call Checking
=====================================
This scheme checks that indirect calls via a member function pointer
take place using an object of the correct dynamic type. Specifically, we
check that the dynamic type of the member function referenced by the member
function pointer matches the "function pointer" part of the member function
pointer, and that the member function's class type is related to the base
type of the member function. This CFI scheme can be enabled on its own using
``-fsanitize=cfi-mfcall``.
The compiler will only emit a full CFI check if the member function pointer's
base type is complete. This is because the complete definition of the base
type contains information that is necessary to correctly compile the CFI
check. To ensure that the compiler always emits a full CFI check, it is
recommended to also pass the flag ``-fcomplete-member-pointers``, which
enables a non-conforming language extension that requires member pointer
base types to be complete if they may be used for a call.
For this scheme to work, all translation units containing the definition
of a virtual member function (whether inline or not), other than members
of :ref:`blacklisted <cfi-blacklist>` types or types with public :doc:`LTO
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
enabled and be statically linked into the program.
This scheme is currently not compatible with cross-DSO CFI or the
Microsoft ABI.
.. _cfi-blacklist:
Blacklist
=========
A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
source files, functions and types using the ``src``, ``fun`` and ``type``
entity types. Specific CFI modes can be be specified using ``[section]``
headers.
.. code-block:: bash
# Suppress all CFI checking for code in a file.
src:bad_file.cpp
src:bad_header.h
# Ignore all functions with names containing MyFooBar.
fun:*MyFooBar*
# Ignore all types in the standard library.
type:std::*
# Disable only unrelated cast checks for this function
[cfi-unrelated-cast]
fun:*UnrelatedCast*
# Disable CFI call checks for this function without affecting cast checks
[cfi-vcall|cfi-nvcall|cfi-icall]
fun:*BadCall*
.. _cfi-cross-dso:
Shared library support
======================
Use **-f[no-]sanitize-cfi-cross-dso** to enable the cross-DSO control
flow integrity mode, which allows all CFI schemes listed above to
apply across DSO boundaries. As in the regular CFI, each DSO must be
built with ``-flto``.
Normally, CFI checks will only be performed for classes that have hidden LTO
visibility. With this flag enabled, the compiler will emit cross-DSO CFI
checks for all classes, except for those which appear in the CFI blacklist
or which use a ``no_sanitize`` attribute.
Design
======
Please refer to the :doc:`design document<ControlFlowIntegrityDesign>`.
Publications
============
`Control-Flow Integrity: Principles, Implementations, and Applications <http://research.microsoft.com/pubs/64250/ccs05.pdf>`_.
Martin Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti.
`Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM <http://www.pcc.me.uk/~peter/acad/usenix14.pdf>`_.
Caroline Tice, Tom Roeder, Peter Collingbourne, Stephen Checkoway,
Úlfar Erlingsson, Luis Lozano, Geoff Pike.

View File

@ -1,803 +0,0 @@
===========================================
Control Flow Integrity Design Documentation
===========================================
This page documents the design of the :doc:`ControlFlowIntegrity` schemes
supported by Clang.
Forward-Edge CFI for Virtual Calls
==================================
This scheme works by allocating, for each static type used to make a virtual
call, a region of read-only storage in the object file holding a bit vector
that maps onto to the region of storage used for those virtual tables. Each
set bit in the bit vector corresponds to the `address point`_ for a virtual
table compatible with the static type for which the bit vector is being built.
For example, consider the following three C++ classes:
.. code-block:: c++
struct A {
virtual void f1();
virtual void f2();
virtual void f3();
};
struct B : A {
virtual void f1();
virtual void f2();
virtual void f3();
};
struct C : A {
virtual void f1();
virtual void f2();
virtual void f3();
};
The scheme will cause the virtual tables for A, B and C to be laid out
consecutively:
.. csv-table:: Virtual Table Layout for A, B, C
:header: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
A::offset-to-top, &A::rtti, &A::f1, &A::f2, &A::f3, B::offset-to-top, &B::rtti, &B::f1, &B::f2, &B::f3, C::offset-to-top, &C::rtti, &C::f1, &C::f2, &C::f3
The bit vector for static types A, B and C will look like this:
.. csv-table:: Bit Vectors for A, B, C
:header: Class, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
A, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0
B, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
Bit vectors are represented in the object file as byte arrays. By loading
from indexed offsets into the byte array and applying a mask, a program can
test bits from the bit set with a relatively short instruction sequence. Bit
vectors may overlap so long as they use different bits. For the full details,
see the `ByteArrayBuilder`_ class.
In this case, assuming A is laid out at offset 0 in bit 0, B at offset 0 in
bit 1 and C at offset 0 in bit 2, the byte array would look like this:
.. code-block:: c++
char bits[] = { 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 5, 0, 0 };
To emit a virtual call, the compiler will assemble code that checks that
the object's virtual table pointer is in-bounds and aligned and that the
relevant bit is set in the bit vector.
For example on x86 a typical virtual call may look like this:
.. code-block:: none
ca7fbb: 48 8b 0f mov (%rdi),%rcx
ca7fbe: 48 8d 15 c3 42 fb 07 lea 0x7fb42c3(%rip),%rdx
ca7fc5: 48 89 c8 mov %rcx,%rax
ca7fc8: 48 29 d0 sub %rdx,%rax
ca7fcb: 48 c1 c0 3d rol $0x3d,%rax
ca7fcf: 48 3d 7f 01 00 00 cmp $0x17f,%rax
ca7fd5: 0f 87 36 05 00 00 ja ca8511
ca7fdb: 48 8d 15 c0 0b f7 06 lea 0x6f70bc0(%rip),%rdx
ca7fe2: f6 04 10 10 testb $0x10,(%rax,%rdx,1)
ca7fe6: 0f 84 25 05 00 00 je ca8511
ca7fec: ff 91 98 00 00 00 callq *0x98(%rcx)
[...]
ca8511: 0f 0b ud2
The compiler relies on co-operation from the linker in order to assemble
the bit vectors for the whole program. It currently does this using LLVM's
`type metadata`_ mechanism together with link-time optimization.
.. _address point: http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-general
.. _type metadata: https://llvm.org/docs/TypeMetadata.html
.. _ByteArrayBuilder: https://llvm.org/docs/doxygen/html/structllvm_1_1ByteArrayBuilder.html
Optimizations
-------------
The scheme as described above is the fully general variant of the scheme.
Most of the time we are able to apply one or more of the following
optimizations to improve binary size or performance.
In fact, if you try the above example with the current version of the
compiler, you will probably find that it will not use the described virtual
table layout or machine instructions. Some of the optimizations we are about
to introduce cause the compiler to use a different layout or a different
sequence of machine instructions.
Stripping Leading/Trailing Zeros in Bit Vectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If a bit vector contains leading or trailing zeros, we can strip them from
the vector. The compiler will emit code to check if the pointer is in range
of the region covered by ones, and perform the bit vector check using a
truncated version of the bit vector. For example, the bit vectors for our
example class hierarchy will be emitted like this:
.. csv-table:: Bit Vectors for A, B, C
:header: Class, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
A, , , 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ,
B, , , , , , , , 1, , , , , , ,
C, , , , , , , , , , , , , 1, ,
Short Inline Bit Vectors
~~~~~~~~~~~~~~~~~~~~~~~~
If the vector is sufficiently short, we can represent it as an inline constant
on x86. This saves us a few instructions when reading the correct element
of the bit vector.
If the bit vector fits in 32 bits, the code looks like this:
.. code-block:: none
dc2: 48 8b 03 mov (%rbx),%rax
dc5: 48 8d 15 14 1e 00 00 lea 0x1e14(%rip),%rdx
dcc: 48 89 c1 mov %rax,%rcx
dcf: 48 29 d1 sub %rdx,%rcx
dd2: 48 c1 c1 3d rol $0x3d,%rcx
dd6: 48 83 f9 03 cmp $0x3,%rcx
dda: 77 2f ja e0b <main+0x9b>
ddc: ba 09 00 00 00 mov $0x9,%edx
de1: 0f a3 ca bt %ecx,%edx
de4: 73 25 jae e0b <main+0x9b>
de6: 48 89 df mov %rbx,%rdi
de9: ff 10 callq *(%rax)
[...]
e0b: 0f 0b ud2
Or if the bit vector fits in 64 bits:
.. code-block:: none
11a6: 48 8b 03 mov (%rbx),%rax
11a9: 48 8d 15 d0 28 00 00 lea 0x28d0(%rip),%rdx
11b0: 48 89 c1 mov %rax,%rcx
11b3: 48 29 d1 sub %rdx,%rcx
11b6: 48 c1 c1 3d rol $0x3d,%rcx
11ba: 48 83 f9 2a cmp $0x2a,%rcx
11be: 77 35 ja 11f5 <main+0xb5>
11c0: 48 ba 09 00 00 00 00 movabs $0x40000000009,%rdx
11c7: 04 00 00
11ca: 48 0f a3 ca bt %rcx,%rdx
11ce: 73 25 jae 11f5 <main+0xb5>
11d0: 48 89 df mov %rbx,%rdi
11d3: ff 10 callq *(%rax)
[...]
11f5: 0f 0b ud2
If the bit vector consists of a single bit, there is only one possible
virtual table, and the check can consist of a single equality comparison:
.. code-block:: none
9a2: 48 8b 03 mov (%rbx),%rax
9a5: 48 8d 0d a4 13 00 00 lea 0x13a4(%rip),%rcx
9ac: 48 39 c8 cmp %rcx,%rax
9af: 75 25 jne 9d6 <main+0x86>
9b1: 48 89 df mov %rbx,%rdi
9b4: ff 10 callq *(%rax)
[...]
9d6: 0f 0b ud2
Virtual Table Layout
~~~~~~~~~~~~~~~~~~~~
The compiler lays out classes of disjoint hierarchies in separate regions
of the object file. At worst, bit vectors in disjoint hierarchies only
need to cover their disjoint hierarchy. But the closer that classes in
sub-hierarchies are laid out to each other, the smaller the bit vectors for
those sub-hierarchies need to be (see "Stripping Leading/Trailing Zeros in Bit
Vectors" above). The `GlobalLayoutBuilder`_ class is responsible for laying
out the globals efficiently to minimize the sizes of the underlying bitsets.
.. _GlobalLayoutBuilder: https://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/LowerTypeTests.h?view=markup
Alignment
~~~~~~~~~
If all gaps between address points in a particular bit vector are multiples
of powers of 2, the compiler can compress the bit vector by strengthening
the alignment requirements of the virtual table pointer. For example, given
this class hierarchy:
.. code-block:: c++
struct A {
virtual void f1();
virtual void f2();
};
struct B : A {
virtual void f1();
virtual void f2();
virtual void f3();
virtual void f4();
virtual void f5();
virtual void f6();
};
struct C : A {
virtual void f1();
virtual void f2();
};
The virtual tables will be laid out like this:
.. csv-table:: Virtual Table Layout for A, B, C
:header: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
A::offset-to-top, &A::rtti, &A::f1, &A::f2, B::offset-to-top, &B::rtti, &B::f1, &B::f2, &B::f3, &B::f4, &B::f5, &B::f6, C::offset-to-top, &C::rtti, &C::f1, &C::f2
Notice that each address point for A is separated by 4 words. This lets us
emit a compressed bit vector for A that looks like this:
.. csv-table::
:header: 2, 6, 10, 14
1, 1, 0, 1
At call sites, the compiler will strengthen the alignment requirements by
using a different rotate count. For example, on a 64-bit machine where the
address points are 4-word aligned (as in A from our example), the ``rol``
instruction may look like this:
.. code-block:: none
dd2: 48 c1 c1 3b rol $0x3b,%rcx
Padding to Powers of 2
~~~~~~~~~~~~~~~~~~~~~~
Of course, this alignment scheme works best if the address points are
in fact aligned correctly. To make this more likely to happen, we insert
padding between virtual tables that in many cases aligns address points to
a power of 2. Specifically, our padding aligns virtual tables to the next
highest power of 2 bytes; because address points for specific base classes
normally appear at fixed offsets within the virtual table, this normally
has the effect of aligning the address points as well.
This scheme introduces tradeoffs between decreased space overhead for
instructions and bit vectors and increased overhead in the form of padding. We
therefore limit the amount of padding so that we align to no more than 128
bytes. This number was found experimentally to provide a good tradeoff.
Eliminating Bit Vector Checks for All-Ones Bit Vectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the bit vector is all ones, the bit vector check is redundant; we simply
need to check that the address is in range and well aligned. This is more
likely to occur if the virtual tables are padded.
Forward-Edge CFI for Virtual Calls by Interleaving Virtual Tables
-----------------------------------------------------------------
Dimitar et. al. proposed a novel approach that interleaves virtual tables in [1]_.
This approach is more efficient in terms of space because padding and bit vectors are no longer needed.
At the same time, it is also more efficient in terms of performance because in the interleaved layout
address points of the virtual tables are consecutive, thus the validity check of a virtual
vtable pointer is always a range check.
At a high level, the interleaving scheme consists of three steps: 1) split virtual table groups into
separate virtual tables, 2) order virtual tables by a pre-order traversal of the class hierarchy
and 3) interleave virtual tables.
The interleaving scheme implemented in LLVM is inspired by [1]_ but has its own
enhancements (more in `Interleave virtual tables`_).
.. [1] `Protecting C++ Dynamic Dispatch Through VTable Interleaving <https://cseweb.ucsd.edu/~lerner/papers/ivtbl-ndss16.pdf>`_. Dimitar Bounov, Rami Gökhan Kıcı, Sorin Lerner.
Split virtual table groups into separate virtual tables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Itanium C++ ABI glues multiple individual virtual tables for a class into a combined virtual table (virtual table group).
The interleaving scheme, however, can only work with individual virtual tables so it must split the combined virtual tables first.
In comparison, the old scheme does not require the splitting but it is more efficient when the combined virtual tables have been split.
The `GlobalSplit`_ pass is responsible for splitting combined virtual tables into individual ones.
.. _GlobalSplit: https://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalSplit.cpp?view=markup
Order virtual tables by a pre-order traversal of the class hierarchy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This step is common to both the old scheme described above and the interleaving scheme.
For the interleaving scheme, since the combined virtual tables have been split in the previous step,
this step ensures that for any class all the compatible virtual tables will appear consecutively.
For the old scheme, the same property may not hold since it may work on combined virtual tables.
For example, consider the following four C++ classes:
.. code-block:: c++
struct A {
virtual void f1();
};
struct B : A {
virtual void f1();
virtual void f2();
};
struct C : A {
virtual void f1();
virtual void f3();
};
struct D : B {
virtual void f1();
virtual void f2();
};
This step will arrange the virtual tables for A, B, C, and D in the order of *vtable-of-A, vtable-of-B, vtable-of-D, vtable-of-C*.
Interleave virtual tables
~~~~~~~~~~~~~~~~~~~~~~~~~
This step is where the interleaving scheme deviates from the old scheme. Instead of laying out
whole virtual tables in the previously computed order, the interleaving scheme lays out table
entries of the virtual tables strategically to ensure the following properties:
(1) offset-to-top and RTTI fields layout property
The Itanium C++ ABI specifies that offset-to-top and RTTI fields appear at the offsets behind the
address point. Note that libraries like libcxxabi do assume this property.
(2) virtual function entry layout property
For each virtual function the distance between an virtual table entry for this function and the corresponding
address point is always the same. This property ensures that dynamic dispatch still works with the interleaving layout.
Note that the interleaving scheme in the CFI implementation guarantees both properties above whereas the original scheme proposed
in [1]_ only guarantees the second property.
To illustrate how the interleaving algorithm works, let us continue with the running example.
The algorithm first separates all the virtual table entries into two work lists. To do so,
it starts by allocating two work lists, one initialized with all the offset-to-top entries of virtual tables in the order
computed in the last step, one initialized with all the RTTI entries in the same order.
.. csv-table:: Work list 1 Layout
:header: 0, 1, 2, 3
A::offset-to-top, B::offset-to-top, D::offset-to-top, C::offset-to-top
.. csv-table:: Work list 2 layout
:header: 0, 1, 2, 3,
&A::rtti, &B::rtti, &D::rtti, &C::rtti
Then for each virtual function the algorithm goes through all the virtual tables in the previously computed order
to collect all the related entries into a virtual function list.
After this step, there are the following virtual function lists:
.. csv-table:: f1 list
:header: 0, 1, 2, 3
&A::f1, &B::f1, &D::f1, &C::f1
.. csv-table:: f2 list
:header: 0, 1
&B::f2, &D::f2
.. csv-table:: f3 list
:header: 0
&C::f3
Next, the algorithm picks the longest remaining virtual function list and appends the whole list to the shortest work list
until no function lists are left, and pads the shorter work list so that they are of the same length.
In the example, f1 list will be first added to work list 1, then f2 list will be added
to work list 2, and finally f3 list will be added to the work list 2. Since work list 1 now has one more entry than
work list 2, a padding entry is added to the latter. After this step, the two work lists look like:
.. csv-table:: Work list 1 Layout
:header: 0, 1, 2, 3, 4, 5, 6, 7
A::offset-to-top, B::offset-to-top, D::offset-to-top, C::offset-to-top, &A::f1, &B::f1, &D::f1, &C::f1
.. csv-table:: Work list 2 layout
:header: 0, 1, 2, 3, 4, 5, 6, 7
&A::rtti, &B::rtti, &D::rtti, &C::rtti, &B::f2, &D::f2, &C::f3, padding
Finally, the algorithm merges the two work lists into the interleaved layout by alternatingly
moving the head of each list to the final layout. After this step, the final interleaved layout looks like:
.. csv-table:: Interleaved layout
:header: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
A::offset-to-top, &A::rtti, B::offset-to-top, &B::rtti, D::offset-to-top, &D::rtti, C::offset-to-top, &C::rtti, &A::f1, &B::f2, &B::f1, &D::f2, &D::f1, &C::f3, &C::f1, padding
In the above interleaved layout, each virtual table's offset-to-top and RTTI are always adjacent, which shows that the layout has the first property.
For the second property, let us look at f2 as an example. In the interleaved layout,
there are two entries for f2: B::f2 and D::f2. The distance between &B::f2
and its address point D::offset-to-top (the entry immediately after &B::rtti) is 5 entry-length, so is the distance between &D::f2 and C::offset-to-top (the entry immediately after &D::rtti).
Forward-Edge CFI for Indirect Function Calls
============================================
Under forward-edge CFI for indirect function calls, each unique function
type has its own bit vector, and at each call site we need to check that the
function pointer is a member of the function type's bit vector. This scheme
works in a similar way to forward-edge CFI for virtual calls, the distinction
being that we need to build bit vectors of function entry points rather than
of virtual tables.
Unlike when re-arranging global variables, we cannot re-arrange functions
in a particular order and base our calculations on the layout of the
functions' entry points, as we have no idea how large a particular function
will end up being (the function sizes could even depend on how we arrange
the functions). Instead, we build a jump table, which is a block of code
consisting of one branch instruction for each of the functions in the bit
set that branches to the target function, and redirect any taken function
addresses to the corresponding jump table entry. In this way, the distance
between function entry points is predictable and controllable. In the object
file's symbol table, the symbols for the target functions also refer to the
jump table entries, so that addresses taken outside the module will pass
any verification done inside the module.
In more concrete terms, suppose we have three functions ``f``, ``g``,
``h`` which are all of the same type, and a function foo that returns their
addresses:
.. code-block:: none
f:
mov 0, %eax
ret
g:
mov 1, %eax
ret
h:
mov 2, %eax
ret
foo:
mov f, %eax
mov g, %edx
mov h, %ecx
ret
Our jump table will (conceptually) look like this:
.. code-block:: none
f:
jmp .Ltmp0 ; 5 bytes
int3 ; 1 byte
int3 ; 1 byte
int3 ; 1 byte
g:
jmp .Ltmp1 ; 5 bytes
int3 ; 1 byte
int3 ; 1 byte
int3 ; 1 byte
h:
jmp .Ltmp2 ; 5 bytes
int3 ; 1 byte
int3 ; 1 byte
int3 ; 1 byte
.Ltmp0:
mov 0, %eax
ret
.Ltmp1:
mov 1, %eax
ret
.Ltmp2:
mov 2, %eax
ret
foo:
mov f, %eax
mov g, %edx
mov h, %ecx
ret
Because the addresses of ``f``, ``g``, ``h`` are evenly spaced at a power of
2, and function types do not overlap (unlike class types with base classes),
we can normally apply the `Alignment`_ and `Eliminating Bit Vector Checks
for All-Ones Bit Vectors`_ optimizations thus simplifying the check at each
call site to a range and alignment check.
Shared library support
======================
**EXPERIMENTAL**
The basic CFI mode described above assumes that the application is a
monolithic binary; at least that all possible virtual/indirect call
targets and the entire class hierarchy are known at link time. The
cross-DSO mode, enabled with **-f[no-]sanitize-cfi-cross-dso** relaxes
this requirement by allowing virtual and indirect calls to cross the
DSO boundary.
Assuming the following setup: the binary consists of several
instrumented and several uninstrumented DSOs. Some of them may be
dlopen-ed/dlclose-d periodically, even frequently.
- Calls made from uninstrumented DSOs are not checked and just work.
- Calls inside any instrumented DSO are fully protected.
- Calls between different instrumented DSOs are also protected, with
a performance penalty (in addition to the monolithic CFI
overhead).
- Calls from an instrumented DSO to an uninstrumented one are
unchecked and just work, with performance penalty.
- Calls from an instrumented DSO outside of any known DSO are
detected as CFI violations.
In the monolithic scheme a call site is instrumented as
.. code-block:: none
if (!InlinedFastCheck(f))
abort();
call *f
In the cross-DSO scheme it becomes
.. code-block:: none
if (!InlinedFastCheck(f))
__cfi_slowpath(CallSiteTypeId, f);
call *f
CallSiteTypeId
--------------
``CallSiteTypeId`` is a stable process-wide identifier of the
call-site type. For a virtual call site, the type in question is the class
type; for an indirect function call it is the function signature. The
mapping from a type to an identifier is an ABI detail. In the current,
experimental, implementation the identifier of type T is calculated as
follows:
- Obtain the mangled name for "typeinfo name for T".
- Calculate MD5 hash of the name as a string.
- Reinterpret the first 8 bytes of the hash as a little-endian
64-bit integer.
It is possible, but unlikely, that collisions in the
``CallSiteTypeId`` hashing will result in weaker CFI checks that would
still be conservatively correct.
CFI_Check
---------
In the general case, only the target DSO knows whether the call to
function ``f`` with type ``CallSiteTypeId`` is valid or not. To
export this information, every DSO implements
.. code-block:: none
void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData)
This function provides external modules with access to CFI checks for
the targets inside this DSO. For each known ``CallSiteTypeId``, this
function performs an ``llvm.type.test`` with the corresponding type
identifier. It reports an error if the type is unknown, or if the
check fails. Depending on the values of compiler flags
``-fsanitize-trap`` and ``-fsanitize-recover``, this function may
print an error, abort and/or return to the caller. ``DiagData`` is an
opaque pointer to the diagnostic information about the error, or
``null`` if the caller does not provide this information.
The basic implementation is a large switch statement over all values
of CallSiteTypeId supported by this DSO, and each case is similar to
the InlinedFastCheck() in the basic CFI mode.
CFI Shadow
----------
To route CFI checks to the target DSO's __cfi_check function, a
mapping from possible virtual / indirect call targets to the
corresponding __cfi_check functions is maintained. This mapping is
implemented as a sparse array of 2 bytes for every possible page (4096
bytes) of memory. The table is kept readonly most of the time.
There are 3 types of shadow values:
- Address in a CFI-instrumented DSO.
- Unchecked address (a “trusted” non-instrumented DSO). Encoded as
value 0xFFFF.
- Invalid address (everything else). Encoded as value 0.
For a CFI-instrumented DSO, a shadow value encodes the address of the
__cfi_check function for all call targets in the corresponding memory
page. If Addr is the target address, and V is the shadow value, then
the address of __cfi_check is calculated as
.. code-block:: none
__cfi_check = AlignUpTo(Addr, 4096) - (V + 1) * 4096
This works as long as __cfi_check is aligned by 4096 bytes and located
below any call targets in its DSO, but not more than 256MB apart from
them.
CFI_SlowPath
------------
The slow path check is implemented in a runtime support library as
.. code-block:: none
void __cfi_slowpath(uint64 CallSiteTypeId, void *TargetAddr)
void __cfi_slowpath_diag(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData)
These functions loads a shadow value for ``TargetAddr``, finds the
address of ``__cfi_check`` as described above and calls
that. ``DiagData`` is an opaque pointer to diagnostic data which is
passed verbatim to ``__cfi_check``, and ``__cfi_slowpath`` passes
``nullptr`` instead.
Compiler-RT library contains reference implementations of slowpath
functions, but they have unresolvable issues with correctness and
performance in the handling of dlopen(). It is recommended that
platforms provide their own implementations, usually as part of libc
or libdl.
Position-independent executable requirement
-------------------------------------------
Cross-DSO CFI mode requires that the main executable is built as PIE.
In non-PIE executables the address of an external function (taken from
the main executable) is the address of that functions PLT record in
the main executable. This would break the CFI checks.
Backward-edge CFI for return statements (RCFI)
==============================================
This section is a proposal. As of March 2017 it is not implemented.
Backward-edge control flow (`RET` instructions) can be hijacked
via overwriting the return address (`RA`) on stack.
Various mitigation techniques (e.g. `SafeStack`_, `RFG`_, `Intel CET`_)
try to detect or prevent `RA` corruption on stack.
RCFI enforces the expected control flow in several different ways described below.
RCFI heavily relies on LTO.
Leaf Functions
--------------
If `f()` is a leaf function (i.e. it has no calls
except maybe no-return calls) it can be called using a special calling convention
that stores `RA` in a dedicated register `R` before the `CALL` instruction.
`f()` does not spill `R` and does not use the `RET` instruction,
instead it uses the value in `R` to `JMP` to `RA`.
This flavour of CFI is *precise*, i.e. the function is guaranteed to return
to the point exactly following the call.
An alternative approach is to
copy `RA` from stack to `R` in the first instruction of `f()`,
then `JMP` to `R`.
This approach is simpler to implement (does not require changing the caller)
but weaker (there is a small window when `RA` is actually stored on stack).
Functions called once
---------------------
Suppose `f()` is called in just one place in the program
(assuming we can verify this in LTO mode).
In this case we can replace the `RET` instruction with a `JMP` instruction
with the immediate constant for `RA`.
This will *precisely* enforce the return control flow no matter what is stored on stack.
Another variant is to compare `RA` on stack with the known constant and abort
if they don't match; then `JMP` to the known constant address.
Functions called in a small number of call sites
------------------------------------------------
We may extend the above approach to cases where `f()`
is called more than once (but still a small number of times).
With LTO we know all possible values of `RA` and we check them
one-by-one (or using binary search) against the value on stack.
If the match is found, we `JMP` to the known constant address, otherwise abort.
This protection is *near-precise*, i.e. it guarantees that the control flow will
be transferred to one of the valid return addresses for this function,
but not necessary to the point of the most recent `CALL`.
General case
------------
For functions called multiple times a *return jump table* is constructed
in the same manner as jump tables for indirect function calls (see above).
The correct jump table entry (or it's index) is passed by `CALL` to `f()`
(as an extra argument) and then spilled to stack.
The `RET` instruction is replaced with a load of the jump table entry,
jump table range check, and `JMP` to the jump table entry.
This protection is also *near-precise*.
Returns from functions called indirectly
----------------------------------------
If a function is called indirectly, the return jump table is constructed for the
equivalence class of functions instead of a single function.
Cross-DSO calls
---------------
Consider two instrumented DSOs, `A` and `B`. `A` defines `f()` and `B` calls it.
This case will be handled similarly to the cross-DSO scheme using the slow path callback.
Non-goals
---------
RCFI does not protect `RET` instructions:
* in non-instrumented DSOs,
* in instrumented DSOs for functions that are called from non-instrumented DSOs,
* embedded into other instructions (e.g. `0f4fc3 cmovg %ebx,%eax`).
.. _SafeStack: https://clang.llvm.org/docs/SafeStack.html
.. _RFG: http://xlab.tencent.com/en/2016/11/02/return-flow-guard
.. _Intel CET: https://software.intel.com/en-us/blogs/2016/06/09/intel-release-new-technology-specifications-protect-rop-attacks
Hardware support
================
We believe that the above design can be efficiently implemented in hardware.
A single new instruction added to an ISA would allow to perform the forward-edge CFI check
with fewer bytes per check (smaller code size overhead) and potentially more
efficiently. The current software-only instrumentation requires at least
32-bytes per check (on x86_64).
A hardware instruction may probably be less than ~ 12 bytes.
Such instruction would check that the argument pointer is in-bounds,
and is properly aligned, and if the checks fail it will either trap (in monolithic scheme)
or call the slow path function (cross-DSO scheme).
The bit vector lookup is probably too complex for a hardware implementation.
.. code-block:: none
// This instruction checks that 'Ptr'
// * is aligned by (1 << kAlignment) and
// * is inside [kRangeBeg, kRangeBeg+(kRangeSize<<kAlignment))
// and if the check fails it jumps to the given target (slow path).
//
// 'Ptr' is a register, pointing to the virtual function table
// or to the function which we need to check. We may require an explicit
// fixed register to be used.
// 'kAlignment' is a 4-bit constant.
// 'kRangeSize' is a ~20-bit constant.
// 'kRangeBeg' is a PC-relative constant (~28 bits)
// pointing to the beginning of the allowed range for 'Ptr'.
// 'kFailedCheckTarget': is a PC-relative constant (~28 bits)
// representing the target to branch to when the check fails.
// If kFailedCheckTarget==0, the process will trap
// (monolithic binary scheme).
// Otherwise it will jump to a handler that implements `CFI_SlowPath`
// (cross-DSO scheme).
CFI_Check(Ptr, kAlignment, kRangeSize, kRangeBeg, kFailedCheckTarget) {
if (Ptr < kRangeBeg ||
Ptr >= kRangeBeg + (kRangeSize << kAlignment) ||
Ptr & ((1 << kAlignment) - 1))
Jump(kFailedCheckTarget);
}
An alternative and more compact encoding would not use `kFailedCheckTarget`,
and will trap on check failure instead.
This will allow us to fit the instruction into **8-9 bytes**.
The cross-DSO checks will be performed by a trap handler and
performance-critical ones will have to be black-listed and checked using the
software-only scheme.
Note that such hardware extension would be complementary to checks
at the callee side, such as e.g. **Intel ENDBRANCH**.
Moreover, CFI would have two benefits over ENDBRANCH: a) precision and b)
ability to protect against invalid casts between polymorphic types.

View File

@ -1,203 +0,0 @@
===================================================================
Cross-compilation using Clang
===================================================================
Introduction
============
This document will guide you in choosing the right Clang options
for cross-compiling your code to a different architecture. It assumes you
already know how to compile the code in question for the host architecture,
and that you know how to choose additional include and library paths.
However, this document is *not* a "how to" and won't help you setting your
build system or Makefiles, nor choosing the right CMake options, etc.
Also, it does not cover all the possible options, nor does it contain
specific examples for specific architectures. For a concrete example, the
`instructions for cross-compiling LLVM itself
<https://llvm.org/docs/HowToCrossCompileLLVM.html>`_ may be of interest.
After reading this document, you should be familiar with the main issues
related to cross-compilation, and what main compiler options Clang provides
for performing cross-compilation.
Cross compilation issues
========================
In GCC world, every host/target combination has its own set of binaries,
headers, libraries, etc. So, it's usually simple to download a package
with all files in, unzip to a directory and point the build system to
that compiler, that will know about its location and find all it needs to
when compiling your code.
On the other hand, Clang/LLVM is natively a cross-compiler, meaning that
one set of programs can compile to all targets by setting the ``-target``
option. That makes it a lot easier for programmers wishing to compile to
different platforms and architectures, and for compiler developers that
only have to maintain one build system, and for OS distributions, that
need only one set of main packages.
But, as is true to any cross-compiler, and given the complexity of
different architectures, OS's and options, it's not always easy finding
the headers, libraries or binutils to generate target specific code.
So you'll need special options to help Clang understand what target
you're compiling to, where your tools are, etc.
Another problem is that compilers come with standard libraries only (like
``compiler-rt``, ``libcxx``, ``libgcc``, ``libm``, etc), so you'll have to
find and make available to the build system, every other library required
to build your software, that is specific to your target. It's not enough to
have your host's libraries installed.
Finally, not all toolchains are the same, and consequently, not every Clang
option will work magically. Some options, like ``--sysroot`` (which
effectively changes the logical root for headers and libraries), assume
all your binaries and libraries are in the same directory, which may not
true when your cross-compiler was installed by the distribution's package
management. So, for each specific case, you may use more than one
option, and in most cases, you'll end up setting include paths (``-I``) and
library paths (``-L``) manually.
To sum up, different toolchains can:
* be host/target specific or more flexible
* be in a single directory, or spread out across your system
* have different sets of libraries and headers by default
* need special options, which your build system won't be able to figure
out by itself
General Cross-Compilation Options in Clang
==========================================
Target Triple
-------------
The basic option is to define the target architecture. For that, use
``-target <triple>``. If you don't specify the target, CPU names won't
match (since Clang assumes the host triple), and the compilation will
go ahead, creating code for the host platform, which will break later
on when assembling or linking.
The triple has the general format ``<arch><sub>-<vendor>-<sys>-<abi>``, where:
* ``arch`` = ``x86_64``, ``i386``, ``arm``, ``thumb``, ``mips``, etc.
* ``sub`` = for ex. on ARM: ``v5``, ``v6m``, ``v7a``, ``v7m``, etc.
* ``vendor`` = ``pc``, ``apple``, ``nvidia``, ``ibm``, etc.
* ``sys`` = ``none``, ``linux``, ``win32``, ``darwin``, ``cuda``, etc.
* ``abi`` = ``eabi``, ``gnu``, ``android``, ``macho``, ``elf``, etc.
The sub-architecture options are available for their own architectures,
of course, so "x86v7a" doesn't make sense. The vendor needs to be
specified only if there's a relevant change, for instance between PC
and Apple. Most of the time it can be omitted (and Unknown)
will be assumed, which sets the defaults for the specified architecture.
The system name is generally the OS (linux, darwin), but could be special
like the bare-metal "none".
When a parameter is not important, it can be omitted, or you can
choose ``unknown`` and the defaults will be used. If you choose a parameter
that Clang doesn't know, like ``blerg``, it'll ignore and assume
``unknown``, which is not always desired, so be careful.
Finally, the ABI option is something that will pick default CPU/FPU,
define the specific behaviour of your code (PCS, extensions),
and also choose the correct library calls, etc.
CPU, FPU, ABI
-------------
Once your target is specified, it's time to pick the hardware you'll
be compiling to. For every architecture, a default set of CPU/FPU/ABI
will be chosen, so you'll almost always have to change it via flags.
Typical flags include:
* ``-mcpu=<cpu-name>``, like x86-64, swift, cortex-a15
* ``-mfpu=<fpu-name>``, like SSE3, NEON, controlling the FP unit available
* ``-mfloat-abi=<fabi>``, like soft, hard, controlling which registers
to use for floating-point
The default is normally the common denominator, so that Clang doesn't
generate code that breaks. But that also means you won't get the best
code for your specific hardware, which may mean orders of magnitude
slower than you expect.
For example, if your target is ``arm-none-eabi``, the default CPU will
be ``arm7tdmi`` using soft float, which is extremely slow on modern cores,
whereas if your triple is ``armv7a-none-eabi``, it'll be Cortex-A8 with
NEON, but still using soft-float, which is much better, but still not
great.
Toolchain Options
-----------------
There are three main options to control access to your cross-compiler:
``--sysroot``, ``-I``, and ``-L``. The two last ones are well known,
but they're particularly important for additional libraries
and headers that are specific to your target.
There are two main ways to have a cross-compiler:
#. When you have extracted your cross-compiler from a zip file into
a directory, you have to use ``--sysroot=<path>``. The path is the
root directory where you have unpacked your file, and Clang will
look for the directories ``bin``, ``lib``, ``include`` in there.
In this case, your setup should be pretty much done (if no
additional headers or libraries are needed), as Clang will find
all binaries it needs (assembler, linker, etc) in there.
#. When you have installed via a package manager (modern Linux
distributions have cross-compiler packages available), make
sure the target triple you set is *also* the prefix of your
cross-compiler toolchain.
In this case, Clang will find the other binaries (assembler,
linker), but not always where the target headers and libraries
are. People add system-specific clues to Clang often, but as
things change, it's more likely that it won't find than the
other way around.
So, here, you'll be a lot safer if you specify the include/library
directories manually (via ``-I`` and ``-L``).
Target-Specific Libraries
=========================
All libraries that you compile as part of your build will be
cross-compiled to your target, and your build system will probably
find them in the right place. But all dependencies that are
normally checked against (like ``libxml`` or ``libz`` etc) will match
against the host platform, not the target.
So, if the build system is not aware that you want to cross-compile
your code, it will get every dependency wrong, and your compilation
will fail during build time, not configure time.
Also, finding the libraries for your target are not as easy
as for your host machine. There aren't many cross-libraries available
as packages to most OS's, so you'll have to either cross-compile them
from source, or download the package for your target platform,
extract the libraries and headers, put them in specific directories
and add ``-I`` and ``-L`` pointing to them.
Also, some libraries have different dependencies on different targets,
so configuration tools to find dependencies in the host can get the
list wrong for the target platform. This means that the configuration
of your build can get things wrong when setting their own library
paths, and you'll have to augment it via additional flags (configure,
Make, CMake, etc).
Multilibs
---------
When you want to cross-compile to more than one configuration, for
example hard-float-ARM and soft-float-ARM, you'll have to have multiple
copies of your libraries and (possibly) headers.
Some Linux distributions have support for Multilib, which handle that
for you in an easier way, but if you're not careful and, for instance,
forget to specify ``-ccc-gcc-name armv7l-linux-gnueabihf-gcc`` (which
uses hard-float), Clang will pick the ``armv7l-linux-gnueabi-ld``
(which uses soft-float) and linker errors will happen.
The same is true if you're compiling for different ABIs, like ``gnueabi``
and ``androideabi``, and might even link and run, but produce run-time
errors, which are much harder to track down and fix.

View File

@ -1,158 +0,0 @@
=================
DataFlowSanitizer
=================
.. toctree::
:hidden:
DataFlowSanitizerDesign
.. contents::
:local:
Introduction
============
DataFlowSanitizer is a generalised dynamic data flow analysis.
Unlike other Sanitizer tools, this tool is not designed to detect a
specific class of bugs on its own. Instead, it provides a generic
dynamic data flow analysis framework to be used by clients to help
detect application-specific issues within their own code.
Usage
=====
With no program changes, applying DataFlowSanitizer to a program
will not alter its behavior. To use DataFlowSanitizer, the program
uses API functions to apply tags to data to cause it to be tracked, and to
check the tag of a specific data item. DataFlowSanitizer manages
the propagation of tags through the program according to its data flow.
The APIs are defined in the header file ``sanitizer/dfsan_interface.h``.
For further information about each function, please refer to the header
file.
ABI List
--------
DataFlowSanitizer uses a list of functions known as an ABI list to decide
whether a call to a specific function should use the operating system's native
ABI or whether it should use a variant of this ABI that also propagates labels
through function parameters and return values. The ABI list file also controls
how labels are propagated in the former case. DataFlowSanitizer comes with a
default ABI list which is intended to eventually cover the glibc library on
Linux but it may become necessary for users to extend the ABI list in cases
where a particular library or function cannot be instrumented (e.g. because
it is implemented in assembly or another language which DataFlowSanitizer does
not support) or a function is called from a library or function which cannot
be instrumented.
DataFlowSanitizer's ABI list file is a :doc:`SanitizerSpecialCaseList`.
The pass treats every function in the ``uninstrumented`` category in the
ABI list file as conforming to the native ABI. Unless the ABI list contains
additional categories for those functions, a call to one of those functions
will produce a warning message, as the labelling behavior of the function
is unknown. The other supported categories are ``discard``, ``functional``
and ``custom``.
* ``discard`` -- To the extent that this function writes to (user-accessible)
memory, it also updates labels in shadow memory (this condition is trivially
satisfied for functions which do not write to user-accessible memory). Its
return value is unlabelled.
* ``functional`` -- Like ``discard``, except that the label of its return value
is the union of the label of its arguments.
* ``custom`` -- Instead of calling the function, a custom wrapper ``__dfsw_F``
is called, where ``F`` is the name of the function. This function may wrap
the original function or provide its own implementation. This category is
generally used for uninstrumentable functions which write to user-accessible
memory or which have more complex label propagation behavior. The signature
of ``__dfsw_F`` is based on that of ``F`` with each argument having a
label of type ``dfsan_label`` appended to the argument list. If ``F``
is of non-void return type a final argument of type ``dfsan_label *``
is appended to which the custom function can store the label for the
return value. For example:
.. code-block:: c++
void f(int x);
void __dfsw_f(int x, dfsan_label x_label);
void *memcpy(void *dest, const void *src, size_t n);
void *__dfsw_memcpy(void *dest, const void *src, size_t n,
dfsan_label dest_label, dfsan_label src_label,
dfsan_label n_label, dfsan_label *ret_label);
If a function defined in the translation unit being compiled belongs to the
``uninstrumented`` category, it will be compiled so as to conform to the
native ABI. Its arguments will be assumed to be unlabelled, but it will
propagate labels in shadow memory.
For example:
.. code-block:: none
# main is called by the C runtime using the native ABI.
fun:main=uninstrumented
fun:main=discard
# malloc only writes to its internal data structures, not user-accessible memory.
fun:malloc=uninstrumented
fun:malloc=discard
# tolower is a pure function.
fun:tolower=uninstrumented
fun:tolower=functional
# memcpy needs to copy the shadow from the source to the destination region.
# This is done in a custom function.
fun:memcpy=uninstrumented
fun:memcpy=custom
Example
=======
The following program demonstrates label propagation by checking that
the correct labels are propagated.
.. code-block:: c++
#include <sanitizer/dfsan_interface.h>
#include <assert.h>
int main(void) {
int i = 1;
dfsan_label i_label = dfsan_create_label("i", 0);
dfsan_set_label(i_label, &i, sizeof(i));
int j = 2;
dfsan_label j_label = dfsan_create_label("j", 0);
dfsan_set_label(j_label, &j, sizeof(j));
int k = 3;
dfsan_label k_label = dfsan_create_label("k", 0);
dfsan_set_label(k_label, &k, sizeof(k));
dfsan_label ij_label = dfsan_get_label(i + j);
assert(dfsan_has_label(ij_label, i_label));
assert(dfsan_has_label(ij_label, j_label));
assert(!dfsan_has_label(ij_label, k_label));
dfsan_label ijk_label = dfsan_get_label(i + j + k);
assert(dfsan_has_label(ijk_label, i_label));
assert(dfsan_has_label(ijk_label, j_label));
assert(dfsan_has_label(ijk_label, k_label));
return 0;
}
Current status
==============
DataFlowSanitizer is a work in progress, currently under development for
x86\_64 Linux.
Design
======
Please refer to the :doc:`design document<DataFlowSanitizerDesign>`.

Some files were not shown because too many files have changed in this diff Show More