зеркало из https://github.com/microsoft/clang-1.git
Creating release candidate final from release_31 branch
git-svn-id: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_31@156748 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
534b67cf22
Коммит
5ed2244156
|
@ -0,0 +1,25 @@
|
|||
#==============================================================================#
|
||||
# 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
|
||||
.*.swp
|
||||
|
||||
#==============================================================================#
|
||||
# Explicit files to ignore (only matches one).
|
||||
#==============================================================================#
|
||||
cscope.files
|
||||
cscope.out
|
|
@ -0,0 +1,282 @@
|
|||
# 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)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(CLANG_PATH_TO_LLVM_SOURCE "" CACHE PATH
|
||||
"Path to LLVM source code. Not necessary if using an installed LLVM.")
|
||||
set(CLANG_PATH_TO_LLVM_BUILD "" CACHE PATH
|
||||
"Path to the directory where LLVM was built or installed.")
|
||||
|
||||
if( CLANG_PATH_TO_LLVM_SOURCE )
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_SOURCE}/cmake/config-ix.cmake" )
|
||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_SOURCE to the root directory of LLVM source code.")
|
||||
else()
|
||||
get_filename_component(LLVM_MAIN_SRC_DIR ${CLANG_PATH_TO_LLVM_SOURCE}
|
||||
ABSOLUTE)
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
# Looking for bin/Debug/llvm-tblgen is a complete hack. How can we get
|
||||
# around this?
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
|
||||
|
||||
get_filename_component(PATH_TO_LLVM_BUILD ${CLANG_PATH_TO_LLVM_BUILD}
|
||||
ABSOLUTE)
|
||||
|
||||
include(AddLLVM)
|
||||
include(TableGen)
|
||||
include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
|
||||
include(HandleLLVMOptions)
|
||||
|
||||
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
|
||||
|
||||
set(LLVM_MAIN_INCLUDE_DIR "${LLVM_MAIN_SRC_DIR}/include")
|
||||
set(LLVM_BINARY_DIR ${CMAKE_BINARY_DIR})
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
|
||||
link_directories("${PATH_TO_LLVM_BUILD}/lib")
|
||||
|
||||
if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
else()
|
||||
# FIXME: This is an utter hack.
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
endif()
|
||||
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
|
||||
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
|
||||
set( CLANG_BUILT_STANDALONE 1 )
|
||||
endif()
|
||||
|
||||
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(CLANG_VENDOR "" CACHE STRING
|
||||
"Vendor-specific text for showing with version information.")
|
||||
|
||||
if( CLANG_VENDOR )
|
||||
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
|
||||
endif()
|
||||
|
||||
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. CMake would overwrite "
|
||||
"the makefiles distributed with LLVM. 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( NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
|
||||
file(GLOB_RECURSE
|
||||
tablegenned_files_on_include_dir
|
||||
"${CLANG_SOURCE_DIR}/include/clang/*.inc")
|
||||
if( tablegenned_files_on_include_dir )
|
||||
message(FATAL_ERROR "Apparently there is a previous in-source build, "
|
||||
"probably as the result of running `configure' and `make' on "
|
||||
"${CLANG_SOURCE_DIR}. This may cause problems. The suspicious files are:\n"
|
||||
"${tablegenned_files_on_include_dir}\nPlease clean the source directory.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Compute the Clang version from the LLVM version.
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
${PACKAGE_VERSION})
|
||||
message(STATUS "Clang version: ${CLANG_VERSION}")
|
||||
|
||||
string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" CLANG_VERSION_MAJOR
|
||||
${CLANG_VERSION})
|
||||
string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" CLANG_VERSION_MINOR
|
||||
${CLANG_VERSION})
|
||||
if (${CLANG_VERSION} MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
|
||||
set(CLANG_HAS_VERSION_PATCHLEVEL 1)
|
||||
string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" CLANG_VERSION_PATCHLEVEL
|
||||
${CLANG_VERSION})
|
||||
else()
|
||||
set(CLANG_HAS_VERSION_PATCHLEVEL 0)
|
||||
endif()
|
||||
|
||||
# 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 -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
|
||||
endif ()
|
||||
|
||||
configure_file(
|
||||
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
|
||||
${CLANG_BINARY_DIR}/include/clang/Config/config.h)
|
||||
|
||||
include(LLVMParseArguments)
|
||||
|
||||
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.
|
||||
|
||||
parse_arguments( CTG "SOURCE;TARGET;DEPENDS" "" ${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_DEFAULT_ARGS} )
|
||||
|
||||
list( GET CTG_DEFAULT_ARGS 0 output_file )
|
||||
if( CTG_TARGET )
|
||||
add_custom_target( ${CTG_TARGET} DEPENDS ${output_file} ${CTG_DEPENDS} )
|
||||
set_target_properties( ${CTG_TARGET} PROPERTIES FOLDER "Clang tablegenning")
|
||||
endif()
|
||||
endfunction(clang_tablegen)
|
||||
|
||||
macro(add_clang_library name)
|
||||
llvm_process_sources(srcs ${ARGN})
|
||||
if(MSVC_IDE OR XCODE)
|
||||
string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list( GET split_path -1 dir)
|
||||
file( GLOB_RECURSE headers
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.h
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.td
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.def
|
||||
../../include/clang${dir}/*.h
|
||||
../../include/clang${dir}/*.td
|
||||
../../include/clang${dir}/*.def)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE OR XCODE)
|
||||
if (MODULE)
|
||||
set(libkind MODULE)
|
||||
elseif (SHARED_LIBRARY)
|
||||
set(libkind SHARED)
|
||||
else()
|
||||
set(libkind)
|
||||
endif()
|
||||
add_library( ${name} ${libkind} ${srcs} )
|
||||
if( LLVM_COMMON_DEPENDS )
|
||||
add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
|
||||
endif( LLVM_COMMON_DEPENDS )
|
||||
|
||||
target_link_libraries( ${name} ${LLVM_USED_LIBS} )
|
||||
llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
|
||||
target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
|
||||
link_system_libs( ${name} )
|
||||
|
||||
add_dependencies(${name} ClangDiagnosticCommon)
|
||||
if(MSVC)
|
||||
get_target_property(cflag ${name} COMPILE_FLAGS)
|
||||
if(NOT cflag)
|
||||
set(cflag "")
|
||||
endif(NOT cflag)
|
||||
set(cflag "${cflag} /Za")
|
||||
set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag})
|
||||
endif(MSVC)
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
RUNTIME DESTINATION bin)
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
|
||||
endmacro(add_clang_library)
|
||||
|
||||
macro(add_clang_executable name)
|
||||
add_llvm_executable( ${name} ${ARGN} )
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Clang executables")
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
include_directories(BEFORE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "*.def"
|
||||
PATTERN "*.h"
|
||||
PATTERN "config.h" EXCLUDE
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "*.inc"
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
# Clang version information
|
||||
set(CLANG_EXECUTABLE_VERSION
|
||||
"${CLANG_VERSION_MAJOR}.${CLANG_VERSION_MINOR}" CACHE STRING
|
||||
"Version number that will be placed into the clang executable, in the form XX.YY")
|
||||
set(LIBCLANG_LIBRARY_VERSION
|
||||
"${CLANG_VERSION_MAJOR}.${CLANG_VERSION_MINOR}" CACHE STRING
|
||||
"Version number that will be placed into the libclang library , in the form XX.YY")
|
||||
mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
|
||||
|
||||
add_subdirectory(utils/TableGen)
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
|
||||
add_subdirectory(examples)
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(runtime)
|
||||
|
||||
# TODO: docs.
|
||||
add_subdirectory(test)
|
||||
|
||||
if( LLVM_INCLUDE_TESTS )
|
||||
if( NOT CLANG_BUILT_STANDALONE )
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Workaround for MSVS10 to avoid the Dialog Hell
|
||||
# FIXME: This could be removed with future version of CMake.
|
||||
if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
|
||||
set(CLANG_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/Clang.sln")
|
||||
if( EXISTS "${CLANG_SLN_FILENAME}" )
|
||||
file(APPEND "${CLANG_SLN_FILENAME}" "\n# This should be regenerated!\n")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
|
||||
"Default URL where bug reports are to be submitted.")
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
|
@ -0,0 +1,86 @@
|
|||
#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
|
|
@ -0,0 +1,639 @@
|
|||
/* 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
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//#import<vecLib/vecLib.h>
|
|
@ -0,0 +1,27 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// 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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// 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>
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
// 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)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
// 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
|
|
@ -0,0 +1,47 @@
|
|||
#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)
|
|
@ -0,0 +1,49 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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 supports a gcc like command line
|
||||
interface. See the man page for clang (installed into $prefix/share/man/man1)
|
||||
for more information.
|
|
@ -0,0 +1,63 @@
|
|||
==============================================================================
|
||||
LLVM Release License
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007-2012 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
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
|
||||
CONTRIBUTORS 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 WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
<none yet>
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
##===- Makefile --------------------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
# If CLANG_LEVEL is not set, then we are the top-level Makefile. Otherwise, we
|
||||
# are being included from a subdirectory makefile.
|
||||
|
||||
ifndef CLANG_LEVEL
|
||||
|
||||
IS_TOP_LEVEL := 1
|
||||
CLANG_LEVEL := .
|
||||
DIRS := utils/TableGen include lib tools runtime docs unittests
|
||||
|
||||
PARALLEL_DIRS :=
|
||||
|
||||
ifeq ($(BUILD_EXAMPLES),1)
|
||||
PARALLEL_DIRS += examples
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),libs-only)
|
||||
DIRS := $(filter-out tools docs, $(DIRS))
|
||||
OPTIONAL_DIRS :=
|
||||
endif
|
||||
|
||||
###
|
||||
# Common Makefile code, shared by all Clang Makefiles.
|
||||
|
||||
# Set LLVM source root level.
|
||||
LEVEL := $(CLANG_LEVEL)/../..
|
||||
|
||||
# Include LLVM common makefile.
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
ifneq ($(ENABLE_DOCS),1)
|
||||
DIRS := $(filter-out docs, $(DIRS))
|
||||
endif
|
||||
|
||||
# Set common Clang build flags.
|
||||
CPP.Flags += -I$(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include -I$(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include
|
||||
ifdef CLANG_VENDOR
|
||||
CPP.Flags += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
|
||||
endif
|
||||
ifdef CLANG_REPOSITORY_STRING
|
||||
CPP.Flags += -DCLANG_REPOSITORY_STRING='"$(CLANG_REPOSITORY_STRING)"'
|
||||
endif
|
||||
|
||||
# Disable -fstrict-aliasing. Darwin disables it by default (and LLVM doesn't
|
||||
# work with it enabled with GCC), Clang/llvm-gcc don't support it yet, and newer
|
||||
# GCC's have false positive warnings with it on Linux (which prove a pain to
|
||||
# fix). For example:
|
||||
# http://gcc.gnu.org/PR41874
|
||||
# http://gcc.gnu.org/PR41838
|
||||
#
|
||||
# We can revisit this when LLVM/Clang support it.
|
||||
CXX.Flags += -fno-strict-aliasing
|
||||
|
||||
# Set up Clang's tblgen.
|
||||
ifndef CLANG_TBLGEN
|
||||
ifeq ($(LLVM_CROSS_COMPILING),1)
|
||||
CLANG_TBLGEN := $(BuildLLVMToolDir)/clang-tblgen$(BUILD_EXEEXT)
|
||||
else
|
||||
CLANG_TBLGEN := $(LLVMToolDir)/clang-tblgen$(EXEEXT)
|
||||
endif
|
||||
endif
|
||||
ClangTableGen = $(CLANG_TBLGEN) $(TableGen.Flags)
|
||||
|
||||
###
|
||||
# Clang Top Level specific stuff.
|
||||
|
||||
ifeq ($(IS_TOP_LEVEL),1)
|
||||
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
$(RecursiveTargets)::
|
||||
$(Verb) for dir in test unittests; do \
|
||||
if [ -f $(PROJ_SRC_DIR)/$${dir}/Makefile ] && [ ! -f $${dir}/Makefile ]; then \
|
||||
$(MKDIR) $${dir}; \
|
||||
$(CP) $(PROJ_SRC_DIR)/$${dir}/Makefile $${dir}/Makefile; \
|
||||
fi \
|
||||
done
|
||||
endif
|
||||
|
||||
test::
|
||||
@ $(MAKE) -C test
|
||||
|
||||
report::
|
||||
@ $(MAKE) -C test report
|
||||
|
||||
clean::
|
||||
@ $(MAKE) -C test clean
|
||||
|
||||
libs-only: all
|
||||
|
||||
tags::
|
||||
$(Verb) etags `find . -type f -name '*.h' -or -name '*.cpp' | \
|
||||
grep -v /lib/Headers | grep -v /test/`
|
||||
|
||||
cscope.files:
|
||||
find tools lib include -name '*.cpp' \
|
||||
-or -name '*.def' \
|
||||
-or -name '*.td' \
|
||||
-or -name '*.h' > cscope.files
|
||||
|
||||
.PHONY: test report clean cscope.files
|
||||
|
||||
endif
|
|
@ -0,0 +1,5 @@
|
|||
# This file provides information for llvm-top
|
||||
DepModule: llvm
|
||||
ConfigCmd:
|
||||
ConfigTest:
|
||||
BuildCmd:
|
|
@ -0,0 +1,114 @@
|
|||
//===---------------------------------------------------------------------===//
|
||||
// Random Notes
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C90/C99/C++ Comparisons:
|
||||
http://david.tribble.com/text/cdiffs.htm
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
To time GCC preprocessing speed without output, use:
|
||||
"time gcc -MM file"
|
||||
This is similar to -Eonly.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Creating and using a PTH file for performance measurement (use a release build).
|
||||
|
||||
$ clang -ccc-pch-is-pth -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache
|
||||
$ clang -cc1 -token-cache /tmp/tokencache INPUTS/Cocoa_h.m
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
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 an 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.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
|
@ -0,0 +1,26 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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.cs.uiuc.edu/mailman/listinfo/cfe-dev
|
||||
|
||||
If you find a bug in Clang, please file it in the LLVM bug tracker:
|
||||
http://llvm.org/bugs/
|
|
@ -0,0 +1,17 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// Clang Python Bindings
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
This directory implements Python bindings for Clang.
|
||||
|
||||
You may need to alter LD_LIBRARY_PATH so that the Clang library can be
|
||||
found. The unit tests are designed to be run with 'nosetests'. For example:
|
||||
--
|
||||
$ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \
|
||||
LD_LIBRARY_PATH=$(llvm-config --libdir) \
|
||||
nosetests -v
|
||||
tests.cindex.test_index.test_create ... ok
|
||||
...
|
||||
|
||||
OK
|
||||
--
|
|
@ -0,0 +1,24 @@
|
|||
#===- __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']
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,87 @@
|
|||
#!/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="Don't compute cursor IDs (very slow)",
|
||||
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', map(get_diag_info, tu.diagnostics)))
|
||||
pprint(('nodes', get_info(tu.cursor)))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#!/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()
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef HEADER1
|
||||
#define HEADER1
|
||||
|
||||
#include "header3.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef HEADER2
|
||||
#define HEADER2
|
||||
|
||||
#include "header3.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
// Not a guarded header!
|
||||
|
||||
void f();
|
|
@ -0,0 +1,6 @@
|
|||
#include "stdio.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
printf("hello world\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#include "header1.h"
|
||||
#include "header2.h"
|
||||
#include "header1.h"
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,2 @@
|
|||
int DECL_ONE = 1;
|
||||
int DECL_TWO = 2;
|
|
@ -0,0 +1,92 @@
|
|||
from clang.cindex import CursorKind
|
||||
from clang.cindex import TypeKind
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
kInput = """\
|
||||
// FIXME: Find nicer way to drop builtins and other cruft.
|
||||
int start_decl;
|
||||
|
||||
struct s0 {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
struct s1;
|
||||
|
||||
void f0(int a0, int a1) {
|
||||
int l0, l1;
|
||||
|
||||
if (a0)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def test_get_children():
|
||||
tu = get_tu(kInput)
|
||||
|
||||
# Skip until past start_decl.
|
||||
it = tu.cursor.get_children()
|
||||
while it.next().spelling != 'start_decl':
|
||||
pass
|
||||
|
||||
tu_nodes = list(it)
|
||||
|
||||
assert len(tu_nodes) == 3
|
||||
|
||||
assert tu_nodes[0] != tu_nodes[1]
|
||||
assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
|
||||
assert tu_nodes[0].spelling == 's0'
|
||||
assert tu_nodes[0].is_definition() == True
|
||||
assert tu_nodes[0].location.file.name == 't.c'
|
||||
assert tu_nodes[0].location.line == 4
|
||||
assert tu_nodes[0].location.column == 8
|
||||
assert tu_nodes[0].hash > 0
|
||||
|
||||
s0_nodes = list(tu_nodes[0].get_children())
|
||||
assert len(s0_nodes) == 2
|
||||
assert s0_nodes[0].kind == CursorKind.FIELD_DECL
|
||||
assert s0_nodes[0].spelling == 'a'
|
||||
assert s0_nodes[0].type.kind == TypeKind.INT
|
||||
assert s0_nodes[1].kind == CursorKind.FIELD_DECL
|
||||
assert s0_nodes[1].spelling == 'b'
|
||||
assert s0_nodes[1].type.kind == TypeKind.INT
|
||||
|
||||
assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
|
||||
assert tu_nodes[1].spelling == 's1'
|
||||
assert tu_nodes[1].displayname == 's1'
|
||||
assert tu_nodes[1].is_definition() == False
|
||||
|
||||
assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
|
||||
assert tu_nodes[2].spelling == 'f0'
|
||||
assert tu_nodes[2].displayname == 'f0(int, int)'
|
||||
assert tu_nodes[2].is_definition() == True
|
||||
|
||||
def test_underlying_type():
|
||||
tu = get_tu('typedef int foo;')
|
||||
typedef = get_cursor(tu, 'foo')
|
||||
assert typedef is not None
|
||||
|
||||
assert typedef.kind.is_declaration()
|
||||
underlying = typedef.underlying_typedef_type
|
||||
assert underlying.kind == TypeKind.INT
|
||||
|
||||
def test_enum_type():
|
||||
tu = get_tu('enum TEST { FOO=1, BAR=2 };')
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
enum_type = enum.enum_type
|
||||
assert enum_type.kind == TypeKind.UINT
|
||||
|
||||
def test_objc_type_encoding():
|
||||
tu = get_tu('int i;', lang='objc')
|
||||
i = get_cursor(tu, 'i')
|
||||
|
||||
assert i is not None
|
||||
assert i.objc_type_encoding == 'i'
|
|
@ -0,0 +1,40 @@
|
|||
from clang.cindex import CursorKind
|
||||
|
||||
def test_name():
|
||||
assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
|
||||
|
||||
def test_get_all_kinds():
|
||||
assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds()
|
||||
assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds()
|
||||
|
||||
def test_kind_groups():
|
||||
"""Check that every kind classifies to exactly one group."""
|
||||
|
||||
assert CursorKind.UNEXPOSED_DECL.is_declaration()
|
||||
assert CursorKind.TYPE_REF.is_reference()
|
||||
assert CursorKind.DECL_REF_EXPR.is_expression()
|
||||
assert CursorKind.UNEXPOSED_STMT.is_statement()
|
||||
assert CursorKind.INVALID_FILE.is_invalid()
|
||||
|
||||
assert CursorKind.TRANSLATION_UNIT.is_translation_unit()
|
||||
assert not CursorKind.TYPE_REF.is_translation_unit()
|
||||
|
||||
assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing()
|
||||
assert not CursorKind.TYPE_REF.is_preprocessing()
|
||||
|
||||
assert CursorKind.UNEXPOSED_DECL.is_unexposed()
|
||||
assert not 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):
|
||||
assert len(group) == 0
|
||||
else:
|
||||
assert len(group) == 1
|
|
@ -0,0 +1,82 @@
|
|||
from clang.cindex import *
|
||||
from .util import get_tu
|
||||
|
||||
# FIXME: We need support for invalid translation units to test better.
|
||||
|
||||
def test_diagnostic_warning():
|
||||
tu = get_tu('int f0() {}\n')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 11
|
||||
assert (tu.diagnostics[0].spelling ==
|
||||
'control reaches end of non-void function')
|
||||
|
||||
def test_diagnostic_note():
|
||||
# FIXME: We aren't getting notes here for some reason.
|
||||
tu = get_tu('#define A x\nvoid *A = 1;\n')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 2
|
||||
assert tu.diagnostics[0].location.column == 7
|
||||
assert 'incompatible' in tu.diagnostics[0].spelling
|
||||
# assert tu.diagnostics[1].severity == Diagnostic.Note
|
||||
# assert tu.diagnostics[1].location.line == 1
|
||||
# assert tu.diagnostics[1].location.column == 11
|
||||
# assert tu.diagnostics[1].spelling == 'instantiated from'
|
||||
|
||||
def test_diagnostic_fixit():
|
||||
tu = get_tu('struct { int f0; } x = { f0 : 1 };')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 26
|
||||
assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
|
||||
assert len(tu.diagnostics[0].fixits) == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.start.line == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.start.column == 26
|
||||
assert tu.diagnostics[0].fixits[0].range.end.line == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.end.column == 30
|
||||
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
|
||||
|
||||
def test_diagnostic_range():
|
||||
tu = get_tu('void f() { int i = "a" + 1; }')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 16
|
||||
assert tu.diagnostics[0].spelling.startswith('incompatible pointer to')
|
||||
assert len(tu.diagnostics[0].fixits) == 0
|
||||
assert len(tu.diagnostics[0].ranges) == 1
|
||||
assert tu.diagnostics[0].ranges[0].start.line == 1
|
||||
assert tu.diagnostics[0].ranges[0].start.column == 20
|
||||
assert tu.diagnostics[0].ranges[0].end.line == 1
|
||||
assert tu.diagnostics[0].ranges[0].end.column == 27
|
||||
try:
|
||||
tu.diagnostics[0].ranges[1].start.line
|
||||
except IndexError:
|
||||
assert True
|
||||
else:
|
||||
assert False
|
||||
|
||||
def test_diagnostic_category():
|
||||
"""Ensure that category properties work."""
|
||||
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
|
||||
assert len(tu.diagnostics) == 1
|
||||
d = tu.diagnostics[0]
|
||||
|
||||
assert d.severity == Diagnostic.Warning
|
||||
assert d.location.line == 1
|
||||
assert d.location.column == 11
|
||||
|
||||
assert d.category_number == 2
|
||||
assert d.category_name == 'Semantic Issue'
|
||||
|
||||
def test_diagnostic_option():
|
||||
"""Ensure that category option properties work."""
|
||||
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
|
||||
assert len(tu.diagnostics) == 1
|
||||
d = tu.diagnostics[0]
|
||||
|
||||
assert d.option == '-Wunused-parameter'
|
||||
assert d.disable_option == '-Wno-unused-parameter'
|
|
@ -0,0 +1,9 @@
|
|||
from clang.cindex import Index, File
|
||||
|
||||
def test_file():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c', "")])
|
||||
file = File.from_name(tu, "t.c")
|
||||
assert str(file) == "t.c"
|
||||
assert file.name == "t.c"
|
||||
assert repr(file) == "<File: t.c>"
|
|
@ -0,0 +1,15 @@
|
|||
from clang.cindex import *
|
||||
import os
|
||||
|
||||
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
||||
|
||||
def test_create():
|
||||
index = Index.create()
|
||||
|
||||
# FIXME: test Index.read
|
||||
|
||||
def test_parse():
|
||||
index = Index.create()
|
||||
assert isinstance(index, Index)
|
||||
tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
|
||||
assert isinstance(tu, TranslationUnit)
|
|
@ -0,0 +1,86 @@
|
|||
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
|
||||
|
||||
baseInput="int one;\nint two;\n"
|
||||
|
||||
def assert_location(loc, line, column, offset):
|
||||
assert loc.line == line
|
||||
assert loc.column == column
|
||||
assert loc.offset == offset
|
||||
|
||||
def test_location():
|
||||
tu = get_tu(baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
assert one is not None
|
||||
assert two is not None
|
||||
|
||||
assert_location(one.location,line=1,column=5,offset=4)
|
||||
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')
|
||||
|
||||
assert one is not None
|
||||
assert two is not None
|
||||
|
||||
assert_location(one.location,line=2,column=5,offset=5)
|
||||
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')
|
||||
|
||||
assert_location(one.location,line=1,column=6,offset=5)
|
||||
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')
|
||||
assert one is not None
|
||||
assert one == cursor
|
||||
|
||||
# Ensure locations referring to the same entity are equivalent.
|
||||
location2 = SourceLocation.from_position(tu, file, 1, 5)
|
||||
assert location == location2
|
||||
location3 = SourceLocation.from_position(tu, file, 1, 4)
|
||||
assert location2 != location3
|
||||
|
||||
def test_extent():
|
||||
tu = get_tu(baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
assert_location(one.extent.start,line=1,column=1,offset=0)
|
||||
assert_location(one.extent.end,line=1,column=8,offset=7)
|
||||
assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one"
|
||||
|
||||
assert_location(two.extent.start,line=2,column=1,offset=9)
|
||||
assert_location(two.extent.end,line=2,column=8,offset=16)
|
||||
assert 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)
|
||||
assert range1 == range2
|
||||
|
||||
location3 = SourceLocation.from_position(tu, file, 1, 6)
|
||||
range3 = SourceRange.from_locations(location1, location3)
|
||||
assert range1 != range3
|
|
@ -0,0 +1,84 @@
|
|||
from clang.cindex import *
|
||||
import os
|
||||
|
||||
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
||||
|
||||
def test_spelling():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
index = Index.create()
|
||||
tu = index.parse(path)
|
||||
assert tu.spelling == path
|
||||
|
||||
def test_cursor():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
index = Index.create()
|
||||
tu = index.parse(path)
|
||||
c = tu.cursor
|
||||
assert isinstance(c, Cursor)
|
||||
assert c.kind is CursorKind.TRANSLATION_UNIT
|
||||
|
||||
def test_parse_arguments():
|
||||
path = os.path.join(kInputsDir, 'parse_arguments.c')
|
||||
index = Index.create()
|
||||
tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_reparse_arguments():
|
||||
path = os.path.join(kInputsDir, 'parse_arguments.c')
|
||||
index = Index.create()
|
||||
tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
tu.reparse()
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_unsaved_files():
|
||||
index = Index.create()
|
||||
tu = index.parse('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()]
|
||||
assert spellings[-2] == 'x'
|
||||
assert spellings[-1] == 'y'
|
||||
|
||||
def test_unsaved_files_2():
|
||||
import StringIO
|
||||
index = Index.create()
|
||||
tu = index.parse('fake.c', unsaved_files = [
|
||||
('fake.c', StringIO.StringIO('int x;'))])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-1] == 'x'
|
||||
|
||||
def normpaths_equal(path1, path2):
|
||||
""" Compares two paths for equality after normalizing them with
|
||||
os.path.normpath
|
||||
"""
|
||||
return os.path.normpath(path1) == os.path.normpath(path2)
|
||||
|
||||
def test_includes():
|
||||
def eq(expected, actual):
|
||||
if not actual.is_input_file:
|
||||
return normpaths_equal(expected[0], actual.source.name) and \
|
||||
normpaths_equal(expected[1], actual.include.name)
|
||||
else:
|
||||
return 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)]
|
||||
|
||||
index = Index.create()
|
||||
tu = index.parse(src)
|
||||
for i in zip(inc, tu.get_includes()):
|
||||
assert eq(i[0], i[1])
|
|
@ -0,0 +1,276 @@
|
|||
from clang.cindex import CursorKind
|
||||
from clang.cindex import TypeKind
|
||||
from nose.tools import raises
|
||||
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;
|
||||
};
|
||||
|
||||
"""
|
||||
|
||||
def test_a_struct():
|
||||
tu = get_tu(kInput)
|
||||
|
||||
teststruct = get_cursor(tu, 'teststruct')
|
||||
assert teststruct is not None, "Could not find teststruct."
|
||||
fields = list(teststruct.get_children())
|
||||
assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
|
||||
|
||||
assert fields[0].spelling == 'a'
|
||||
assert not fields[0].type.is_const_qualified()
|
||||
assert fields[0].type.kind == TypeKind.INT
|
||||
assert fields[0].type.get_canonical().kind == TypeKind.INT
|
||||
|
||||
assert fields[1].spelling == 'b'
|
||||
assert not fields[1].type.is_const_qualified()
|
||||
assert fields[1].type.kind == TypeKind.TYPEDEF
|
||||
assert fields[1].type.get_canonical().kind == TypeKind.INT
|
||||
assert fields[1].type.get_declaration().spelling == 'I'
|
||||
|
||||
assert fields[2].spelling == 'c'
|
||||
assert not fields[2].type.is_const_qualified()
|
||||
assert fields[2].type.kind == TypeKind.LONG
|
||||
assert fields[2].type.get_canonical().kind == TypeKind.LONG
|
||||
|
||||
assert fields[3].spelling == 'd'
|
||||
assert not fields[3].type.is_const_qualified()
|
||||
assert fields[3].type.kind == TypeKind.ULONG
|
||||
assert fields[3].type.get_canonical().kind == TypeKind.ULONG
|
||||
|
||||
assert fields[4].spelling == 'e'
|
||||
assert not fields[4].type.is_const_qualified()
|
||||
assert fields[4].type.kind == TypeKind.LONG
|
||||
assert fields[4].type.get_canonical().kind == TypeKind.LONG
|
||||
|
||||
assert fields[5].spelling == 'f'
|
||||
assert fields[5].type.is_const_qualified()
|
||||
assert fields[5].type.kind == TypeKind.INT
|
||||
assert fields[5].type.get_canonical().kind == TypeKind.INT
|
||||
|
||||
assert fields[6].spelling == 'g'
|
||||
assert not fields[6].type.is_const_qualified()
|
||||
assert fields[6].type.kind == TypeKind.POINTER
|
||||
assert fields[6].type.get_pointee().kind == TypeKind.INT
|
||||
|
||||
assert fields[7].spelling == 'h'
|
||||
assert not fields[7].type.is_const_qualified()
|
||||
assert fields[7].type.kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
|
||||
|
||||
constarrayInput="""
|
||||
struct teststruct {
|
||||
void *A[2];
|
||||
};
|
||||
"""
|
||||
def testConstantArray():
|
||||
tu = get_tu(constarrayInput)
|
||||
|
||||
teststruct = get_cursor(tu, 'teststruct')
|
||||
assert teststruct is not None, "Didn't find teststruct??"
|
||||
fields = list(teststruct.get_children())
|
||||
assert fields[0].spelling == 'A'
|
||||
assert fields[0].type.kind == TypeKind.CONSTANTARRAY
|
||||
assert fields[0].type.get_array_element_type() is not None
|
||||
assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
|
||||
assert fields[0].type.get_array_size() == 2
|
||||
|
||||
def test_equal():
|
||||
"""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')
|
||||
|
||||
assert a is not None
|
||||
assert b is not None
|
||||
assert v is not None
|
||||
|
||||
assert a.type == b.type
|
||||
assert a.type != v.type
|
||||
|
||||
assert a.type != None
|
||||
assert a.type != 'foo'
|
||||
|
||||
def test_typekind_spelling():
|
||||
"""Ensure TypeKind.spelling works."""
|
||||
tu = get_tu('int a;')
|
||||
a = get_cursor(tu, 'a')
|
||||
|
||||
assert a is not None
|
||||
assert a.type.kind.spelling == 'Int'
|
||||
|
||||
def test_function_argument_types():
|
||||
"""Ensure that Type.argument_types() works as expected."""
|
||||
tu = get_tu('void f(int, int);')
|
||||
f = get_cursor(tu, 'f')
|
||||
assert f is not None
|
||||
|
||||
args = f.type.argument_types()
|
||||
assert args is not None
|
||||
assert len(args) == 2
|
||||
|
||||
t0 = args[0]
|
||||
assert t0 is not None
|
||||
assert t0.kind == TypeKind.INT
|
||||
|
||||
t1 = args[1]
|
||||
assert t1 is not None
|
||||
assert t1.kind == TypeKind.INT
|
||||
|
||||
args2 = list(args)
|
||||
assert len(args2) == 2
|
||||
assert t0 == args2[0]
|
||||
assert t1 == args2[1]
|
||||
|
||||
@raises(TypeError)
|
||||
def test_argument_types_string_key():
|
||||
"""Ensure that non-int keys raise a TypeError."""
|
||||
tu = get_tu('void f(int, int);')
|
||||
f = get_cursor(tu, 'f')
|
||||
assert f is not None
|
||||
|
||||
args = f.type.argument_types()
|
||||
assert len(args) == 2
|
||||
|
||||
args['foo']
|
||||
|
||||
@raises(IndexError)
|
||||
def test_argument_types_negative_index():
|
||||
"""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()
|
||||
|
||||
args[-1]
|
||||
|
||||
@raises(IndexError)
|
||||
def test_argument_types_overflow_index():
|
||||
"""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()
|
||||
|
||||
args[2]
|
||||
|
||||
@raises(Exception)
|
||||
def test_argument_types_invalid_type():
|
||||
"""Ensure that obtaining argument_types on a Type without them raises."""
|
||||
tu = get_tu('int i;')
|
||||
i = get_cursor(tu, 'i')
|
||||
assert i is not None
|
||||
|
||||
i.type.argument_types()
|
||||
|
||||
def test_is_pod():
|
||||
"""Ensure Type.is_pod() works."""
|
||||
tu = get_tu('int i; void f();')
|
||||
i = get_cursor(tu, 'i')
|
||||
f = get_cursor(tu, 'f')
|
||||
|
||||
assert i is not None
|
||||
assert f is not None
|
||||
|
||||
assert i.type.is_pod()
|
||||
assert not f.type.is_pod()
|
||||
|
||||
def test_function_variadic():
|
||||
"""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')
|
||||
|
||||
assert foo is not None
|
||||
assert bar is not None
|
||||
|
||||
assert isinstance(foo.type.is_function_variadic(), bool)
|
||||
assert foo.type.is_function_variadic()
|
||||
assert not bar.type.is_function_variadic()
|
||||
|
||||
def test_element_type():
|
||||
"""Ensure Type.element_type works."""
|
||||
tu = get_tu('int i[5];')
|
||||
i = get_cursor(tu, 'i')
|
||||
assert i is not None
|
||||
|
||||
assert i.type.kind == TypeKind.CONSTANTARRAY
|
||||
assert i.type.element_type.kind == TypeKind.INT
|
||||
|
||||
@raises(Exception)
|
||||
def test_invalid_element_type():
|
||||
"""Ensure Type.element_type raises if type doesn't have elements."""
|
||||
tu = get_tu('int i;')
|
||||
i = get_cursor(tu, 'i')
|
||||
assert i is not None
|
||||
i.element_type
|
||||
|
||||
def test_element_count():
|
||||
"""Ensure Type.element_count works."""
|
||||
tu = get_tu('int i[5]; int j;')
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert i.type.element_count == 5
|
||||
|
||||
try:
|
||||
j.type.element_count
|
||||
assert False
|
||||
except:
|
||||
assert True
|
||||
|
||||
def test_is_volatile_qualified():
|
||||
"""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')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert isinstance(i.type.is_volatile_qualified(), bool)
|
||||
assert i.type.is_volatile_qualified()
|
||||
assert not j.type.is_volatile_qualified()
|
||||
|
||||
def test_is_restrict_qualified():
|
||||
"""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')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert isinstance(i.type.is_restrict_qualified(), bool)
|
||||
assert i.type.is_restrict_qualified()
|
||||
assert not j.type.is_restrict_qualified()
|
|
@ -0,0 +1,65 @@
|
|||
# This file provides common utility functions for the test suite.
|
||||
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import Index
|
||||
|
||||
def get_tu(source, lang='c', all_warnings=False):
|
||||
"""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.
|
||||
"""
|
||||
name = 't.c'
|
||||
if lang == 'cpp':
|
||||
name = 't.cpp'
|
||||
elif lang == 'objc':
|
||||
name = 't.m'
|
||||
elif lang != 'c':
|
||||
raise Exception('Unknown language: %s' % lang)
|
||||
|
||||
args = []
|
||||
if all_warnings:
|
||||
args = ['-Wall', '-Wextra']
|
||||
|
||||
index = Index.create()
|
||||
tu = index.parse(name, args=args, unsaved_files=[(name, source)])
|
||||
assert tu is not None
|
||||
return tu
|
||||
|
||||
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.
|
||||
"""
|
||||
children = []
|
||||
if isinstance(source, Cursor):
|
||||
children = source.get_children()
|
||||
else:
|
||||
# Assume TU
|
||||
children = source.cursor.get_children()
|
||||
|
||||
for cursor in children:
|
||||
if cursor.spelling == spelling:
|
||||
return cursor
|
||||
|
||||
# Recurse into children.
|
||||
result = get_cursor(cursor, spelling)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
|
||||
__all__ = [
|
||||
'get_cursor',
|
||||
'get_tu',
|
||||
]
|
|
@ -0,0 +1,139 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
|
||||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>AddressSanitizer, a fast memory error detector</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>AddressSanitizer</h1>
|
||||
<ul>
|
||||
<li> <a href="intro">Introduction</a>
|
||||
<li> <a href="howtobuild">How to Build</a>
|
||||
<li> <a href="usage">Usage</a>
|
||||
<ul><li> <a href="has_feature">__has_feature(address_sanitizer)</a></ul>
|
||||
<li> <a href="platforms">Supported Platforms</a>
|
||||
<li> <a href="limitations">Limitations</a>
|
||||
<li> <a href="status">Current Status</a>
|
||||
<li> <a href="moreinfo">More Information</a>
|
||||
</ul>
|
||||
|
||||
<h2 id="intro">Introduction</h2>
|
||||
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:
|
||||
<ul> <li> Out-of-bounds accesses to heap, stack and globals
|
||||
<li> Use-after-free
|
||||
<li> Use-after-return (to some extent)
|
||||
<li> Double-free, invalid free
|
||||
</ul>
|
||||
Typical slowdown introduced by AddressSanitizer is <b>2x</b>.
|
||||
|
||||
<h2 id="howtobuild">How to build</h2>
|
||||
Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
|
||||
Note: CMake build does not work yet.
|
||||
See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
|
||||
|
||||
<h2 id="usage">Usage</h2>
|
||||
Simply compile and link your program with <tt>-faddress-sanitizer</tt> flag. <BR>
|
||||
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
|
||||
To get nicer stack traces in error messages add
|
||||
<tt>-fno-omit-frame-pointer</tt>. <BR>
|
||||
To get perfect stack traces you may need to disable inlining (just use <tt>-O1</tt>) and tail call
|
||||
elimination (</tt>-fno-optimize-sibling-calls</tt>).
|
||||
|
||||
<pre>
|
||||
% cat example_UseAfterFree.cc
|
||||
int main(int argc, char **argv) {
|
||||
int *array = new int[100];
|
||||
delete [] array;
|
||||
return array[argc]; // BOOM
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
% clang -O1 -g -faddress-sanitizer -fno-omit-frame-pointer example_UseAfterFree.cc
|
||||
</pre>
|
||||
|
||||
If a bug is detected, the program will print an error message to stderr and exit with a
|
||||
non-zero exit code.
|
||||
Currently, AddressSanitizer does not symbolize its output, so you may need to use a
|
||||
separate script to symbolize the result offline (this will be fixed in future).
|
||||
<pre>
|
||||
% ./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
|
||||
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
|
||||
</pre>
|
||||
|
||||
<h3 id="has_feature">__has_feature(address_sanitizer)</h3>
|
||||
In some cases one may need to execute different code depending on whether
|
||||
AddressSanitizer is enabled.
|
||||
<a href="LanguageExtensions.html#__has_feature_extension">__has_feature</a>
|
||||
can be used for this purpose.
|
||||
<pre>
|
||||
#if defined(__has_feature) && __has_feature(address_sanitizer)
|
||||
code that runs only under AddressSanitizer
|
||||
#else
|
||||
code that does not run under AddressSanitizer
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
<h2 id="platforms">Supported Platforms</h2>
|
||||
AddressSanitizer is supported on
|
||||
<ul><li>Linux x86_64 (tested on Ubuntu 10.04).
|
||||
<li>MacOS 10.6 i386/x86_64.
|
||||
</ul>
|
||||
Support for Linux i386/ARM and MacOS 10.7 is in progress
|
||||
(it may work, but is not guaranteed too).
|
||||
|
||||
|
||||
<h2 id="limitations">Limitations</h2>
|
||||
<ul>
|
||||
<li> AddressSanitizer uses more real memory than a native run.
|
||||
How much -- depends on the allocations sizes. The smaller the
|
||||
allocations you make the bigger the overhead.
|
||||
<li> On 64-bit platforms AddressSanitizer maps (but not reserves)
|
||||
16+ Terabytes of virtual address space.
|
||||
This means that tools like <tt>ulimit</tt> may not work as usually expected.
|
||||
<li> Static linking is not supported.
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="status">Current Status</h2>
|
||||
AddressSanitizer is fully functional on supported platforms in LLVM head.
|
||||
However, the test suite is not fully integrated yet and we lack the testing
|
||||
process (buildbots).
|
||||
|
||||
<h2 id="moreinfo">More Information</h2>
|
||||
<a href="http://code.google.com/p/address-sanitizer/">http://code.google.com/p/address-sanitizer</a>.
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,260 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Static Analyzer Design Document: Memory Regions</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Static Analyzer Design Document: Memory Regions</h1>
|
||||
|
||||
<h3>Authors</h3>
|
||||
|
||||
<p>Ted Kremenek, <tt>kremenek at apple</tt><br>
|
||||
Zhongxing Xu, <tt>xuzhongzhing at gmail</tt></p>
|
||||
|
||||
<h2 id="intro">Introduction</h2>
|
||||
|
||||
<p>The path-sensitive analysis engine in libAnalysis employs an extensible API
|
||||
for abstractly modeling the memory of an analyzed program. This API employs the
|
||||
concept of "memory regions" to abstractly model chunks of program memory such as
|
||||
program variables and dynamically allocated memory such as those returned from
|
||||
'malloc' and 'alloca'. Regions are hierarchical, with subregions modeling
|
||||
subtyping relationships, field and array offsets into larger chunks of memory,
|
||||
and so on.</p>
|
||||
|
||||
<p>The region API consists of two components:</p>
|
||||
|
||||
<ul> <li>A taxonomy and representation of regions themselves within the analyzer
|
||||
engine. The primary definitions and interfaces are described in <tt><a
|
||||
href="http://clang.llvm.org/doxygen/MemRegion_8h-source.html">MemRegion.h</a></tt>.
|
||||
At the root of the region hierarchy is the class <tt>MemRegion</tt> with
|
||||
specific subclasses refining the region concept for variables, heap allocated
|
||||
memory, and so forth.</li> <li>The modeling of binding of values to regions. For
|
||||
example, modeling the value stored to a local variable <tt>x</tt> consists of
|
||||
recording the binding between the region for <tt>x</tt> (which represents the
|
||||
raw memory associated with <tt>x</tt>) and the value stored to <tt>x</tt>. This
|
||||
binding relationship is captured with the notion of "symbolic
|
||||
stores."</li> </ul>
|
||||
|
||||
<p>Symbolic stores, which can be thought of as representing the relation
|
||||
<tt>regions -> values</tt>, are implemented by subclasses of the
|
||||
<tt>StoreManager</tt> class (<tt><a
|
||||
href="http://clang.llvm.org/doxygen/Store_8h-source.html">Store.h</a></tt>). A
|
||||
particular StoreManager implementation has complete flexibility concerning the
|
||||
following:
|
||||
|
||||
<ul>
|
||||
<li><em>How</em> to model the binding between regions and values</li>
|
||||
<li><em>What</em> bindings are recorded
|
||||
</ul>
|
||||
|
||||
<p>Together, both points allow different StoreManagers to tradeoff between
|
||||
different levels of analysis precision and scalability concerning the reasoning
|
||||
of program memory. Meanwhile, the core path-sensitive engine makes no
|
||||
assumptions about either points, and queries a StoreManager about the bindings
|
||||
to a memory region through a generic interface that all StoreManagers share. If
|
||||
a particular StoreManager cannot reason about the potential bindings of a given
|
||||
memory region (e.g., '<tt>BasicStoreManager</tt>' does not reason about fields
|
||||
of structures) then the StoreManager can simply return 'unknown' (represented by
|
||||
'<tt>UnknownVal</tt>') for a particular region-binding. This separation of
|
||||
concerns not only isolates the core analysis engine from the details of
|
||||
reasoning about program memory but also facilities the option of a client of the
|
||||
path-sensitive engine to easily swap in different StoreManager implementations
|
||||
that internally reason about program memory in very different ways.</p>
|
||||
|
||||
<p>The rest of this document is divided into two parts. We first discuss region
|
||||
taxonomy and the semantics of regions. We then discuss the StoreManager
|
||||
interface, and details of how the currently available StoreManager classes
|
||||
implement region bindings.</p>
|
||||
|
||||
<h2 id="regions">Memory Regions and Region Taxonomy</h2>
|
||||
|
||||
<h3>Pointers</h3>
|
||||
|
||||
<p>Before talking about the memory regions, we would talk about the pointers
|
||||
since memory regions are essentially used to represent pointer values.</p>
|
||||
|
||||
<p>The pointer is a type of values. Pointer values have two semantic aspects.
|
||||
One is its physical value, which is an address or location. The other is the
|
||||
type of the memory object residing in the address.</p>
|
||||
|
||||
<p>Memory regions are designed to abstract these two properties of the pointer.
|
||||
The physical value of a pointer is represented by MemRegion pointers. The rvalue
|
||||
type of the region corresponds to the type of the pointee object.</p>
|
||||
|
||||
<p>One complication is that we could have different view regions on the same
|
||||
memory chunk. They represent the same memory location, but have different
|
||||
abstract location, i.e., MemRegion pointers. Thus we need to canonicalize the
|
||||
abstract locations to get a unique abstract location for one physical
|
||||
location.</p>
|
||||
|
||||
<p>Furthermore, these different view regions may or may not represent memory
|
||||
objects of different types. Some different types are semantically the same,
|
||||
for example, 'struct s' and 'my_type' are the same type.</p>
|
||||
|
||||
<pre>
|
||||
struct s;
|
||||
typedef struct s my_type;
|
||||
</pre>
|
||||
|
||||
<p>But <tt>char</tt> and <tt>int</tt> are not the same type in the code below:</p>
|
||||
|
||||
<pre>
|
||||
void *p;
|
||||
int *q = (int*) p;
|
||||
char *r = (char*) p;
|
||||
</pre>
|
||||
|
||||
<p>Thus we need to canonicalize the MemRegion which is used in binding and
|
||||
retrieving.</p>
|
||||
|
||||
<h3>Regions</h3>
|
||||
<p>Region is the entity used to model pointer values. A Region has the following
|
||||
properties:</p>
|
||||
|
||||
<ul>
|
||||
<li>Kind</li>
|
||||
|
||||
<li>ObjectType: the type of the object residing on the region.</li>
|
||||
|
||||
<li>LocationType: the type of the pointer value that the region corresponds to.
|
||||
Usually this is the pointer to the ObjectType. But sometimes we want to cache
|
||||
this type explicitly, for example, for a CodeTextRegion.</li>
|
||||
|
||||
<li>StartLocation</li>
|
||||
|
||||
<li>EndLocation</li>
|
||||
</ul>
|
||||
|
||||
<h3>Symbolic Regions</h3>
|
||||
|
||||
<p>A symbolic region is a map of the concept of symbolic values into the domain
|
||||
of regions. It is the way that we represent symbolic pointers. Whenever a
|
||||
symbolic pointer value is needed, a symbolic region is created to represent
|
||||
it.</p>
|
||||
|
||||
<p>A symbolic region has no type. It wraps a SymbolData. But sometimes we have
|
||||
type information associated with a symbolic region. For this case, a
|
||||
TypedViewRegion is created to layer the type information on top of the symbolic
|
||||
region. The reason we do not carry type information with the symbolic region is
|
||||
that the symbolic regions can have no type. To be consistent, we don't let them
|
||||
to carry type information.</p>
|
||||
|
||||
<p>Like a symbolic pointer, a symbolic region may be NULL, has unknown extent,
|
||||
and represents a generic chunk of memory.</p>
|
||||
|
||||
<p><em><b>NOTE</b>: We plan not to use loc::SymbolVal in RegionStore and remove it
|
||||
gradually.</em></p>
|
||||
|
||||
<p>Symbolic regions get their rvalue types through the following ways:</p>
|
||||
|
||||
<ul>
|
||||
<li>Through the parameter or global variable that points to it, e.g.:
|
||||
<pre>
|
||||
void f(struct s* p) {
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>The symbolic region pointed to by <tt>p</tt> has type <tt>struct
|
||||
s</tt>.</p></li>
|
||||
|
||||
<li>Through explicit or implicit casts, e.g.:
|
||||
<pre>
|
||||
void f(void* p) {
|
||||
struct s* q = (struct s*) p;
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>We attach the type information to the symbolic region lazily. For the first
|
||||
case above, we create the <tt>TypedViewRegion</tt> only when the pointer is
|
||||
actually used to access the pointee memory object, that is when the element or
|
||||
field region is created. For the cast case, the <tt>TypedViewRegion</tt> is
|
||||
created when visiting the <tt>CastExpr</tt>.</p>
|
||||
|
||||
<p>The reason for doing lazy typing is that symbolic regions are sometimes only
|
||||
used to do location comparison.</p>
|
||||
|
||||
<h3>Pointer Casts</h3>
|
||||
|
||||
<p>Pointer casts allow people to impose different 'views' onto a chunk of
|
||||
memory.</p>
|
||||
|
||||
<p>Usually we have two kinds of casts. One kind of casts cast down with in the
|
||||
type hierarchy. It imposes more specific views onto more generic memory regions.
|
||||
The other kind of casts cast up with in the type hierarchy. It strips away more
|
||||
specific views on top of the more generic memory regions.</p>
|
||||
|
||||
<p>We simulate the down casts by layering another <tt>TypedViewRegion</tt> on
|
||||
top of the original region. We simulate the up casts by striping away the top
|
||||
<tt>TypedViewRegion</tt>. Down casts is usually simple. For up casts, if the
|
||||
there is no <tt>TypedViewRegion</tt> to be stripped, we return the original
|
||||
region. If the underlying region is of the different type than the cast-to type,
|
||||
we flag an error state.</p>
|
||||
|
||||
<p>For toll-free bridging casts, we return the original region.</p>
|
||||
|
||||
<p>We can set up a partial order for pointer types, with the most general type
|
||||
<tt>void*</tt> at the top. The partial order forms a tree with <tt>void*</tt> as
|
||||
its root node.</p>
|
||||
|
||||
<p>Every <tt>MemRegion</tt> has a root position in the type tree. For example,
|
||||
the pointee region of <tt>void *p</tt> has its root position at the root node of
|
||||
the tree. <tt>VarRegion</tt> of <tt>int x</tt> has its root position at the 'int
|
||||
type' node.</p>
|
||||
|
||||
<p><tt>TypedViewRegion</tt> is used to move the region down or up in the tree.
|
||||
Moving down in the tree adds a <tt>TypedViewRegion</tt>. Moving up in the tree
|
||||
removes a <Tt>TypedViewRegion</tt>.</p>
|
||||
|
||||
<p>Do we want to allow moving up beyond the root position? This happens
|
||||
when:</p> <pre> int x; void *p = &x; </pre>
|
||||
|
||||
<p>The region of <tt>x</tt> has its root position at 'int*' node. the cast to
|
||||
void* moves that region up to the 'void*' node. I propose to not allow such
|
||||
casts, and assign the region of <tt>x</tt> for <tt>p</tt>.</p>
|
||||
|
||||
<p>Another non-ideal case is that people might cast to a non-generic pointer
|
||||
from another non-generic pointer instead of first casting it back to the generic
|
||||
pointer. Direct handling of this case would result in multiple layers of
|
||||
TypedViewRegions. This enforces an incorrect semantic view to the region,
|
||||
because we can only have one typed view on a region at a time. To avoid this
|
||||
inconsistency, before casting the region, we strip the TypedViewRegion, then do
|
||||
the cast. In summary, we only allow one layer of TypedViewRegion.</p>
|
||||
|
||||
<h3>Region Bindings</h3>
|
||||
|
||||
<p>The following region kinds are boundable: VarRegion, CompoundLiteralRegion,
|
||||
StringRegion, ElementRegion, FieldRegion, and ObjCIvarRegion.</p>
|
||||
|
||||
<p>When binding regions, we perform canonicalization on element regions and field
|
||||
regions. This is because we can have different views on the same region, some
|
||||
of which are essentially the same view with different sugar type names.</p>
|
||||
|
||||
<p>To canonicalize a region, we get the canonical types for all TypedViewRegions
|
||||
along the way up to the root region, and make new TypedViewRegions with those
|
||||
canonical types.</p>
|
||||
|
||||
<p>For Objective-C and C++, perhaps another canonicalization rule should be
|
||||
added: for FieldRegion, the least derived class that has the field is used as
|
||||
the type of the super region of the FieldRegion.</p>
|
||||
|
||||
<p>All bindings and retrievings are done on the canonicalized regions.</p>
|
||||
|
||||
<p>Canonicalization is transparent outside the region store manager, and more
|
||||
specifically, unaware outside the Bind() and Retrieve() method. We don't need to
|
||||
consider region canonicalization when doing pointer cast.</p>
|
||||
|
||||
<h3>Constraint Manager</h3>
|
||||
|
||||
<p>The constraint manager reasons about the abstract location of memory objects.
|
||||
We can have different views on a region, but none of these views changes the
|
||||
location of that object. Thus we should get the same abstract location for those
|
||||
regions.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,669 @@
|
|||
Block Implementation Specification
|
||||
|
||||
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.
|
||||
|
||||
0. 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/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
|
||||
|
||||
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.
|
||||
|
||||
1. 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:
|
||||
|
||||
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:
|
||||
|
||||
enum {
|
||||
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.
|
||||
|
||||
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) static descriptor structure is declared and initialized as follows:
|
||||
1a) 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.
|
||||
1b) the size field is set to the size of the following Block literal structure.
|
||||
1c) 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:
|
||||
2a) 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.
|
||||
2) 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
|
||||
^ { printf("hello world\n"); }
|
||||
would cause to be created on a 32-bit system:
|
||||
|
||||
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 appeared
|
||||
|
||||
struct __block_literal_1 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<29), <uninitialized>,
|
||||
__block_invoke_1,
|
||||
&__block_descriptor_1
|
||||
};
|
||||
|
||||
Blocks import 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 used as the initial value of a global or static local variable it is initialized as follows:
|
||||
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.
|
||||
|
||||
|
||||
2. 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.
|
||||
|
||||
2.1 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.
|
||||
|
||||
int x = 10;
|
||||
void (^vv)(void) = ^{ printf("x is %d\n", x); }
|
||||
x = 11;
|
||||
vv();
|
||||
|
||||
would be compiled
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
2.2 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 Section 5.0 Runtime Helper Functions.
|
||||
|
||||
An example:
|
||||
|
||||
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 it is used
|
||||
|
||||
struct __block_literal_4 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<25)|(1<<29), <uninitialized>
|
||||
__block_invoke_4,
|
||||
& __block_descriptor_4
|
||||
existingBlock,
|
||||
};
|
||||
|
||||
2.2.1 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 xyzzy in the following
|
||||
|
||||
struct Opaque *__attribute__((NSObject)) objectPointer = ...;
|
||||
...
|
||||
void (^xyzzy)(void) = ^{ CFPrint(objectPointer); };
|
||||
|
||||
would have helper functions
|
||||
|
||||
void __block_copy_xyzzy(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
|
||||
_Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
|
||||
}
|
||||
|
||||
void __block_dispose_xyzzy(struct __block_literal_5 *src) {
|
||||
_Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
|
||||
}
|
||||
|
||||
generated.
|
||||
|
||||
|
||||
2.3 Imported __block marked variables.
|
||||
|
||||
2.3.1 Layout of __block marked variables
|
||||
|
||||
The compiler must embed variables that are marked __block in a specialized structure of the form:
|
||||
|
||||
struct _block_byref_xxxx {
|
||||
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:
|
||||
|
||||
struct _block_byref_xxxx {
|
||||
void *isa;
|
||||
struct _block_byref_xxxx *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
|
||||
|
||||
2.3.2 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:
|
||||
|
||||
int __block i = 10;
|
||||
i = 11;
|
||||
|
||||
would be rewritten to be:
|
||||
|
||||
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:
|
||||
|
||||
__block void (voidBlock)(void) = blockA;
|
||||
voidBlock = blockB;
|
||||
|
||||
would translate into
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
|
||||
2.3.3 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:
|
||||
|
||||
int __block i = 2;
|
||||
functioncall(^{ i = 10; });
|
||||
|
||||
would translate to
|
||||
|
||||
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
|
||||
|
||||
struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
|
||||
struct __block_literal_5 _block_literal = {
|
||||
&_NSConcreteStackBlock,
|
||||
(1<<25)|(1<<29), <uninitialized>,
|
||||
__block_invoke_5,
|
||||
&__block_descriptor_5,
|
||||
2,
|
||||
};
|
||||
|
||||
2.3.4 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.
|
||||
|
||||
2.3.5 __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:
|
||||
|
||||
_Block_object_dispose(&_block_byref_xxx, BLOCK_FIELD_IS_BYREF);
|
||||
|
||||
|
||||
2.3.6 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.
|
||||
|
||||
3. Objective C Extensions to Blocks
|
||||
|
||||
3.1 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.
|
||||
|
||||
|
||||
3.2 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.
|
||||
|
||||
3.3 __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:
|
||||
objc_read_weak(&block->byref_i->forwarding->i)
|
||||
|
||||
The __weak variable is stored in a _block_byref_xxxx structure and the Block has copy and dispose helpers for this structure that call:
|
||||
_Block_object_assign(&dest->_block_byref_i, src-> _block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
|
||||
and
|
||||
_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:
|
||||
_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
|
||||
_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:
|
||||
|
||||
|
||||
__block __weak id obj = <initialization expression>;
|
||||
functioncall(^{ [obj somemessage]; });
|
||||
|
||||
would translate to
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
struct _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> )};
|
||||
|
||||
struct __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));
|
||||
|
||||
|
||||
4.0 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:
|
||||
|
||||
{
|
||||
FOO foo;
|
||||
void (^block)(void) = ^{ printf("%d\n", foo.value()); };
|
||||
}
|
||||
|
||||
The compiler would synthesize
|
||||
|
||||
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:
|
||||
{
|
||||
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,
|
||||
|
||||
__block FOO blockStorageFoo;
|
||||
|
||||
requires the normal constructor for the embedded blockStorageFoo object
|
||||
|
||||
FOO_ctor(& _block_byref_blockStorageFoo->blockStorageFoo);
|
||||
|
||||
and at scope termination the destructor:
|
||||
|
||||
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:
|
||||
|
||||
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.
|
||||
|
||||
5.0 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
|
||||
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
|
||||
in the copy helper and
|
||||
_Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
|
||||
in the dispose helper where
|
||||
<appropo> is
|
||||
|
||||
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 CTORs/DTORs 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_<appropo> field within the block_byref copy/dispose helper calls.
|
||||
|
||||
The prototypes, and summary, of the helper functions are
|
||||
|
||||
/* 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);
|
|
@ -0,0 +1,165 @@
|
|||
Language Specification for Blocks
|
||||
|
||||
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
|
||||
|
||||
Copyright 2008-2009 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.
|
||||
|
||||
The Block Type
|
||||
|
||||
A new derived type is introduced to C and, by extension, Objective-C, C++, and Objective-C++. Like function types, the 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 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 variable with Block type is declared using function pointer style notation substituting ^ for *. The following are valid Block variable declarations:
|
||||
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 literal expression produces a reference to a Block. It is introduced by the use of the ^ token as a unary operator.
|
||||
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:
|
||||
^ 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:
|
||||
^ ( void ) { printf("hello world\n"); }
|
||||
|
||||
...and:
|
||||
^ { 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:
|
||||
typedef int (*pointerToFunctionThatReturnsIntWithCharArg)(char);
|
||||
pointerToFunctionThatReturnsIntWithCharArg functionPointer;
|
||||
|
||||
^ pointerToFunctionThatReturnsIntWithCharArg (float x) { return functionPointer; }
|
||||
|
||||
...and:
|
||||
^ int ((*)(float x))(char) { return functionPointer; }
|
||||
|
||||
...are equivalent expressions, as is:
|
||||
|
||||
^(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 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 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:
|
||||
int (^x)(char);
|
||||
void (^z)(void);
|
||||
int (^(*y))(char) = &x;
|
||||
|
||||
...the following are all legal Block invocations:
|
||||
x('a');
|
||||
(*y)('a');
|
||||
(true ? x : *y)('a')
|
||||
|
||||
|
||||
The Copy and Release Operations
|
||||
|
||||
The compiler and runtime provide copy and 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, 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_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.
|
||||
|
||||
For example, given class Foo with member function fighter(void):
|
||||
Foo foo;
|
||||
Foo &fooRef = foo;
|
||||
Foo *fooPtr = &foo;
|
||||
|
||||
...a Block that used foo would import the variables as const variations:
|
||||
const Foo block_foo = foo; // const copy constructor
|
||||
const Foo &block_fooRef = fooRef;
|
||||
Foo *const block_fooPtr = fooPtr;
|
||||
|
||||
Stack-local objects are copied into a Block via a copy const constructor. If no such constructor exists, it is considered an error to reference such objects from within the Block compound statements. A destructor is run as control leaves the compound statement that contains the Block literal expression.
|
||||
|
||||
If a Block originates on the stack, a const copy constructor of the stack-based Block const copy is performed when a Block_copy operation is called; when the last Block_release (or subsequently GC) occurs, a destructor is run on the heap copy.
|
||||
|
||||
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, a normal copy constructor is used to initialize the heap-based version from the original stack version. The destructor for a const copied object is run at the normal end of scope. The destructor for any initial stack based version is also called at normal end of scope.
|
||||
|
||||
Within a member function, access to member functions and variables is done via an implicit const copy of a this pointer.
|
||||
|
||||
Member variables that are Blocks may not be overloaded by the types of their arguments.
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 71 KiB |
|
@ -0,0 +1,523 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Driver Manual</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Driver Design & Internals</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#features">Features and Goals</a>
|
||||
<ul>
|
||||
<li><a href="#gcccompat">GCC Compatibility</a></li>
|
||||
<li><a href="#components">Flexible</a></li>
|
||||
<li><a href="#performance">Low Overhead</a></li>
|
||||
<li><a href="#simple">Simple</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#design">Design</a>
|
||||
<ul>
|
||||
<li><a href="#int_intro">Internals Introduction</a></li>
|
||||
<li><a href="#int_overview">Design Overview</a></li>
|
||||
<li><a href="#int_notes">Additional Notes</a>
|
||||
<ul>
|
||||
<li><a href="#int_compilation">The Compilation Object</a></li>
|
||||
<li><a href="#int_unified_parsing">Unified Parsing & Pipelining</a></li>
|
||||
<li><a href="#int_toolchain_translation">ToolChain Argument Translation</a></li>
|
||||
<li><a href="#int_unused_warnings">Unused Argument Warnings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This document describes the Clang driver. The purpose of this
|
||||
document is to describe both the motivation and design goals
|
||||
for the driver, as well as details of the internal
|
||||
implementation.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="features">Features and Goals</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The Clang driver is intended to be a production quality
|
||||
compiler driver providing access to the Clang compiler and
|
||||
tools, with a command line interface which is compatible with
|
||||
the gcc driver.</p>
|
||||
|
||||
<p>Although the driver is part of and driven by the Clang
|
||||
project, it is logically a separate tool which shares many of
|
||||
the same goals as Clang:</p>
|
||||
|
||||
<p><b>Features</b>:</p>
|
||||
<ul>
|
||||
<li><a href="#gcccompat">GCC Compatibility</a></li>
|
||||
<li><a href="#components">Flexible</a></li>
|
||||
<li><a href="#performance">Low Overhead</a></li>
|
||||
<li><a href="#simple">Simple</a></li>
|
||||
</ul>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="gcccompat">GCC Compatibility</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The number one goal of the driver is to ease the adoption of
|
||||
Clang by allowing users to drop Clang into a build system
|
||||
which was designed to call GCC. Although this makes the driver
|
||||
much more complicated than might otherwise be necessary, we
|
||||
decided that being very compatible with the gcc command line
|
||||
interface was worth it in order to allow users to quickly test
|
||||
clang on their projects.</p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="components">Flexible</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The driver was designed to be flexible and easily accommodate
|
||||
new uses as we grow the clang and LLVM infrastructure. As one
|
||||
example, the driver can easily support the introduction of
|
||||
tools which have an integrated assembler; something we hope to
|
||||
add to LLVM in the future.</p>
|
||||
|
||||
<p>Similarly, most of the driver functionality is kept in a
|
||||
library which can be used to build other tools which want to
|
||||
implement or accept a gcc like interface. </p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="performance">Low Overhead</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The driver should have as little overhead as possible. In
|
||||
practice, we found that the gcc driver by itself incurred a
|
||||
small but meaningful overhead when compiling many small
|
||||
files. The driver doesn't do much work compared to a
|
||||
compilation, but we have tried to keep it as efficient as
|
||||
possible by following a few simple principles:</p>
|
||||
<ul>
|
||||
<li>Avoid memory allocation and string copying when
|
||||
possible.</li>
|
||||
|
||||
<li>Don't parse arguments more than once.</li>
|
||||
|
||||
<li>Provide a few simple interfaces for efficiently searching
|
||||
arguments.</li>
|
||||
</ul>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3 id="simple">Simple</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>Finally, the driver was designed to be "as simple as
|
||||
possible", given the other goals. Notably, trying to be
|
||||
completely compatible with the gcc driver adds a significant
|
||||
amount of complexity. However, the design of the driver
|
||||
attempts to mitigate this complexity by dividing the process
|
||||
into a number of independent stages instead of a single
|
||||
monolithic task.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="design">Internal Design and Implementation</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<ul>
|
||||
<li><a href="#int_intro">Internals Introduction</a></li>
|
||||
<li><a href="#int_overview">Design Overview</a></li>
|
||||
<li><a href="#int_notes">Additional Notes</a></li>
|
||||
<li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
|
||||
</ul>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_intro">Internals Introduction</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>In order to satisfy the stated goals, the driver was designed
|
||||
to completely subsume the functionality of the gcc executable;
|
||||
that is, the driver should not need to delegate to gcc to
|
||||
perform subtasks. On Darwin, this implies that the Clang
|
||||
driver also subsumes the gcc driver-driver, which is used to
|
||||
implement support for building universal images (binaries and
|
||||
object files). This also implies that the driver should be
|
||||
able to call the language specific compilers (e.g. cc1)
|
||||
directly, which means that it must have enough information to
|
||||
forward command line arguments to child processes
|
||||
correctly.</p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_overview">Design Overview</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The diagram below shows the significant components of the
|
||||
driver architecture and how they relate to one another. The
|
||||
orange components represent concrete data structures built by
|
||||
the driver, the green components indicate conceptually
|
||||
distinct stages which manipulate these data structures, and
|
||||
the blue components are important helper classes. </p>
|
||||
|
||||
<div style="text-align:center">
|
||||
<a href="DriverArchitecture.png">
|
||||
<img width=400 src="DriverArchitecture.png"
|
||||
alt="Driver Architecture Diagram">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_stages">Driver Stages</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The driver functionality is conceptually divided into five stages:</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
<b>Parse: Option Parsing</b>
|
||||
|
||||
<p>The command line argument strings are decomposed into
|
||||
arguments (<tt>Arg</tt> instances). The driver expects to
|
||||
understand all available options, although there is some
|
||||
facility for just passing certain classes of options
|
||||
through (like <tt>-Wl,</tt>).</p>
|
||||
|
||||
<p>Each argument corresponds to exactly one
|
||||
abstract <tt>Option</tt> definition, which describes how
|
||||
the option is parsed along with some additional
|
||||
metadata. The Arg instances themselves are lightweight and
|
||||
merely contain enough information for clients to determine
|
||||
which option they correspond to and their values (if they
|
||||
have additional parameters).</p>
|
||||
|
||||
<p>For example, a command line like "-Ifoo -I foo" would
|
||||
parse to two Arg instances (a JoinedArg and a SeparateArg
|
||||
instance), but each would refer to the same Option.</p>
|
||||
|
||||
<p>Options are lazily created in order to avoid populating
|
||||
all Option classes when the driver is loaded. Most of the
|
||||
driver code only needs to deal with options by their
|
||||
unique ID (e.g., <tt>options::OPT_I</tt>),</p>
|
||||
|
||||
<p>Arg instances themselves do not generally store the
|
||||
values of parameters. In many cases, this would
|
||||
simply result in creating unnecessary string
|
||||
copies. Instead, Arg instances are always embedded inside
|
||||
an ArgList structure, which contains the original vector
|
||||
of argument strings. Each Arg itself only needs to contain
|
||||
an index into this vector instead of storing its values
|
||||
directly.</p>
|
||||
|
||||
<p>The clang driver can dump the results of this
|
||||
stage using the <tt>-ccc-print-options</tt> flag (which
|
||||
must precede any actual command line arguments). For
|
||||
example:</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-options -Xarch_i386 -fomit-frame-pointer -Wa,-fast -Ifoo -I foo t.c</b>
|
||||
Option 0 - Name: "-Xarch_", Values: {"i386", "-fomit-frame-pointer"}
|
||||
Option 1 - Name: "-Wa,", Values: {"-fast"}
|
||||
Option 2 - Name: "-I", Values: {"foo"}
|
||||
Option 3 - Name: "-I", Values: {"foo"}
|
||||
Option 4 - Name: "<input>", Values: {"t.c"}
|
||||
</pre>
|
||||
|
||||
<p>After this stage is complete the command line should be
|
||||
broken down into well defined option objects with their
|
||||
appropriate parameters. Subsequent stages should rarely,
|
||||
if ever, need to do any string processing.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Pipeline: Compilation Job Construction</b>
|
||||
|
||||
<p>Once the arguments are parsed, the tree of subprocess
|
||||
jobs needed for the desired compilation sequence are
|
||||
constructed. This involves determining the input files and
|
||||
their types, what work is to be done on them (preprocess,
|
||||
compile, assemble, link, etc.), and constructing a list of
|
||||
Action instances for each task. The result is a list of
|
||||
one or more top-level actions, each of which generally
|
||||
corresponds to a single output (for example, an object or
|
||||
linked executable).</p>
|
||||
|
||||
<p>The majority of Actions correspond to actual tasks,
|
||||
however there are two special Actions. The first is
|
||||
InputAction, which simply serves to adapt an input
|
||||
argument for use as an input to other Actions. The second
|
||||
is BindArchAction, which conceptually alters the
|
||||
architecture to be used for all of its input Actions.</p>
|
||||
|
||||
<p>The clang driver can dump the results of this
|
||||
stage using the <tt>-ccc-print-phases</tt> flag. For
|
||||
example:</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-phases -x c t.c -x assembler t.s</b>
|
||||
0: input, "t.c", c
|
||||
1: preprocessor, {0}, cpp-output
|
||||
2: compiler, {1}, assembler
|
||||
3: assembler, {2}, object
|
||||
4: input, "t.s", assembler
|
||||
5: assembler, {4}, object
|
||||
6: linker, {3, 5}, image
|
||||
</pre>
|
||||
<p>Here the driver is constructing seven distinct actions,
|
||||
four to compile the "t.c" input into an object file, two to
|
||||
assemble the "t.s" input, and one to link them together.</p>
|
||||
|
||||
<p>A rather different compilation pipeline is shown here; in
|
||||
this example there are two top level actions to compile
|
||||
the input files into two separate object files, where each
|
||||
object file is built using <tt>lipo</tt> to merge results
|
||||
built for two separate architectures.</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-phases -c -arch i386 -arch x86_64 t0.c t1.c</b>
|
||||
0: input, "t0.c", c
|
||||
1: preprocessor, {0}, cpp-output
|
||||
2: compiler, {1}, assembler
|
||||
3: assembler, {2}, object
|
||||
4: bind-arch, "i386", {3}, object
|
||||
5: bind-arch, "x86_64", {3}, object
|
||||
6: lipo, {4, 5}, object
|
||||
7: input, "t1.c", c
|
||||
8: preprocessor, {7}, cpp-output
|
||||
9: compiler, {8}, assembler
|
||||
10: assembler, {9}, object
|
||||
11: bind-arch, "i386", {10}, object
|
||||
12: bind-arch, "x86_64", {10}, object
|
||||
13: lipo, {11, 12}, object
|
||||
</pre>
|
||||
|
||||
<p>After this stage is complete the compilation process is
|
||||
divided into a simple set of actions which need to be
|
||||
performed to produce intermediate or final outputs (in
|
||||
some cases, like <tt>-fsyntax-only</tt>, there is no
|
||||
"real" final output). Phases are well known compilation
|
||||
steps, such as "preprocess", "compile", "assemble",
|
||||
"link", etc.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Bind: Tool & Filename Selection</b>
|
||||
|
||||
<p>This stage (in conjunction with the Translate stage)
|
||||
turns the tree of Actions into a list of actual subprocess
|
||||
to run. Conceptually, the driver performs a top down
|
||||
matching to assign Action(s) to Tools. The ToolChain is
|
||||
responsible for selecting the tool to perform a particular
|
||||
action; once selected the driver interacts with the tool
|
||||
to see if it can match additional actions (for example, by
|
||||
having an integrated preprocessor).
|
||||
|
||||
<p>Once Tools have been selected for all actions, the driver
|
||||
determines how the tools should be connected (for example,
|
||||
using an inprocess module, pipes, temporary files, or user
|
||||
provided filenames). If an output file is required, the
|
||||
driver also computes the appropriate file name (the suffix
|
||||
and file location depend on the input types and options
|
||||
such as <tt>-save-temps</tt>).
|
||||
|
||||
<p>The driver interacts with a ToolChain to perform the Tool
|
||||
bindings. Each ToolChain contains information about all
|
||||
the tools needed for compilation for a particular
|
||||
architecture, platform, and operating system. A single
|
||||
driver invocation may query multiple ToolChains during one
|
||||
compilation in order to interact with tools for separate
|
||||
architectures.</p>
|
||||
|
||||
<p>The results of this stage are not computed directly, but
|
||||
the driver can print the results via
|
||||
the <tt>-ccc-print-bindings</tt> option. For example:</p>
|
||||
<pre>
|
||||
$ <b>clang -ccc-print-bindings -arch i386 -arch ppc t0.c</b>
|
||||
# "i386-apple-darwin9" - "clang", inputs: ["t0.c"], output: "/tmp/cc-Sn4RKF.s"
|
||||
# "i386-apple-darwin9" - "darwin::Assemble", inputs: ["/tmp/cc-Sn4RKF.s"], output: "/tmp/cc-gvSnbS.o"
|
||||
# "i386-apple-darwin9" - "darwin::Link", inputs: ["/tmp/cc-gvSnbS.o"], output: "/tmp/cc-jgHQxi.out"
|
||||
# "ppc-apple-darwin9" - "gcc::Compile", inputs: ["t0.c"], output: "/tmp/cc-Q0bTox.s"
|
||||
# "ppc-apple-darwin9" - "gcc::Assemble", inputs: ["/tmp/cc-Q0bTox.s"], output: "/tmp/cc-WCdicw.o"
|
||||
# "ppc-apple-darwin9" - "gcc::Link", inputs: ["/tmp/cc-WCdicw.o"], output: "/tmp/cc-HHBEBh.out"
|
||||
# "i386-apple-darwin9" - "darwin::Lipo", inputs: ["/tmp/cc-jgHQxi.out", "/tmp/cc-HHBEBh.out"], output: "a.out"
|
||||
</pre>
|
||||
|
||||
<p>This shows the tool chain, tool, inputs and outputs which
|
||||
have been bound for this compilation sequence. Here clang
|
||||
is being used to compile t0.c on the i386 architecture and
|
||||
darwin specific versions of the tools are being used to
|
||||
assemble and link the result, but generic gcc versions of
|
||||
the tools are being used on PowerPC.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Translate: Tool Specific Argument Translation</b>
|
||||
|
||||
<p>Once a Tool has been selected to perform a particular
|
||||
Action, the Tool must construct concrete Jobs which will be
|
||||
executed during compilation. The main work is in translating
|
||||
from the gcc style command line options to whatever options
|
||||
the subprocess expects.</p>
|
||||
|
||||
<p>Some tools, such as the assembler, only interact with a
|
||||
handful of arguments and just determine the path of the
|
||||
executable to call and pass on their input and output
|
||||
arguments. Others, like the compiler or the linker, may
|
||||
translate a large number of arguments in addition.</p>
|
||||
|
||||
<p>The ArgList class provides a number of simple helper
|
||||
methods to assist with translating arguments; for example,
|
||||
to pass on only the last of arguments corresponding to some
|
||||
option, or all arguments for an option.</p>
|
||||
|
||||
<p>The result of this stage is a list of Jobs (executable
|
||||
paths and argument strings) to execute.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Execute</b>
|
||||
<p>Finally, the compilation pipeline is executed. This is
|
||||
mostly straightforward, although there is some interaction
|
||||
with options
|
||||
like <tt>-pipe</tt>, <tt>-pass-exit-codes</tt>
|
||||
and <tt>-time</tt>.</p>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_notes">Additional Notes</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<h4 id="int_compilation">The Compilation Object</h4>
|
||||
|
||||
<p>The driver constructs a Compilation object for each set of
|
||||
command line arguments. The Driver itself is intended to be
|
||||
invariant during construction of a Compilation; an IDE should be
|
||||
able to construct a single long lived driver instance to use
|
||||
for an entire build, for example.</p>
|
||||
|
||||
<p>The Compilation object holds information that is particular
|
||||
to each compilation sequence. For example, the list of used
|
||||
temporary files (which must be removed once compilation is
|
||||
finished) and result files (which should be removed if
|
||||
compilation fails).</p>
|
||||
|
||||
<h4 id="int_unified_parsing">Unified Parsing & Pipelining</h4>
|
||||
|
||||
<p>Parsing and pipelining both occur without reference to a
|
||||
Compilation instance. This is by design; the driver expects that
|
||||
both of these phases are platform neutral, with a few very well
|
||||
defined exceptions such as whether the platform uses a driver
|
||||
driver.</p>
|
||||
|
||||
<h4 id="int_toolchain_translation">ToolChain Argument Translation</h4>
|
||||
|
||||
<p>In order to match gcc very closely, the clang driver
|
||||
currently allows tool chains to perform their own translation of
|
||||
the argument list (into a new ArgList data structure). Although
|
||||
this allows the clang driver to match gcc easily, it also makes
|
||||
the driver operation much harder to understand (since the Tools
|
||||
stop seeing some arguments the user provided, and see new ones
|
||||
instead).</p>
|
||||
|
||||
<p>For example, on Darwin <tt>-gfull</tt> gets translated into two
|
||||
separate arguments, <tt>-g</tt>
|
||||
and <tt>-fno-eliminate-unused-debug-symbols</tt>. Trying to write Tool
|
||||
logic to do something with <tt>-gfull</tt> will not work, because Tool
|
||||
argument translation is done after the arguments have been
|
||||
translated.</p>
|
||||
|
||||
<p>A long term goal is to remove this tool chain specific
|
||||
translation, and instead force each tool to change its own logic
|
||||
to do the right thing on the untranslated original arguments.</p>
|
||||
|
||||
<h4 id="int_unused_warnings">Unused Argument Warnings</h4>
|
||||
<p>The driver operates by parsing all arguments but giving Tools
|
||||
the opportunity to choose which arguments to pass on. One
|
||||
downside of this infrastructure is that if the user misspells
|
||||
some option, or is confused about which options to use, some
|
||||
command line arguments the user really cared about may go
|
||||
unused. This problem is particularly important when using
|
||||
clang as a compiler, since the clang compiler does not support
|
||||
anywhere near all the options that gcc does, and we want to make
|
||||
sure users know which ones are being used.</p>
|
||||
|
||||
<p>To support this, the driver maintains a bit associated with
|
||||
each argument of whether it has been used (at all) during the
|
||||
compilation. This bit usually doesn't need to be set by hand,
|
||||
as the key ArgList accessors will set it automatically.</p>
|
||||
|
||||
<p>When a compilation is successful (there are no errors), the
|
||||
driver checks the bit and emits an "unused argument" warning for
|
||||
any arguments which were never accessed. This is conservative
|
||||
(the argument may not have been used to do what the user wanted)
|
||||
but still catches the most obvious cases.</p>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_gcc_concepts">Relation to GCC Driver Concepts</a></h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>For those familiar with the gcc driver, this section provides
|
||||
a brief overview of how things from the gcc driver map to the
|
||||
clang driver.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>Driver Driver</b>
|
||||
<p>The driver driver is fully integrated into the clang
|
||||
driver. The driver simply constructs additional Actions to
|
||||
bind the architecture during the <i>Pipeline</i>
|
||||
phase. The tool chain specific argument translation is
|
||||
responsible for handling <tt>-Xarch_</tt>.</p>
|
||||
|
||||
<p>The one caveat is that this approach
|
||||
requires <tt>-Xarch_</tt> not be used to alter the
|
||||
compilation itself (for example, one cannot
|
||||
provide <tt>-S</tt> as an <tt>-Xarch_</tt> argument). The
|
||||
driver attempts to reject such invocations, and overall
|
||||
there isn't a good reason to abuse <tt>-Xarch_</tt> to
|
||||
that end in practice.</p>
|
||||
|
||||
<p>The upside is that the clang driver is more efficient and
|
||||
does little extra work to support universal builds. It also
|
||||
provides better error reporting and UI consistency.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Specs</b>
|
||||
<p>The clang driver has no direct correspondent for
|
||||
"specs". The majority of the functionality that is
|
||||
embedded in specs is in the Tool specific argument
|
||||
translation routines. The parts of specs which control the
|
||||
compilation pipeline are generally part of
|
||||
the <i>Pipeline</i> stage.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<b>Toolchains</b>
|
||||
<p>The gcc driver has no direct understanding of tool
|
||||
chains. Each gcc binary roughly corresponds to the
|
||||
information which is embedded inside a single
|
||||
ToolChain.</p>
|
||||
|
||||
<p>The clang driver is intended to be portable and support
|
||||
complex compilation environments. All platform and tool
|
||||
chain specific code should be protected behind either
|
||||
abstract or well defined interfaces (such as whether the
|
||||
platform supports use as a driver driver).</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,97 @@
|
|||
##===- docs/Makefile ---------------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ..
|
||||
DIRS := tools
|
||||
|
||||
ifdef BUILD_FOR_WEBSITE
|
||||
PROJ_OBJ_DIR = .
|
||||
DOXYGEN = doxygen
|
||||
|
||||
$(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
|
||||
cat $< | sed \
|
||||
-e 's/@abs_srcdir@/./g' \
|
||||
-e 's/@DOT@/dot/g' \
|
||||
-e 's/@PACKAGE_VERSION@/mainline/' \
|
||||
-e 's/@abs_builddir@/./g' > $@
|
||||
endif
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
HTML := $(wildcard $(PROJ_SRC_DIR)/*.html) \
|
||||
$(wildcard $(PROJ_SRC_DIR)/*.css)
|
||||
#IMAGES := $(wildcard $(PROJ_SRC_DIR)/img/*.*)
|
||||
DOXYFILES := doxygen.cfg.in doxygen.css doxygen.footer doxygen.header \
|
||||
doxygen.intro
|
||||
EXTRA_DIST := $(HTML) $(DOXYFILES) llvm.css CommandGuide img
|
||||
|
||||
.PHONY: install-html install-doxygen doxygen generated
|
||||
|
||||
install_targets :=
|
||||
ifndef ONLY_MAN_DOCS
|
||||
install_targets += install-html
|
||||
endif
|
||||
ifeq ($(ENABLE_DOXYGEN),1)
|
||||
install_targets += install-doxygen
|
||||
endif
|
||||
install-local:: $(install_targets)
|
||||
|
||||
# Live documentation is generated for the web site using this target:
|
||||
# 'make generated BUILD_FOR_WEBSITE=1'
|
||||
generated:: doxygen
|
||||
|
||||
install-html: $(PROJ_OBJ_DIR)/html.tar.gz
|
||||
$(Echo) Installing HTML documentation
|
||||
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_docsdir)/html
|
||||
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_docsdir)/html/img
|
||||
$(Verb) $(DataInstall) $(HTML) $(DESTDIR)$(PROJ_docsdir)/html
|
||||
# $(Verb) $(DataInstall) $(IMAGES) $(DESTDIR)$(PROJ_docsdir)/html/img
|
||||
$(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/html.tar.gz $(DESTDIR)$(PROJ_docsdir)
|
||||
|
||||
$(PROJ_OBJ_DIR)/html.tar.gz: $(HTML)
|
||||
$(Echo) Packaging HTML documentation
|
||||
$(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/html.tar
|
||||
$(Verb) cd $(PROJ_SRC_DIR) && \
|
||||
$(TAR) cf $(PROJ_OBJ_DIR)/html.tar *.html
|
||||
$(Verb) $(GZIPBIN) $(PROJ_OBJ_DIR)/html.tar
|
||||
|
||||
install-doxygen: doxygen
|
||||
$(Echo) Installing doxygen documentation
|
||||
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_docsdir)/html/doxygen
|
||||
$(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(DESTDIR)$(PROJ_docsdir)
|
||||
$(Verb) cd $(PROJ_OBJ_DIR)/doxygen && \
|
||||
$(FIND) . -type f -exec \
|
||||
$(DataInstall) {} $(DESTDIR)$(PROJ_docsdir)/html/doxygen \;
|
||||
|
||||
doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
|
||||
|
||||
regendoc:
|
||||
$(Echo) Building doxygen documentation
|
||||
$(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \
|
||||
$(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
|
||||
fi
|
||||
$(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||
|
||||
$(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||
$(Echo) Packaging doxygen documentation
|
||||
$(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/doxygen.tar
|
||||
$(Verb) $(TAR) cf $(PROJ_OBJ_DIR)/doxygen.tar doxygen
|
||||
$(Verb) $(GZIPBIN) $(PROJ_OBJ_DIR)/doxygen.tar
|
||||
$(Verb) $(CP) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_OBJ_DIR)/doxygen/html/
|
||||
|
||||
userloc: $(LLVM_SRC_ROOT)/docs/userloc.html
|
||||
|
||||
$(LLVM_SRC_ROOT)/docs/userloc.html:
|
||||
$(Echo) Making User LOC Table
|
||||
$(Verb) cd $(LLVM_SRC_ROOT) ; ./utils/userloc.pl -details -recurse \
|
||||
-html lib include tools runtime utils examples autoconf test > docs/userloc.html
|
||||
|
||||
uninstall-local::
|
||||
$(Echo) Uninstalling Documentation
|
||||
$(Verb) $(RM) -rf $(DESTDIR)$(PROJ_docsdir)
|
|
@ -0,0 +1,314 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
|
||||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=UTF8">
|
||||
<title>Clang Language Extensions</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
th { background-color: #ffddaa; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Objective-C Literals</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
Three new features were introduced into clang at the same time: <i>NSNumber Literals</i> provide a syntax for creating <code>NSNumber</code> from scalar literal expressions; <i>Collection Literals</i> provide a short-hand for creating arrays and dictionaries; <i>Object Subscripting</i> provides a way to use subscripting with Objective-C objects. Users of Apple compiler releases can use these features starting with the Apple LLVM Compiler 4.0. Users of open-source LLVM.org compiler releases can use these features starting with clang v3.1.<p>
|
||||
|
||||
These language additions simplify common Objective-C programming patterns, make programs more concise, and improve the safety of container creation.<p>
|
||||
|
||||
This document describes how the features are implemented in clang, and how to use them in your own programs.<p>
|
||||
|
||||
<h2>NSNumber Literals</h2>
|
||||
|
||||
The framework class <code>NSNumber</code> is used to wrap scalar values inside objects: signed and unsigned integers (<code>char</code>, <code>short</code>, <code>int</code>, <code>long</code>, <code>long long</code>), floating point numbers (<code>float</code>, <code>double</code>), and boolean values (<code>BOOL</code>, C++ <code>bool</code>). Scalar values wrapped in objects are also known as <i>boxed</i> values.<p>
|
||||
|
||||
In Objective-C, any character, numeric or boolean literal prefixed with the <code>'@'</code> character will evaluate to a pointer to an <code>NSNumber</code> object initialized with that value. C's type suffixes may be used to control the size of numeric literals.
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
The following program illustrates the rules for <code>NSNumber</code> literals:<p>
|
||||
|
||||
<pre>
|
||||
void main(int argc, const char *argv[]) {
|
||||
// character literals.
|
||||
NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z']
|
||||
|
||||
// integral literals.
|
||||
NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42]
|
||||
NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
|
||||
NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L]
|
||||
NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
|
||||
|
||||
// floating point literals.
|
||||
NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F]
|
||||
NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535]
|
||||
|
||||
// BOOL literals.
|
||||
NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES]
|
||||
NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO]
|
||||
|
||||
#ifdef __cplusplus
|
||||
NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true]
|
||||
NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false]
|
||||
#endif
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
NSNumber literals only support literal scalar values after the '@'. Consequently, @INT_MAX works, but @INT_MIN does not, because they are defined like this:<p>
|
||||
|
||||
<pre>
|
||||
#define INT_MAX 2147483647 /* max value for an int */
|
||||
#define INT_MIN (-2147483647-1) /* min value for an int */
|
||||
</pre>
|
||||
|
||||
The definition of INT_MIN is not a simple literal, but a parenthesized expression. This is by design, but may be improved in subsequent compiler releases.<p>
|
||||
|
||||
Because <code>NSNumber</code> does not currently support wrapping <code>long double</code> values, the use of a <code>long double NSNumber</code> literal (e.g. <code>@123.23L</code>) will be rejected by the compiler.<p>
|
||||
|
||||
Previously, the <code>BOOL</code> type was simply a typedef for <code>signed char</code>, and <code>YES</code> and <code>NO</code> were macros that expand to <code>(BOOL)1</code> and <code>(BOOL)0</code> respectively. To support <code>@YES</code> and <code>@NO</code> expressions, these macros are now defined using new language keywords in <code><objc/objc.h></code>:<p>
|
||||
|
||||
<pre>
|
||||
#if __has_feature(objc_bool)
|
||||
#define YES __objc_yes
|
||||
#define NO __objc_no
|
||||
#else
|
||||
#define YES ((BOOL)1)
|
||||
#define NO ((BOOL)0)
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
The compiler implicitly converts <code>__objc_yes</code> and <code>__objc_no</code> to <code>(BOOL)1</code> and <code>(BOOL)0</code>. The keywords are used to disambiguate <code>BOOL</code> and integer literals.<p>
|
||||
|
||||
Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.
|
||||
|
||||
|
||||
<h2>Container Literals</h2>
|
||||
|
||||
Objective-C now supports a new expression syntax for creating immutable array and dictionary container objects.
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
Immutable array expression:<p>
|
||||
|
||||
<pre>
|
||||
NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
|
||||
</pre>
|
||||
|
||||
This creates an <code>NSArray</code> with 3 elements. The comma-separated sub-expressions of an array literal can be any Objective-C object pointer typed expression.<p>
|
||||
|
||||
Immutable dictionary expression:<p>
|
||||
|
||||
<pre>
|
||||
NSDictionary *dictionary = @{
|
||||
@"name" : NSUserName(),
|
||||
@"date" : [NSDate date],
|
||||
@"processInfo" : [NSProcessInfo processInfo]
|
||||
};
|
||||
</pre>
|
||||
|
||||
This creates an <code>NSDictionary</code> with 3 key/value pairs. Value sub-expressions of a dictionary literal must be Objective-C object pointer typed, as in array literals. Key sub-expressions must be of an Objective-C object pointer type that implements the <code><NSCopying></code> protocol.<p>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
Neither keys nor values can have the value <code>nil</code> in containers. If the compiler can prove that a key or value is <code>nil</code> at compile time, then a warning will be emitted. Otherwise, a runtime error will occur.<p>
|
||||
|
||||
Using array and dictionary literals is safer than the variadic creation forms commonly in use today. Array literal expressions expand to calls to <code>+[NSArray arrayWithObjects:count:]</code>, which validates that all objects are non-<code>nil</code>. The variadic form, <code>+[NSArray arrayWithObjects:]</code> uses <code>nil</code> as an argument list terminator, which can lead to malformed array objects. Dictionary literals are similarly created with <code>+[NSDictionary dictionaryWithObjects:forKeys:count:]</code> which validates all objects and keys, unlike <code>+[NSDictionary dictionaryWithObjectsAndKeys:]</code> which also uses a <code>nil</code> parameter as an argument list terminator.<p>
|
||||
|
||||
<h2>Object Subscripting</h2>
|
||||
|
||||
Objective-C object pointer values can now be used with C's subscripting operator.<p>
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
The following code demonstrates the use of object subscripting syntax with <code>NSMutableArray</code> and <code>NSMutableDictionary</code> objects:<p>
|
||||
|
||||
<pre>
|
||||
NSMutableArray *array = ...;
|
||||
NSUInteger idx = ...;
|
||||
id newObject = ...;
|
||||
id oldObject = array[idx];
|
||||
array[idx] = newObject; // replace oldObject with newObject
|
||||
|
||||
NSMutableDictionary *dictionary = ...;
|
||||
NSString *key = ...;
|
||||
oldObject = dictionary[key];
|
||||
dictionary[key] = newObject; // replace oldObject with newObject
|
||||
</pre>
|
||||
|
||||
The next section explains how subscripting expressions map to accessor methods.<p>
|
||||
|
||||
<h3>Subscripting Methods</h3>
|
||||
|
||||
Objective-C supports two kinds of subscript expressions: <i>array-style</i> subscript expressions use integer typed subscripts; <i>dictionary-style</i> subscript expressions use Objective-C object pointer typed subscripts. Each type of subscript expression is mapped to a message send using a predefined selector. The advantage of this design is flexibility: class designers are free to introduce subscripting by declaring methods or by adopting protocols. Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.
|
||||
|
||||
<h4>Array-Style Subscripting</h4>
|
||||
|
||||
When the subscript operand has an integral type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. When an expression reads an element using an integral index, as in the following example:<p>
|
||||
|
||||
<pre>
|
||||
NSUInteger idx = ...;
|
||||
id value = object[idx];
|
||||
</pre>
|
||||
|
||||
it is translated into a call to <code>objectAtIndexedSubscript:</code><p>
|
||||
|
||||
<pre>
|
||||
id value = [object objectAtIndexedSubscript:idx];
|
||||
</pre>
|
||||
|
||||
When an expression writes an element using an integral index:<p>
|
||||
|
||||
<pre>
|
||||
object[idx] = newValue;
|
||||
</pre>
|
||||
|
||||
it is translated to a call to <code>setObject:atIndexedSubscript:</code><p>
|
||||
|
||||
<pre>
|
||||
[object setObject:newValue atIndexedSubscript:idx];
|
||||
</pre>
|
||||
|
||||
These message sends are then type-checked and performed just like explicit message sends. The method used for objectAtIndexedSubscript: must be declared with an argument of integral type and a return value of some Objective-C object pointer type. The method used for setObject:atIndexedSubscript: must be declared with its first argument having some Objective-C pointer type and its second argument having integral type.<p>
|
||||
|
||||
The meaning of indexes is left up to the declaring class. The compiler will coerce the index to the appropriate argument type of the method it uses for type-checking. For an instance of <code>NSArray</code>, reading an element using an index outside the range <code>[0, array.count)</code> will raise an exception. For an instance of <code>NSMutableArray</code>, assigning to an element using an index within this range will replace that element, but assigning to an element using an index outside this range will raise an exception; no syntax is provided for inserting, appending, or removing elements for mutable arrays.<p>
|
||||
|
||||
A class need not declare both methods in order to take advantage of this language feature. For example, the class <code>NSArray</code> declares only <code>objectAtIndexedSubscript:</code>, so that assignments to elements will fail to type-check; moreover, its subclass <code>NSMutableArray</code> declares <code>setObject:atIndexedSubscript:</code>.
|
||||
|
||||
<h4>Dictionary-Style Subscripting</h4>
|
||||
|
||||
When the subscript operand has an Objective-C object pointer type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read from or written to. When an expression reads an element using an Objective-C object pointer subscript operand, as in the following example:<p>
|
||||
|
||||
<pre>
|
||||
id key = ...;
|
||||
id value = object[key];
|
||||
</pre>
|
||||
|
||||
it is translated into a call to the <code>objectForKeyedSubscript:</code> method:<p>
|
||||
|
||||
<pre>
|
||||
id value = [object objectForKeyedSubscript:key];
|
||||
</pre>
|
||||
|
||||
When an expression writes an element using an Objective-C object pointer subscript:<p>
|
||||
|
||||
<pre>
|
||||
object[key] = newValue;
|
||||
</pre>
|
||||
|
||||
it is translated to a call to <code>setObject:forKeyedSubscript:</code>
|
||||
|
||||
<pre>
|
||||
[object setObject:newValue forKeyedSubscript:key];
|
||||
</pre>
|
||||
|
||||
The behavior of <code>setObject:forKeyedSubscript:</code> is class-specific; but in general it should replace an existing value if one is already associated with a key, otherwise it should add a new value for the key. No syntax is provided for removing elements from mutable dictionaries.<p>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
An Objective-C subscript expression occurs when the base operand of the C subscript operator has an Objective-C object pointer type. Since this potentially collides with pointer arithmetic on the value, these expressions are only supported under the modern Objective-C runtime, which categorically forbids such arithmetic.<p>
|
||||
|
||||
Currently, only subscripts of integral or Objective-C object pointer type are supported. In C++, a class type can be used if it has a single conversion function to an integral or Objective-C pointer type, in which case that conversion is applied and analysis continues as appropriate. Otherwise, the expression is ill-formed.<p>
|
||||
|
||||
An Objective-C object subscript expression is always an l-value. If the expression appears on the left-hand side of a simple assignment operator (=), the element is written as described below. If the expression appears on the left-hand side of a compound assignment operator (e.g. +=), the program is ill-formed, because the result of reading an element is always an Objective-C object pointer and no binary operators are legal on such pointers. If the expression appears in any other position, the element is read as described below. It is an error to take the address of a subscript expression, or (in C++) to bind a reference to it.<p>
|
||||
|
||||
Programs can use object subscripting with Objective-C object pointers of type <code>id</code>. Normal dynamic message send rules apply; the compiler must see <i>some</i> declaration of the subscripting methods, and will pick the declaration seen first.<p>
|
||||
|
||||
<h2>Grammar Additions</h2>
|
||||
|
||||
To support the new syntax described above, the Objective-C <code>@</code>-expression grammar has the following new productions:<p>
|
||||
|
||||
<pre>
|
||||
objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal)
|
||||
;
|
||||
|
||||
object-literal : ('+' | '-')? numeric-constant
|
||||
| character-constant
|
||||
| boolean-constant
|
||||
| array-literal
|
||||
| dictionary-literal
|
||||
;
|
||||
|
||||
boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */
|
||||
;
|
||||
|
||||
array-literal : '[' assignment-expression-list ']'
|
||||
;
|
||||
|
||||
assignment-expression-list : assignment-expression (',' assignment-expression-list)?
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
dictionary-literal : '{' key-value-list '}'
|
||||
;
|
||||
|
||||
key-value-list : key-value-pair (',' key-value-list)?
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
key-value-pair : assignment-expression ':' assignment-expression
|
||||
;
|
||||
</pre>
|
||||
|
||||
Note: <code>@true</code> and <code>@false</code> are only supported in Objective-C++.<p>
|
||||
|
||||
<h2>Availability Checks</h2>
|
||||
|
||||
Programs test for the new features by using clang's __has_feature checks. Here are examples of their use:<p>
|
||||
|
||||
<pre>
|
||||
#if __has_feature(objc_array_literals)
|
||||
// new way.
|
||||
NSArray *elements = @[ @"H", @"He", @"O", @"C" ];
|
||||
#else
|
||||
// old way (equivalent).
|
||||
id objects[] = { @"H", @"He", @"O", @"C" };
|
||||
NSArray *elements = [NSArray arrayWithObjects:objects count:4];
|
||||
#endif
|
||||
|
||||
#if __has_feature(objc_dictionary_literals)
|
||||
// new way.
|
||||
NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 };
|
||||
#else
|
||||
// old way (equivalent).
|
||||
id keys[] = { @"H", @"He", @"O", @"C" };
|
||||
id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026],
|
||||
[NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] };
|
||||
NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4];
|
||||
#endif
|
||||
|
||||
#if __has_feature(objc_subscripting)
|
||||
NSUInteger i, count = elements.count;
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSString *element = elements[i];
|
||||
NSNumber *mass = masses[element];
|
||||
NSLog(@"the mass of %@ is %@", element, mass);
|
||||
}
|
||||
#else
|
||||
NSUInteger i, count = [elements count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSString *element = [elements objectAtIndex:i];
|
||||
NSNumber *mass = [masses objectForKey:element];
|
||||
NSLog(@"the mass of %@ is %@", element, mass);
|
||||
}
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
Code can use also <code>__has_feature(objc_bool)</code> to check for the availability of numeric literals support. This checks for the new <code>__objc_yes / __objc_no</code> keywords, which enable the use of <code>@YES / @NO</code> literals.<p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,532 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Precompiled Headers (PCH)</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Precompiled Headers</h1>
|
||||
|
||||
<p>This document describes the design and implementation of Clang's
|
||||
precompiled headers (PCH). If you are interested in the end-user
|
||||
view, please see the <a
|
||||
href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
|
||||
|
||||
<p><b>Table of Contents</b></p>
|
||||
<ul>
|
||||
<li><a href="#usage">Using Precompiled Headers with
|
||||
<tt>clang</tt></a></li>
|
||||
<li><a href="#philosophy">Design Philosophy</a></li>
|
||||
<li><a href="#contents">Precompiled Header Contents</a>
|
||||
<ul>
|
||||
<li><a href="#metadata">Metadata Block</a></li>
|
||||
<li><a href="#sourcemgr">Source Manager Block</a></li>
|
||||
<li><a href="#preprocessor">Preprocessor Block</a></li>
|
||||
<li><a href="#types">Types Block</a></li>
|
||||
<li><a href="#decls">Declarations Block</a></li>
|
||||
<li><a href="#stmt">Statements and Expressions</a></li>
|
||||
<li><a href="#idtable">Identifier Table Block</a></li>
|
||||
<li><a href="#method-pool">Method Pool Block</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#tendrils">Precompiled Header Integration
|
||||
Points</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="usage">Using Precompiled Headers with <tt>clang</tt></h2>
|
||||
|
||||
<p>The Clang compiler frontend, <tt>clang -cc1</tt>, supports two command line
|
||||
options for generating and using PCH files.<p>
|
||||
|
||||
<p>To generate PCH files using <tt>clang -cc1</tt>, use the option
|
||||
<b><tt>-emit-pch</tt></b>:
|
||||
|
||||
<pre> $ clang -cc1 test.h -emit-pch -o test.h.pch </pre>
|
||||
|
||||
<p>This option is transparently used by <tt>clang</tt> when generating
|
||||
PCH files. The resulting PCH file contains the serialized form of the
|
||||
compiler's internal representation after it has completed parsing and
|
||||
semantic analysis. The PCH file can then be used as a prefix header
|
||||
with the <b><tt>-include-pch</tt></b> option:</p>
|
||||
|
||||
<pre>
|
||||
$ clang -cc1 -include-pch test.h.pch test.c -o test.s
|
||||
</pre>
|
||||
|
||||
<h2 id="philosophy">Design Philosophy</h2>
|
||||
|
||||
<p>Precompiled headers are meant to improve overall compile times for
|
||||
projects, so the design of precompiled headers is entirely driven by
|
||||
performance concerns. The use case for precompiled headers is
|
||||
relatively simple: when there is a common set of headers that is
|
||||
included in nearly every source file in the project, we
|
||||
<i>precompile</i> that bundle of headers into a single precompiled
|
||||
header (PCH file). Then, when compiling the source files in the
|
||||
project, we load the PCH file first (as a prefix header), which acts
|
||||
as a stand-in for that bundle of headers.</p>
|
||||
|
||||
<p>A precompiled header implementation improves performance when:</p>
|
||||
<ul>
|
||||
<li>Loading the PCH file is significantly faster than re-parsing the
|
||||
bundle of headers stored within the PCH file. Thus, a precompiled
|
||||
header design attempts to minimize the cost of reading the PCH
|
||||
file. Ideally, this cost should not vary with the size of the
|
||||
precompiled header file.</li>
|
||||
|
||||
<li>The cost of generating the PCH file initially is not so large
|
||||
that it counters the per-source-file performance improvement due to
|
||||
eliminating the need to parse the bundled headers in the first
|
||||
place. This is particularly important on multi-core systems, because
|
||||
PCH file generation serializes the build when all compilations
|
||||
require the PCH file to be up-to-date.</li>
|
||||
</ul>
|
||||
|
||||
<p>Clang's precompiled headers are designed with a compact on-disk
|
||||
representation, which minimizes both PCH creation time and the time
|
||||
required to initially load the PCH file. The PCH file itself contains
|
||||
a serialized representation of Clang's abstract syntax trees and
|
||||
supporting data structures, stored using the same compressed bitstream
|
||||
as <a href="http://llvm.org/docs/BitCodeFormat.html">LLVM's bitcode
|
||||
file format</a>.</p>
|
||||
|
||||
<p>Clang's precompiled headers are loaded "lazily" from disk. When a
|
||||
PCH file is initially loaded, Clang reads only a small amount of data
|
||||
from the PCH file to establish where certain important data structures
|
||||
are stored. The amount of data read in this initial load is
|
||||
independent of the size of the PCH file, such that a larger PCH file
|
||||
does not lead to longer PCH load times. The actual header data in the
|
||||
PCH file--macros, functions, variables, types, etc.--is loaded only
|
||||
when it is referenced from the user's code, at which point only that
|
||||
entity (and those entities it depends on) are deserialized from the
|
||||
PCH file. With this approach, the cost of using a precompiled header
|
||||
for a translation unit is proportional to the amount of code actually
|
||||
used from the header, rather than being proportional to the size of
|
||||
the header itself.</p>
|
||||
|
||||
<p>When given the <code>-print-stats</code> option, Clang produces
|
||||
statistics describing how much of the precompiled header was actually
|
||||
loaded from disk. For a simple "Hello, World!" program that includes
|
||||
the Apple <code>Cocoa.h</code> header (which is built as a precompiled
|
||||
header), this option illustrates how little of the actual precompiled
|
||||
header is required:</p>
|
||||
|
||||
<pre>
|
||||
*** PCH Statistics:
|
||||
933 stat cache hits
|
||||
4 stat cache misses
|
||||
895/39981 source location entries read (2.238563%)
|
||||
19/15315 types read (0.124061%)
|
||||
20/82685 declarations read (0.024188%)
|
||||
154/58070 identifiers read (0.265197%)
|
||||
0/7260 selectors read (0.000000%)
|
||||
0/30842 statements read (0.000000%)
|
||||
4/8400 macros read (0.047619%)
|
||||
1/4995 lexical declcontexts read (0.020020%)
|
||||
0/4413 visible declcontexts read (0.000000%)
|
||||
0/7230 method pool entries read (0.000000%)
|
||||
0 method pool misses
|
||||
</pre>
|
||||
|
||||
<p>For this small program, only a tiny fraction of the source
|
||||
locations, types, declarations, identifiers, and macros were actually
|
||||
deserialized from the precompiled header. These statistics can be
|
||||
useful to determine whether the precompiled header implementation can
|
||||
be improved by making more of the implementation lazy.</p>
|
||||
|
||||
<p>Precompiled headers can be chained. When you create a PCH while
|
||||
including an existing PCH, Clang can create the new PCH by referencing
|
||||
the original file and only writing the new data to the new file. For
|
||||
example, you could create a PCH out of all the headers that are very
|
||||
commonly used throughout your project, and then create a PCH for every
|
||||
single source file in the project that includes the code that is
|
||||
specific to that file, so that recompiling the file itself is very fast,
|
||||
without duplicating the data from the common headers for every file.</p>
|
||||
|
||||
<h2 id="contents">Precompiled Header Contents</h2>
|
||||
|
||||
<img src="PCHLayout.png" style="float:right" alt="Precompiled header layout">
|
||||
|
||||
<p>Clang's precompiled headers are organized into several different
|
||||
blocks, each of which contains the serialized representation of a part
|
||||
of Clang's internal representation. Each of the blocks corresponds to
|
||||
either a block or a record within <a
|
||||
href="http://llvm.org/docs/BitCodeFormat.html">LLVM's bitstream
|
||||
format</a>. The contents of each of these logical blocks are described
|
||||
below.</p>
|
||||
|
||||
<p>For a given precompiled header, the <a
|
||||
href="http://llvm.org/cmds/llvm-bcanalyzer.html"><code>llvm-bcanalyzer</code></a>
|
||||
utility can be used to examine the actual structure of the bitstream
|
||||
for the precompiled header. This information can be used both to help
|
||||
understand the structure of the precompiled header and to isolate
|
||||
areas where precompiled headers can still be optimized, e.g., through
|
||||
the introduction of abbreviations.</p>
|
||||
|
||||
<h3 id="metadata">Metadata Block</h3>
|
||||
|
||||
<p>The metadata block contains several records that provide
|
||||
information about how the precompiled header was built. This metadata
|
||||
is primarily used to validate the use of a precompiled header. For
|
||||
example, a precompiled header built for a 32-bit x86 target cannot be used
|
||||
when compiling for a 64-bit x86 target. The metadata block contains
|
||||
information about:</p>
|
||||
|
||||
<dl>
|
||||
<dt>Language options</dt>
|
||||
<dd>Describes the particular language dialect used to compile the
|
||||
PCH file, including major options (e.g., Objective-C support) and more
|
||||
minor options (e.g., support for "//" comments). The contents of this
|
||||
record correspond to the <code>LangOptions</code> class.</dd>
|
||||
|
||||
<dt>Target architecture</dt>
|
||||
<dd>The target triple that describes the architecture, platform, and
|
||||
ABI for which the PCH file was generated, e.g.,
|
||||
<code>i386-apple-darwin9</code>.</dd>
|
||||
|
||||
<dt>PCH version</dt>
|
||||
<dd>The major and minor version numbers of the precompiled header
|
||||
format. Changes in the minor version number should not affect backward
|
||||
compatibility, while changes in the major version number imply that a
|
||||
newer compiler cannot read an older precompiled header (and
|
||||
vice-versa).</dd>
|
||||
|
||||
<dt>Original file name</dt>
|
||||
<dd>The full path of the header that was used to generate the
|
||||
precompiled header.</dd>
|
||||
|
||||
<dt>Predefines buffer</dt>
|
||||
<dd>Although not explicitly stored as part of the metadata, the
|
||||
predefines buffer is used in the validation of the precompiled header.
|
||||
The predefines buffer itself contains code generated by the compiler
|
||||
to initialize the preprocessor state according to the current target,
|
||||
platform, and command-line options. For example, the predefines buffer
|
||||
will contain "<code>#define __STDC__ 1</code>" when we are compiling C
|
||||
without Microsoft extensions. The predefines buffer itself is stored
|
||||
within the <a href="#sourcemgr">source manager block</a>, but its
|
||||
contents are verified along with the rest of the metadata.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<p>A chained PCH file (that is, one that references another PCH) has
|
||||
a slightly different metadata block, which contains the following
|
||||
information:</p>
|
||||
|
||||
<dl>
|
||||
<dt>Referenced file</dt>
|
||||
<dd>The name of the referenced PCH file. It is looked up like a file
|
||||
specified using -include-pch.</dd>
|
||||
|
||||
<dt>PCH version</dt>
|
||||
<dd>This is the same as in normal PCH files.</dd>
|
||||
|
||||
<dt>Original file name</dt>
|
||||
<dd>The full path of the header that was used to generate this
|
||||
precompiled header.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<p>The language options, target architecture and predefines buffer data
|
||||
is taken from the end of the chain, since they have to match anyway.</p>
|
||||
|
||||
<h3 id="sourcemgr">Source Manager Block</h3>
|
||||
|
||||
<p>The source manager block contains the serialized representation of
|
||||
Clang's <a
|
||||
href="InternalsManual.html#SourceLocation">SourceManager</a> class,
|
||||
which handles the mapping from source locations (as represented in
|
||||
Clang's abstract syntax tree) into actual column/line positions within
|
||||
a source file or macro instantiation. The precompiled header's
|
||||
representation of the source manager also includes information about
|
||||
all of the headers that were (transitively) included when building the
|
||||
precompiled header.</p>
|
||||
|
||||
<p>The bulk of the source manager block is dedicated to information
|
||||
about the various files, buffers, and macro instantiations into which
|
||||
a source location can refer. Each of these is referenced by a numeric
|
||||
"file ID", which is a unique number (allocated starting at 1) stored
|
||||
in the source location. Clang serializes the information for each kind
|
||||
of file ID, along with an index that maps file IDs to the position
|
||||
within the PCH file where the information about that file ID is
|
||||
stored. The data associated with a file ID is loaded only when
|
||||
required by the front end, e.g., to emit a diagnostic that includes a
|
||||
macro instantiation history inside the header itself.</p>
|
||||
|
||||
<p>The source manager block also contains information about all of the
|
||||
headers that were included when building the precompiled header. This
|
||||
includes information about the controlling macro for the header (e.g.,
|
||||
when the preprocessor identified that the contents of the header
|
||||
dependent on a macro like <code>LLVM_CLANG_SOURCEMANAGER_H</code>)
|
||||
along with a cached version of the results of the <code>stat()</code>
|
||||
system calls performed when building the precompiled header. The
|
||||
latter is particularly useful in reducing system time when searching
|
||||
for include files.</p>
|
||||
|
||||
<h3 id="preprocessor">Preprocessor Block</h3>
|
||||
|
||||
<p>The preprocessor block contains the serialized representation of
|
||||
the preprocessor. Specifically, it contains all of the macros that
|
||||
have been defined by the end of the header used to build the
|
||||
precompiled header, along with the token sequences that comprise each
|
||||
macro. The macro definitions are only read from the PCH file when the
|
||||
name of the macro first occurs in the program. This lazy loading of
|
||||
macro definitions is triggered by lookups into the <a
|
||||
href="#idtable">identifier table</a>.</p>
|
||||
|
||||
<h3 id="types">Types Block</h3>
|
||||
|
||||
<p>The types block contains the serialized representation of all of
|
||||
the types referenced in the translation unit. Each Clang type node
|
||||
(<code>PointerType</code>, <code>FunctionProtoType</code>, etc.) has a
|
||||
corresponding record type in the PCH file. When types are deserialized
|
||||
from the precompiled header, the data within the record is used to
|
||||
reconstruct the appropriate type node using the AST context.</p>
|
||||
|
||||
<p>Each type has a unique type ID, which is an integer that uniquely
|
||||
identifies that type. Type ID 0 represents the NULL type, type IDs
|
||||
less than <code>NUM_PREDEF_TYPE_IDS</code> represent predefined types
|
||||
(<code>void</code>, <code>float</code>, etc.), while other
|
||||
"user-defined" type IDs are assigned consecutively from
|
||||
<code>NUM_PREDEF_TYPE_IDS</code> upward as the types are encountered.
|
||||
The PCH file has an associated mapping from the user-defined types
|
||||
block to the location within the types block where the serialized
|
||||
representation of that type resides, enabling lazy deserialization of
|
||||
types. When a type is referenced from within the PCH file, that
|
||||
reference is encoded using the type ID shifted left by 3 bits. The
|
||||
lower three bits are used to represent the <code>const</code>,
|
||||
<code>volatile</code>, and <code>restrict</code> qualifiers, as in
|
||||
Clang's <a
|
||||
href="http://clang.llvm.org/docs/InternalsManual.html#Type">QualType</a>
|
||||
class.</p>
|
||||
|
||||
<h3 id="decls">Declarations Block</h3>
|
||||
|
||||
<p>The declarations block contains the serialized representation of
|
||||
all of the declarations referenced in the translation unit. Each Clang
|
||||
declaration node (<code>VarDecl</code>, <code>FunctionDecl</code>,
|
||||
etc.) has a corresponding record type in the PCH file. When
|
||||
declarations are deserialized from the precompiled header, the data
|
||||
within the record is used to build and populate a new instance of the
|
||||
corresponding <code>Decl</code> node. As with types, each declaration
|
||||
node has a numeric ID that is used to refer to that declaration within
|
||||
the PCH file. In addition, a lookup table provides a mapping from that
|
||||
numeric ID to the offset within the precompiled header where that
|
||||
declaration is described.</p>
|
||||
|
||||
<p>Declarations in Clang's abstract syntax trees are stored
|
||||
hierarchically. At the top of the hierarchy is the translation unit
|
||||
(<code>TranslationUnitDecl</code>), which contains all of the
|
||||
declarations in the translation unit. These declarations (such as
|
||||
functions or struct types) may also contain other declarations inside
|
||||
them, and so on. Within Clang, each declaration is stored within a <a
|
||||
href="http://clang.llvm.org/docs/InternalsManual.html#DeclContext">declaration
|
||||
context</a>, as represented by the <code>DeclContext</code> class.
|
||||
Declaration contexts provide the mechanism to perform name lookup
|
||||
within a given declaration (e.g., find the member named <code>x</code>
|
||||
in a structure) and iterate over the declarations stored within a
|
||||
context (e.g., iterate over all of the fields of a structure for
|
||||
structure layout).</p>
|
||||
|
||||
<p>In Clang's precompiled header format, deserializing a declaration
|
||||
that is a <code>DeclContext</code> is a separate operation from
|
||||
deserializing all of the declarations stored within that declaration
|
||||
context. Therefore, Clang will deserialize the translation unit
|
||||
declaration without deserializing the declarations within that
|
||||
translation unit. When required, the declarations stored within a
|
||||
declaration context will be deserialized. There are two representations
|
||||
of the declarations within a declaration context, which correspond to
|
||||
the name-lookup and iteration behavior described above:</p>
|
||||
|
||||
<ul>
|
||||
<li>When the front end performs name lookup to find a name
|
||||
<code>x</code> within a given declaration context (for example,
|
||||
during semantic analysis of the expression <code>p->x</code>,
|
||||
where <code>p</code>'s type is defined in the precompiled header),
|
||||
Clang deserializes a hash table mapping from the names within that
|
||||
declaration context to the declaration IDs that represent each
|
||||
visible declaration with that name. The entire hash table is
|
||||
deserialized at this point (into the <code>llvm::DenseMap</code>
|
||||
stored within each <code>DeclContext</code> object), but the actual
|
||||
declarations are not yet deserialized. In a second step, those
|
||||
declarations with the name <code>x</code> will be deserialized and
|
||||
will be used as the result of name lookup.</li>
|
||||
|
||||
<li>When the front end performs iteration over all of the
|
||||
declarations within a declaration context, all of those declarations
|
||||
are immediately de-serialized. For large declaration contexts (e.g.,
|
||||
the translation unit), this operation is expensive; however, large
|
||||
declaration contexts are not traversed in normal compilation, since
|
||||
such a traversal is unnecessary. However, it is common for the code
|
||||
generator and semantic analysis to traverse declaration contexts for
|
||||
structs, classes, unions, and enumerations, although those contexts
|
||||
contain relatively few declarations in the common case.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="stmt">Statements and Expressions</h3>
|
||||
|
||||
<p>Statements and expressions are stored in the precompiled header in
|
||||
both the <a href="#types">types</a> and the <a
|
||||
href="#decls">declarations</a> blocks, because every statement or
|
||||
expression will be associated with either a type or declaration. The
|
||||
actual statement and expression records are stored immediately
|
||||
following the declaration or type that owns the statement or
|
||||
expression. For example, the statement representing the body of a
|
||||
function will be stored directly following the declaration of the
|
||||
function.</p>
|
||||
|
||||
<p>As with types and declarations, each statement and expression kind
|
||||
in Clang's abstract syntax tree (<code>ForStmt</code>,
|
||||
<code>CallExpr</code>, etc.) has a corresponding record type in the
|
||||
precompiled header, which contains the serialized representation of
|
||||
that statement or expression. Each substatement or subexpression
|
||||
within an expression is stored as a separate record (which keeps most
|
||||
records to a fixed size). Within the precompiled header, the
|
||||
subexpressions of an expression are stored, in reverse order, prior to the expression
|
||||
that owns those expression, using a form of <a
|
||||
href="http://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse
|
||||
Polish Notation</a>. For example, an expression <code>3 - 4 + 5</code>
|
||||
would be represented as follows:</p>
|
||||
|
||||
<table border="1">
|
||||
<tr><td><code>IntegerLiteral(5)</code></td></tr>
|
||||
<tr><td><code>IntegerLiteral(4)</code></td></tr>
|
||||
<tr><td><code>IntegerLiteral(3)</code></td></tr>
|
||||
<tr><td><code>BinaryOperator(-)</code></td></tr>
|
||||
<tr><td><code>BinaryOperator(+)</code></td></tr>
|
||||
<tr><td>STOP</td></tr>
|
||||
</table>
|
||||
|
||||
<p>When reading this representation, Clang evaluates each expression
|
||||
record it encounters, builds the appropriate abstract syntax tree node,
|
||||
and then pushes that expression on to a stack. When a record contains <i>N</i>
|
||||
subexpressions--<code>BinaryOperator</code> has two of them--those
|
||||
expressions are popped from the top of the stack. The special STOP
|
||||
code indicates that we have reached the end of a serialized expression
|
||||
or statement; other expression or statement records may follow, but
|
||||
they are part of a different expression.</p>
|
||||
|
||||
<h3 id="idtable">Identifier Table Block</h3>
|
||||
|
||||
<p>The identifier table block contains an on-disk hash table that maps
|
||||
each identifier mentioned within the precompiled header to the
|
||||
serialized representation of the identifier's information (e.g, the
|
||||
<code>IdentifierInfo</code> structure). The serialized representation
|
||||
contains:</p>
|
||||
|
||||
<ul>
|
||||
<li>The actual identifier string.</li>
|
||||
<li>Flags that describe whether this identifier is the name of a
|
||||
built-in, a poisoned identifier, an extension token, or a
|
||||
macro.</li>
|
||||
<li>If the identifier names a macro, the offset of the macro
|
||||
definition within the <a href="#preprocessor">preprocessor
|
||||
block</a>.</li>
|
||||
<li>If the identifier names one or more declarations visible from
|
||||
translation unit scope, the <a href="#decls">declaration IDs</a> of these
|
||||
declarations.</li>
|
||||
</ul>
|
||||
|
||||
<p>When a precompiled header is loaded, the precompiled header
|
||||
mechanism introduces itself into the identifier table as an external
|
||||
lookup source. Thus, when the user program refers to an identifier
|
||||
that has not yet been seen, Clang will perform a lookup into the
|
||||
identifier table. If an identifier is found, its contents (macro
|
||||
definitions, flags, top-level declarations, etc.) will be deserialized, at which point the corresponding <code>IdentifierInfo</code> structure will have the same contents it would have after parsing the headers in the precompiled header.</p>
|
||||
|
||||
<p>Within the PCH file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
|
||||
hash table where that identifier is stored. This mapping is used when
|
||||
deserializing the name of a declaration, the identifier of a token, or
|
||||
any other construct in the PCH file that refers to a name.</p>
|
||||
|
||||
<h3 id="method-pool">Method Pool Block</h3>
|
||||
|
||||
<p>The method pool block is represented as an on-disk hash table that
|
||||
serves two purposes: it provides a mapping from the names of
|
||||
Objective-C selectors to the set of Objective-C instance and class
|
||||
methods that have that particular selector (which is required for
|
||||
semantic analysis in Objective-C) and also stores all of the selectors
|
||||
used by entities within the precompiled header. The design of the
|
||||
method pool is similar to that of the <a href="#idtable">identifier
|
||||
table</a>: the first time a particular selector is formed during the
|
||||
compilation of the program, Clang will search in the on-disk hash
|
||||
table of selectors; if found, Clang will read the Objective-C methods
|
||||
associated with that selector into the appropriate front-end data
|
||||
structure (<code>Sema::InstanceMethodPool</code> and
|
||||
<code>Sema::FactoryMethodPool</code> for instance and class methods,
|
||||
respectively).</p>
|
||||
|
||||
<p>As with identifiers, selectors are represented by numeric values
|
||||
within the PCH file. A separate index maps these numeric selector
|
||||
values to the offset of the selector within the on-disk hash table,
|
||||
and will be used when de-serializing an Objective-C method declaration
|
||||
(or other Objective-C construct) that refers to the selector.</p>
|
||||
|
||||
<h2 id="tendrils">Precompiled Header Integration Points</h2>
|
||||
|
||||
<p>The "lazy" deserialization behavior of precompiled headers requires
|
||||
their integration into several completely different submodules of
|
||||
Clang. For example, lazily deserializing the declarations during name
|
||||
lookup requires that the name-lookup routines be able to query the
|
||||
precompiled header to find entities within the PCH file.</p>
|
||||
|
||||
<p>For each Clang data structure that requires direct interaction with
|
||||
the precompiled header logic, there is an abstract class that provides
|
||||
the interface between the two modules. The <code>PCHReader</code>
|
||||
class, which handles the loading of a precompiled header, inherits
|
||||
from all of these abstract classes to provide lazy deserialization of
|
||||
Clang's data structures. <code>PCHReader</code> implements the
|
||||
following abstract classes:</p>
|
||||
|
||||
<dl>
|
||||
<dt><code>StatSysCallCache</code></dt>
|
||||
<dd>This abstract interface is associated with the
|
||||
<code>FileManager</code> class, and is used whenever the file
|
||||
manager is going to perform a <code>stat()</code> system call.</dd>
|
||||
|
||||
<dt><code>ExternalSLocEntrySource</code></dt>
|
||||
<dd>This abstract interface is associated with the
|
||||
<code>SourceManager</code> class, and is used whenever the
|
||||
<a href="#sourcemgr">source manager</a> needs to load the details
|
||||
of a file, buffer, or macro instantiation.</dd>
|
||||
|
||||
<dt><code>IdentifierInfoLookup</code></dt>
|
||||
<dd>This abstract interface is associated with the
|
||||
<code>IdentifierTable</code> class, and is used whenever the
|
||||
program source refers to an identifier that has not yet been seen.
|
||||
In this case, the precompiled header implementation searches for
|
||||
this identifier within its <a href="#idtable">identifier table</a>
|
||||
to load any top-level declarations or macros associated with that
|
||||
identifier.</dd>
|
||||
|
||||
<dt><code>ExternalASTSource</code></dt>
|
||||
<dd>This abstract interface is associated with the
|
||||
<code>ASTContext</code> class, and is used whenever the abstract
|
||||
syntax tree nodes need to loaded from the precompiled header. It
|
||||
provides the ability to de-serialize declarations and types
|
||||
identified by their numeric values, read the bodies of functions
|
||||
when required, and read the declarations stored within a
|
||||
declaration context (either for iteration or for name lookup).</dd>
|
||||
|
||||
<dt><code>ExternalSemaSource</code></dt>
|
||||
<dd>This abstract interface is associated with the <code>Sema</code>
|
||||
class, and is used whenever semantic analysis needs to read
|
||||
information from the <a href="#methodpool">global method
|
||||
pool</a>.</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 31 KiB |
|
@ -0,0 +1,179 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Pretokenized Headers (PTH)</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Pretokenized Headers (PTH)</h1>
|
||||
|
||||
<p>This document first describes the low-level
|
||||
interface for using PTH and then briefly elaborates on its design and
|
||||
implementation. If you are interested in the end-user view, please see the
|
||||
<a href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
|
||||
|
||||
|
||||
<h2>Using Pretokenized Headers with <tt>clang</tt> (Low-level Interface)</h2>
|
||||
|
||||
<p>The Clang compiler frontend, <tt>clang -cc1</tt>, supports three command line
|
||||
options for generating and using PTH files.<p>
|
||||
|
||||
<p>To generate PTH files using <tt>clang -cc1</tt>, use the option
|
||||
<b><tt>-emit-pth</tt></b>:
|
||||
|
||||
<pre> $ clang -cc1 test.h -emit-pth -o test.h.pth </pre>
|
||||
|
||||
<p>This option is transparently used by <tt>clang</tt> when generating PTH
|
||||
files. Similarly, PTH files can be used as prefix headers using the
|
||||
<b><tt>-include-pth</tt></b> option:</p>
|
||||
|
||||
<pre>
|
||||
$ clang -cc1 -include-pth test.h.pth test.c -o test.s
|
||||
</pre>
|
||||
|
||||
<p>Alternatively, Clang's PTH files can be used as a raw "token-cache"
|
||||
(or "content" cache) of the source included by the original header
|
||||
file. This means that the contents of the PTH file are searched as substitutes
|
||||
for <em>any</em> source files that are used by <tt>clang -cc1</tt> to process a
|
||||
source file. This is done by specifying the <b><tt>-token-cache</tt></b>
|
||||
option:</p>
|
||||
|
||||
<pre>
|
||||
$ cat test.h
|
||||
#include <stdio.h>
|
||||
$ clang -cc1 -emit-pth test.h -o test.h.pth
|
||||
$ cat test.c
|
||||
#include "test.h"
|
||||
$ clang -cc1 test.c -o test -token-cache test.h.pth
|
||||
</pre>
|
||||
|
||||
<p>In this example the contents of <tt>stdio.h</tt> (and the files it includes)
|
||||
will be retrieved from <tt>test.h.pth</tt>, as the PTH file is being used in
|
||||
this case as a raw cache of the contents of <tt>test.h</tt>. This is a low-level
|
||||
interface used to both implement the high-level PTH interface as well as to
|
||||
provide alternative means to use PTH-style caching.</p>
|
||||
|
||||
<h2>PTH Design and Implementation</h2>
|
||||
|
||||
<p>Unlike GCC's precompiled headers, which cache the full ASTs and preprocessor
|
||||
state of a header file, Clang's pretokenized header files mainly cache the raw
|
||||
lexer <em>tokens</em> that are needed to segment the stream of characters in a
|
||||
source file into keywords, identifiers, and operators. Consequently, PTH serves
|
||||
to mainly directly speed up the lexing and preprocessing of a source file, while
|
||||
parsing and type-checking must be completely redone every time a PTH file is
|
||||
used.</p>
|
||||
|
||||
<h3>Basic Design Tradeoffs</h3>
|
||||
|
||||
<p>In the long term there are plans to provide an alternate PCH implementation
|
||||
for Clang that also caches the work for parsing and type checking the contents
|
||||
of header files. The current implementation of PCH in Clang as pretokenized
|
||||
header files was motivated by the following factors:<p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><p><b>Language independence</b>: PTH files work with any language that
|
||||
Clang's lexer can handle, including C, Objective-C, and (in the early stages)
|
||||
C++. This means development on language features at the parsing level or above
|
||||
(which is basically almost all interesting pieces) does not require PTH to be
|
||||
modified.</p></li>
|
||||
|
||||
<li><b>Simple design</b>: Relatively speaking, PTH has a simple design and
|
||||
implementation, making it easy to test. Further, because the machinery for PTH
|
||||
resides at the lower-levels of the Clang library stack it is fairly
|
||||
straightforward to profile and optimize.</li>
|
||||
</ul>
|
||||
|
||||
<p>Further, compared to GCC's PCH implementation (which is the dominate
|
||||
precompiled header file implementation that Clang can be directly compared
|
||||
against) the PTH design in Clang yields several attractive features:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><p><b>Architecture independence</b>: In contrast to GCC's PCH files (and
|
||||
those of several other compilers), Clang's PTH files are architecture
|
||||
independent, requiring only a single PTH file when building an program for
|
||||
multiple architectures.</p>
|
||||
|
||||
<p>For example, on Mac OS X one may wish to
|
||||
compile a "universal binary" that runs on PowerPC, 32-bit Intel
|
||||
(i386), and 64-bit Intel architectures. In contrast, GCC requires a PCH file for
|
||||
each architecture, as the definitions of types in the AST are
|
||||
architecture-specific. Since a Clang PTH file essentially represents a lexical
|
||||
cache of header files, a single PTH file can be safely used when compiling for
|
||||
multiple architectures. This can also reduce compile times because only a single
|
||||
PTH file needs to be generated during a build instead of several.</p></li>
|
||||
|
||||
<li><p><b>Reduced memory pressure</b>: Similar to GCC,
|
||||
Clang reads PTH files via the use of memory mapping (i.e., <tt>mmap</tt>).
|
||||
Clang, however, memory maps PTH files as read-only, meaning that multiple
|
||||
invocations of <tt>clang -cc1</tt> can share the same pages in memory from a
|
||||
memory-mapped PTH file. In comparison, GCC also memory maps its PCH files but
|
||||
also modifies those pages in memory, incurring the copy-on-write costs. The
|
||||
read-only nature of PTH can greatly reduce memory pressure for builds involving
|
||||
multiple cores, thus improving overall scalability.</p></li>
|
||||
|
||||
<li><p><b>Fast generation</b>: PTH files can be generated in a small fraction
|
||||
of the time needed to generate GCC's PCH files. Since PTH/PCH generation is a
|
||||
serial operation that typically blocks progress during a build, faster
|
||||
generation time leads to improved processor utilization with parallel builds on
|
||||
multicore machines.</p></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>Despite these strengths, PTH's simple design suffers some algorithmic
|
||||
handicaps compared to other PCH strategies such as those used by GCC. While PTH
|
||||
can greatly speed up the processing time of a header file, the amount of work
|
||||
required to process a header file is still roughly linear in the size of the
|
||||
header file. In contrast, the amount of work done by GCC to process a
|
||||
precompiled header is (theoretically) constant (the ASTs for the header are
|
||||
literally memory mapped into the compiler). This means that only the pieces of
|
||||
the header file that are referenced by the source file including the header are
|
||||
the only ones the compiler needs to process during actual compilation. While
|
||||
GCC's particular implementation of PCH mitigates some of these algorithmic
|
||||
strengths via the use of copy-on-write pages, the approach itself can
|
||||
fundamentally dominate at an algorithmic level, especially when one considers
|
||||
header files of arbitrary size.</p>
|
||||
|
||||
<p>There are plans to potentially implement an complementary PCH implementation
|
||||
for Clang based on the lazy deserialization of ASTs. This approach would
|
||||
theoretically have the same constant-time algorithmic advantages just mentioned
|
||||
but would also retain some of the strengths of PTH such as reduced memory
|
||||
pressure (ideal for multi-core builds).</p>
|
||||
|
||||
<h3>Internal PTH Optimizations</h3>
|
||||
|
||||
<p>While the main optimization employed by PTH is to reduce lexing time of
|
||||
header files by caching pre-lexed tokens, PTH also employs several other
|
||||
optimizations to speed up the processing of header files:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><p><em><tt>stat</tt> caching</em>: PTH files cache information obtained via
|
||||
calls to <tt>stat</tt> that <tt>clang -cc1</tt> uses to resolve which files are
|
||||
included by <tt>#include</tt> directives. This greatly reduces the overhead
|
||||
involved in context-switching to the kernel to resolve included files.</p></li>
|
||||
|
||||
<li><p><em>Fasting skipping of <tt>#ifdef</tt>...<tt>#endif</tt> chains</em>:
|
||||
PTH files record the basic structure of nested preprocessor blocks. When the
|
||||
condition of the preprocessor block is false, all of its tokens are immediately
|
||||
skipped instead of requiring them to be handled by Clang's
|
||||
preprocessor.</p></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,193 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang 3.1 Release Notes</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Clang 3.1 Release Notes</h1>
|
||||
|
||||
<img style="float:right" src="http://llvm.org/img/DragonSmall.png"
|
||||
width="136" height="136" alt="LLVM Dragon Logo">
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#whatsnew">What's New in Clang 3.1?</a>
|
||||
<ul>
|
||||
<li><a href="#majorfeatures">Major New Features</a></li>
|
||||
<li><a href="#cchanges">C Language Changes</a></li>
|
||||
<li><a href="#cxxchanges">C++ Language Changes</a></li>
|
||||
<li><a href="#objcchanges">Objective-C Language Changes</a></li>
|
||||
<li><a href="#apichanges">Internal API Changes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#knownproblems">Known Problems</a></li>
|
||||
<li><a href="#additionalinfo">Additional Information</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="doc_author">
|
||||
<p>Written by the <a href="http://llvm.org/">LLVM Team</a></p>
|
||||
</div>
|
||||
|
||||
<h1 style="color:red">These are in-progress notes for the upcoming Clang 3.1
|
||||
release.<br>
|
||||
You may prefer the
|
||||
<a href="http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html">Clang 3.0
|
||||
Release Notes</a>.</h1>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This document contains the release notes for the Clang C/C++/Objective-C
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.1. Here we
|
||||
describe the status of Clang in some detail, including major improvements from
|
||||
the previous release and new feature work. For the general LLVM release notes,
|
||||
see <a href="http://llvm.org/docs/ReleaseNotes.html">the LLVM
|
||||
documentation</a>. All LLVM releases may be downloaded from the
|
||||
<a href="http://llvm.org/releases/">LLVM releases web site</a>.</p>
|
||||
|
||||
<p>For more information about Clang or LLVM, including information about the
|
||||
latest release, please check out the main please see the
|
||||
<a href="http://clang.llvm.org">Clang Web Site</a> or the
|
||||
<a href="http://llvm.org">LLVM Web Site</a>.
|
||||
|
||||
<p>Note that if you are reading this file from a Subversion checkout or the main
|
||||
Clang web page, this document applies to the <i>next</i> release, not the
|
||||
current one. To see the release notes for a specific release, please see the
|
||||
<a href="http://llvm.org/releases/">releases page</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="whatsnew">What's New in Clang 3.1?</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Some of the major new features and improvements to Clang are listed here.
|
||||
Generic improvements to Clang as a whole or two its underlying infrastructure
|
||||
are described first, followed by language-specific sections with improvements to
|
||||
Clang's support for those languages.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="majorfeatures">Major New Features</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="majorfeature1">Feature 1</h4>
|
||||
...
|
||||
|
||||
<h4 id="diagnostics">New and better diagnostics</h4>
|
||||
|
||||
<p>New: <code>-Wdangling-else</code>, <code>-Wstrncat-size</code>, ...</p>
|
||||
|
||||
<p>Improved: <code>-Wformat</code>, <code>-Wempty-body</code>,
|
||||
<code>-Wliteral-conversion</code>, ...</p>
|
||||
|
||||
<h4 id="tooling">Tooling</h4>
|
||||
<!-- FIXME: add a link to the tooling documentation once that's written. -->
|
||||
<p>Added an API to enable clang-based standalone tools, including initial build
|
||||
system integration.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cchanges">C Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="c11changes">C11 Feature Support</h4>
|
||||
|
||||
<p>Clang 3.1 adds support for anonymous structs and anonymous unions, added in
|
||||
the latest ISO C standard. Use <code>-std=c11</code> or <code>-std=gnu11</code>
|
||||
to enable support for the new language standard. The new C11 features are
|
||||
backwards-compatible and are available as an extension in all language
|
||||
modes.</p>
|
||||
|
||||
<p>All warning and language selection flags which previously accepted
|
||||
<code>c1x</code> have been updated to accept <code>c11</code>. The old
|
||||
<code>c1x</code> forms have been removed.
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cxxchanges">C++ Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="cxx11changes">C++11 Feature Support</h4>
|
||||
<p>Clang 3.1 supports
|
||||
<a href="http://clang.llvm.org/cxx_status.html#cxx11">most of the language
|
||||
features</a> added in the latest ISO C++ standard,
|
||||
<a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">C++ 2011</a>.
|
||||
Use <code>-std=c++11</code> or <code>-std=gnu++11</code> to enable support for
|
||||
these features. In addition to the features supported by Clang 3.0, the
|
||||
following are now considered to be of production quality:
|
||||
<ul>
|
||||
<li>Generalized constant expressions</li>
|
||||
<li>Lambda expressions</li>
|
||||
<li>Generalized initializers</li>
|
||||
<li>Unrestricted unions</li>
|
||||
<li>User-defined literals</li>
|
||||
<li>Forward-declared enumerations</li>
|
||||
<li>Atomics (both libc++'s and libstdc++4.7's <tt><atomic></tt> are
|
||||
supported)</li>
|
||||
</ul>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="objcchanges">Objective-C Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
Clang 3.1 introduces several new Objective-C language features and improvements.
|
||||
|
||||
<h4 id="objcwformat">Format string checking for NSString literals</h4>
|
||||
|
||||
<code>-Wformat</code> now checks <code>@"nsstring literals"</code>.
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="apichanges">Internal API Changes</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
These are major API changes that have happened since the 3.0 release of Clang.
|
||||
If upgrading an external codebase that uses Clang as a library, this section
|
||||
should help get you past the largest hurdles of upgrading.
|
||||
|
||||
<h4 id="api1">API change 1</h4>
|
||||
...
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="knownproblems">Significant Known Problems</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="additionalinfo">Additional Information</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>A wide variety of additional information is available on the
|
||||
<a href="http://clang.llvm.org/">Clang web page</a>. The web page contains
|
||||
versions of the API documentation which are up-to-date with the Subversion
|
||||
version of the source code. You can access versions of these documents specific
|
||||
to this release by going into the "<tt>clang/doc/</tt>" directory in the Clang
|
||||
tree.</p>
|
||||
|
||||
<p>If you have any questions or comments about Clang, please feel free to
|
||||
contact us via the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">
|
||||
mailing list</a>.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<!-- Likely 3.1 release notes -->
|
||||
<!-- ======================================================================= -->
|
||||
<!--
|
||||
This is just a section to hold things that have already gotten started and
|
||||
should likely pick up proper release notes in 3.1.
|
||||
|
||||
- C1X and C++11 atomics infrastructure and support
|
||||
- CUDA support?
|
||||
|
||||
-->
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,408 @@
|
|||
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
|
||||
font-family: Verdana,Geneva,Arial,Helvetica,sans-serif;
|
||||
}
|
||||
BODY,TD {
|
||||
font-size: 90%;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
CAPTION { font-weight: bold }
|
||||
DIV.qindex {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.nav {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.navtab {
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
TD.navtab {
|
||||
font-size: 70%;
|
||||
}
|
||||
A.qindex {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D;
|
||||
}
|
||||
A.qindex:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D
|
||||
}
|
||||
A.qindex:hover {
|
||||
text-decoration: none;
|
||||
background-color: #ddddff;
|
||||
}
|
||||
A.qindexHL {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
border: 1px double #9295C2;
|
||||
}
|
||||
A.qindexHL:hover {
|
||||
text-decoration: none;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
}
|
||||
A.qindexHL:visited {
|
||||
text-decoration: none; background-color: #6666cc; color: #ffffff }
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.codeRef:link { font-weight: normal; color: #0000FF}
|
||||
A.codeRef:visited { font-weight: normal; color: #0000FF}
|
||||
A:hover { text-decoration: none; background-color: #f2f2ff }
|
||||
DL.el { margin-left: -1cm }
|
||||
.fragment {
|
||||
font-family: Fixed, monospace;
|
||||
font-size: 95%;
|
||||
}
|
||||
PRE.fragment {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
|
||||
TD.md { background-color: #F4F4FB; font-weight: bold; }
|
||||
TD.mdPrefix {
|
||||
background-color: #F4F4FB;
|
||||
color: #606060;
|
||||
font-size: 80%;
|
||||
}
|
||||
TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
|
||||
TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
|
||||
DIV.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
|
||||
BODY {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
TD.indexkey {
|
||||
background-color: #eeeeff;
|
||||
font-weight: bold;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TD.indexvalue {
|
||||
background-color: #eeeeff;
|
||||
font-style: italic;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TR.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
P.formulaDsp { text-align: center; }
|
||||
IMG.formulaDsp { }
|
||||
IMG.formulaInl { vertical-align: middle; }
|
||||
SPAN.keyword { color: #008000 }
|
||||
SPAN.keywordtype { color: #604020 }
|
||||
SPAN.keywordflow { color: #e08000 }
|
||||
SPAN.comment { color: #800000 }
|
||||
SPAN.preprocessor { color: #806020 }
|
||||
SPAN.stringliteral { color: #002080 }
|
||||
SPAN.charliteral { color: #008080 }
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #F4F4FB;
|
||||
}
|
||||
.mdRow {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
.mdescLeft {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.mdescRight {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.memItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplParams {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
color: #606060;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.search { color: #003399;
|
||||
font-weight: bold;
|
||||
}
|
||||
FORM.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
INPUT.search { font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
TD.tiny { font-size: 75%;
|
||||
}
|
||||
a {
|
||||
color: #252E78;
|
||||
}
|
||||
a:visited {
|
||||
color: #3D2185;
|
||||
}
|
||||
.dirtab { padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #b0b0b0;
|
||||
}
|
||||
TH.dirtab { background: #eeeeff;
|
||||
font-weight: bold;
|
||||
}
|
||||
HR { height: 1px;
|
||||
border: none;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
/*
|
||||
* LLVM Modifications.
|
||||
* Note: Everything above here is generated with "doxygen -w htlm" command. See
|
||||
* "doxygen --help" for details. What follows are CSS overrides for LLVM
|
||||
* specific formatting. We want to keep the above so it can be replaced with
|
||||
* subsequent doxygen upgrades.
|
||||
*/
|
||||
|
||||
.footer {
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.title {
|
||||
font-size: 25pt;
|
||||
color: black; background: url("http://llvm.org/img/lines.gif");
|
||||
font-weight: bold;
|
||||
border-width: 1px;
|
||||
border-style: solid none solid none;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding-left: 8pt;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 2px
|
||||
}
|
||||
A:link {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:visited {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:active {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
font-style: italic;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
H2, H3 {
|
||||
border-bottom: 2px solid;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
A.qindex {}
|
||||
A.qindexRef {}
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code { text-decoration: none; font-weight: normal; color: #4444ee }
|
||||
A.codeRef { font-weight: normal; color: #4444ee }
|
||||
|
||||
div.memitem {
|
||||
border: 1px solid #999999;
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 1.0em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-webkit-box-shadow: 3px 3px 6px #777777;
|
||||
-moz-border-radius: 0.5em;
|
||||
-moz-box-shadow: black 3px 3px 3px;
|
||||
}
|
||||
|
||||
div.memproto {
|
||||
background-color: #E3E4E5;
|
||||
padding: 0.25em 0.5em;
|
||||
-webkit-border-top-left-radius: 0.5em;
|
||||
-webkit-border-top-right-radius: 0.5em;
|
||||
-moz-border-radius-topleft: 0.5em;
|
||||
-moz-border-radius-topright: 0.5em;
|
||||
}
|
||||
|
||||
div.memdoc {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<hr>
|
||||
<p class="footer">
|
||||
Generated on $datetime by <a href="http://www.doxygen.org">Doxygen
|
||||
$doxygenversion</a>.</p>
|
||||
|
||||
<p class="footer">
|
||||
See the <a href="http://clang.llvm.org">Main Clang Web Page</a> for more
|
||||
information.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
|
||||
<meta name="keywords" content="clang,LLVM,Low Level Virtual Machine,C,C++,doxygen,API,frontend,documentation"/>
|
||||
<meta name="description" content="C++ source code API documentation for clang."/>
|
||||
<title>clang: $title</title>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
|
||||
</head><body>
|
||||
<p class="title">clang API Documentation</p>
|
|
@ -0,0 +1,15 @@
|
|||
/// @mainpage clang
|
||||
///
|
||||
/// @section main_intro Introduction
|
||||
/// Welcome to the clang project.
|
||||
///
|
||||
/// This documentation describes the @b internal software that makes
|
||||
/// up clang, not the @b external use of clang. There are no instructions
|
||||
/// here on how to use clang, only the APIs that make up the software. For
|
||||
/// usage instructions, please see the programmer's guide or reference
|
||||
/// manual.
|
||||
///
|
||||
/// @section main_caveat Caveat
|
||||
/// This documentation is generated directly from the source code with doxygen.
|
||||
/// Since clang is constantly under active development, what you're about to
|
||||
/// read is out of date!
|
|
@ -0,0 +1,116 @@
|
|||
##===- docs/tools/Makefile ---------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
ifdef BUILD_FOR_WEBSITE
|
||||
|
||||
# FIXME: This was copied from the CommandGuide makefile. Figure out
|
||||
# how to get this stuff on the website.
|
||||
|
||||
# This special case is for keeping the CommandGuide on the LLVM web site
|
||||
# up to date automatically as the documents are checked in. It must build
|
||||
# the POD files to HTML only and keep them in the src directories. It must also
|
||||
# build in an unconfigured tree, hence the ifdef. To use this, run
|
||||
# make -s BUILD_FOR_WEBSITE=1 inside the cvs commit script.
|
||||
SRC_DOC_DIR=
|
||||
DST_HTML_DIR=html/
|
||||
DST_MAN_DIR=man/man1/
|
||||
DST_PS_DIR=ps/
|
||||
CLANG_VERSION := trunk
|
||||
|
||||
# If we are in BUILD_FOR_WEBSITE mode, default to the all target.
|
||||
all:: html man ps
|
||||
|
||||
clean:
|
||||
rm -f pod2htm*.*~~ $(HTML) $(MAN) $(PS)
|
||||
|
||||
# To create other directories, as needed, and timestamp their creation
|
||||
%/.dir:
|
||||
-mkdir $* > /dev/null
|
||||
date > $@
|
||||
|
||||
else
|
||||
|
||||
# Otherwise, if not in BUILD_FOR_WEBSITE mode, use the project info.
|
||||
CLANG_LEVEL := ../..
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
CLANG_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \
|
||||
$(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc))
|
||||
|
||||
SRC_DOC_DIR=$(PROJ_SRC_DIR)/
|
||||
DST_HTML_DIR=$(PROJ_OBJ_DIR)/
|
||||
DST_MAN_DIR=$(PROJ_OBJ_DIR)/
|
||||
DST_PS_DIR=$(PROJ_OBJ_DIR)/
|
||||
|
||||
endif
|
||||
|
||||
|
||||
POD := $(wildcard $(SRC_DOC_DIR)*.pod)
|
||||
HTML := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_HTML_DIR)%.html, $(POD))
|
||||
MAN := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_MAN_DIR)%.1, $(POD))
|
||||
PS := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_PS_DIR)%.ps, $(POD))
|
||||
|
||||
ifdef ONLY_MAN_DOCS
|
||||
INSTALL_TARGETS := install-man
|
||||
else
|
||||
INSTALL_TARGETS := install-html install-man install-ps
|
||||
endif
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .html .pod .1 .ps
|
||||
|
||||
$(DST_HTML_DIR)%.html: %.pod $(DST_HTML_DIR)/.dir
|
||||
pod2html --css=manpage.css --htmlroot=. \
|
||||
--podpath=. --infile=$< --outfile=$@ --title=$*
|
||||
|
||||
$(DST_MAN_DIR)%.1: %.pod $(DST_MAN_DIR)/.dir
|
||||
pod2man --release "clang $(CLANG_VERSION)" --center="Clang Tools Documentation" $< $@
|
||||
|
||||
$(DST_PS_DIR)%.ps: $(DST_MAN_DIR)%.1 $(DST_PS_DIR)/.dir
|
||||
groff -Tps -man $< > $@
|
||||
|
||||
|
||||
html: $(HTML)
|
||||
man: $(MAN)
|
||||
ps: $(PS)
|
||||
|
||||
EXTRA_DIST := $(POD)
|
||||
|
||||
clean-local::
|
||||
$(Verb) $(RM) -f pod2htm*.*~~ $(HTML) $(MAN) $(PS)
|
||||
|
||||
HTML_DIR := $(DESTDIR)$(PROJ_docsdir)/html/clang
|
||||
MAN_DIR := $(DESTDIR)$(PROJ_mandir)/man1
|
||||
PS_DIR := $(DESTDIR)$(PROJ_docsdir)/ps
|
||||
|
||||
install-html:: $(HTML)
|
||||
$(Echo) Installing HTML Clang Tools Documentation
|
||||
$(Verb) $(MKDIR) $(HTML_DIR)
|
||||
$(Verb) $(DataInstall) $(HTML) $(HTML_DIR)
|
||||
$(Verb) $(DataInstall) $(PROJ_SRC_DIR)/manpage.css $(HTML_DIR)
|
||||
|
||||
install-man:: $(MAN)
|
||||
$(Echo) Installing MAN Clang Tools Documentation
|
||||
$(Verb) $(MKDIR) $(MAN_DIR)
|
||||
$(Verb) $(DataInstall) $(MAN) $(MAN_DIR)
|
||||
|
||||
install-ps:: $(PS)
|
||||
$(Echo) Installing PS Clang Tools Documentation
|
||||
$(Verb) $(MKDIR) $(PS_DIR)
|
||||
$(Verb) $(DataInstall) $(PS) $(PS_DIR)
|
||||
|
||||
install-local:: $(INSTALL_TARGETS)
|
||||
|
||||
uninstall-local::
|
||||
$(Echo) Uninstalling Clang Tools Documentation
|
||||
$(Verb) $(RM) -rf $(HTML_DIR) $(MAN_DIR) $(PS_DIR)
|
||||
|
||||
printvars::
|
||||
$(Echo) "POD : " '$(POD)'
|
||||
$(Echo) "HTML : " '$(HTML)'
|
|
@ -0,0 +1,560 @@
|
|||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
clang - the Clang C, C++, and Objective-C compiler
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
|
||||
[B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-Oz>|B<-O3>|B<-O4>]
|
||||
B<-W>I<warnings...> B<-pedantic>
|
||||
B<-I>I<dir...> B<-L>I<dir...>
|
||||
B<-D>I<macro[=defn]>
|
||||
B<-f>I<feature-option...>
|
||||
B<-m>I<machine-option...>
|
||||
B<-o> I<output-file>
|
||||
B<-stdlib=>I<library>
|
||||
I<input-filenames>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<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:
|
||||
|
||||
=over
|
||||
|
||||
=item B<Driver>
|
||||
|
||||
The B<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.
|
||||
|
||||
=item B<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.
|
||||
|
||||
=item B<Parsing and Semantic Analysis>
|
||||
|
||||
This stage parses the input file, translating preprocessor tokens into a parse
|
||||
tree. Once in the form of a parser 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).
|
||||
|
||||
=item B<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.
|
||||
|
||||
=item B<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.
|
||||
|
||||
=item B<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.
|
||||
|
||||
=back
|
||||
|
||||
The Clang compiler supports a large number of options to control each of these
|
||||
stages. In addition to compilation of code, Clang also supports other tools:
|
||||
|
||||
B<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.
|
||||
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=head2 Stage Selection Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-E>
|
||||
|
||||
Run the preprocessor stage.
|
||||
|
||||
=item B<-fsyntax-only>
|
||||
|
||||
Run the preprocessor, parser and type checking stages.
|
||||
|
||||
=item B<-S>
|
||||
|
||||
Run the previous stages as well as LLVM generation and optimization stages and
|
||||
target-specific code generation, producing an assembly file.
|
||||
|
||||
=item B<-c>
|
||||
|
||||
Run all of the above, plus the assembler, generating a target ".o" object file.
|
||||
|
||||
=item B<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.
|
||||
|
||||
=item B<--analyze>
|
||||
|
||||
Run the Clang Static Analyzer.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=head2 Language Selection and Mode Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-x> I<language>
|
||||
|
||||
Treat subsequent input files as having type I<language>.
|
||||
|
||||
=item B<-std>=I<language>
|
||||
|
||||
Specify the language standard to compile for.
|
||||
|
||||
=item B<-stdlib>=I<language>
|
||||
|
||||
Specify the C++ standard library to use; supported options are libstdc++ and
|
||||
libc++.
|
||||
|
||||
=item B<-ansi>
|
||||
|
||||
Same as B<-std=c89>.
|
||||
|
||||
=item B<-ObjC++>
|
||||
|
||||
Treat source input files as Objective-C++ inputs.
|
||||
|
||||
=item B<-ObjC>
|
||||
|
||||
Treat source input files as Objective-C inputs.
|
||||
|
||||
=item B<-trigraphs>
|
||||
|
||||
Enable trigraphs.
|
||||
|
||||
=item B<-ffreestanding>
|
||||
|
||||
Indicate that the file should be compiled for a freestanding, not a hosted,
|
||||
environment.
|
||||
|
||||
=item B<-fno-builtin>
|
||||
|
||||
Disable special handling and optimizations of builtin functions like strlen and
|
||||
malloc.
|
||||
|
||||
=item B<-fmath-errno>
|
||||
|
||||
Indicate that math functions should be treated as updating errno.
|
||||
|
||||
=item B<-fpascal-strings>
|
||||
|
||||
Enable support for Pascal-style strings with "\pfoo".
|
||||
|
||||
=item B<-fms-extensions>
|
||||
|
||||
Enable support for Microsoft extensions.
|
||||
|
||||
=item B<-fmsc-version=>
|
||||
|
||||
Set _MSC_VER. Defaults to 1300 on Windows. Not set otherwise.
|
||||
|
||||
=item B<-fborland-extensions>
|
||||
|
||||
Enable support for Borland extensions.
|
||||
|
||||
=item B<-fwritable-strings>
|
||||
|
||||
Make all string literals default to writable. This disables uniquing of
|
||||
strings and other optimizations.
|
||||
|
||||
=item B<-flax-vector-conversions>
|
||||
|
||||
Allow loose type checking rules for implicit vector conversions.
|
||||
|
||||
=item B<-fblocks>
|
||||
|
||||
Enable the "Blocks" language feature.
|
||||
|
||||
=item B<-fobjc-gc-only>
|
||||
|
||||
Indicate that Objective-C code should be compiled in GC-only mode, which only
|
||||
works when Objective-C Garbage Collection is enabled.
|
||||
|
||||
=item B<-fobjc-gc>
|
||||
|
||||
Indicate that Objective-C code should be compiled in hybrid-GC mode, which works
|
||||
with both GC and non-GC mode.
|
||||
|
||||
=item B<-fobjc-abi-version>=I<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).
|
||||
|
||||
=item B<-fobjc-nonfragile-abi-version>=I<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
|
||||
-fobjc-nonfragile-abi, or because it is the platform default).
|
||||
|
||||
=item B<-fobjc-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 B<-fno-objc-nonfragile-abi>.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=head2 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.
|
||||
|
||||
=over
|
||||
|
||||
=item B<-arch> I<architecture>
|
||||
|
||||
Specify the architecture to build for.
|
||||
|
||||
=item B<-mmacosx-version-min>=I<version>
|
||||
|
||||
When building for Mac OS/X, specify the minimum version supported by your
|
||||
application.
|
||||
|
||||
=item B<-miphoneos-version-min>
|
||||
|
||||
When building for iPhone OS, specify the minimum version supported by your
|
||||
application.
|
||||
|
||||
|
||||
=item B<-march>=I<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.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Code Generation Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-O0> B<-O1> B<-O2> B<-Os> B<-Oz> B<-O3> B<-O4>
|
||||
|
||||
Specify which optimization level to use. B<-O0> means "no optimization": this
|
||||
level compiles the fastest and generates the most debuggable code. B<-O2> is a
|
||||
moderate level of optimization which enables most optimizations. B<-Os> is like
|
||||
B<-O2> with extra optimizations to reduce code size. B<-Oz> is like B<-Os>
|
||||
(and thus B<-O2>), but reduces code size further. B<-O3> is like B<-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). On
|
||||
supported platforms, B<-O4> enables link-time optimization; object files are
|
||||
stored in the LLVM bitcode file format and whole program optimization is done at
|
||||
link time. B<-O1> is somewhere between B<-O0> and B<-O2>.
|
||||
|
||||
=item B<-g>
|
||||
|
||||
Generate debug information. Note that Clang debug information works best at
|
||||
B<-O0>. At higher optimization levels, only line number information is
|
||||
currently available.
|
||||
|
||||
=item B<-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.
|
||||
|
||||
=item B<-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.
|
||||
|
||||
|
||||
=item B<-fvisibility>
|
||||
|
||||
This flag sets the default visibility level.
|
||||
|
||||
=item B<-fcommon>
|
||||
|
||||
This flag specifies that variables without initializers get common linkage. It
|
||||
can be disabled with B<-fno-common>.
|
||||
|
||||
=item B<-flto> B<-emit-llvm>
|
||||
|
||||
Generate output files in LLVM formats, suitable for link time optimization. When
|
||||
used with B<-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).
|
||||
|
||||
=cut
|
||||
|
||||
##=item B<-fnext-runtime> B<-fobjc-nonfragile-abi> B<-fgnu-runtime>
|
||||
##These options specify which Objective-C runtime the code generator should
|
||||
##target. FIXME: we don't want people poking these generally.
|
||||
|
||||
=pod
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Driver Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-###>
|
||||
|
||||
Print the commands to run for this compilation.
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Display available options.
|
||||
|
||||
=item B<-Qunused-arguments>
|
||||
|
||||
Don't emit warning for unused driver arguments.
|
||||
|
||||
=item B<-Wa,>I<args>
|
||||
|
||||
Pass the comma separated arguments in I<args> to the assembler.
|
||||
|
||||
=item B<-Wl,>I<args>
|
||||
|
||||
Pass the comma separated arguments in I<args> to the linker.
|
||||
|
||||
=item B<-Wp,>I<args>
|
||||
|
||||
Pass the comma separated arguments in I<args> to the preprocessor.
|
||||
|
||||
=item B<-Xanalyzer> I<arg>
|
||||
|
||||
Pass I<arg> to the static analyzer.
|
||||
|
||||
=item B<-Xassembler> I<arg>
|
||||
|
||||
Pass I<arg> to the assembler.
|
||||
|
||||
=item B<-Xlinker> I<arg>
|
||||
|
||||
Pass I<arg> to the linker.
|
||||
|
||||
=item B<-Xpreprocessor> I<arg>
|
||||
|
||||
Pass I<arg> to the preprocessor.
|
||||
|
||||
=item B<-o> I<file>
|
||||
|
||||
Write output to I<file>.
|
||||
|
||||
=item B<-print-file-name>=I<file>
|
||||
|
||||
Print the full library path of I<file>.
|
||||
|
||||
=item B<-print-libgcc-file-name>
|
||||
|
||||
Print the library path for "libgcc.a".
|
||||
|
||||
=item B<-print-prog-name>=I<name>
|
||||
|
||||
Print the full program path of I<name>.
|
||||
|
||||
=item B<-print-search-dirs>
|
||||
|
||||
Print the paths used for finding libraries and programs.
|
||||
|
||||
=item B<-save-temps>
|
||||
|
||||
Save intermediate compilation results.
|
||||
|
||||
=item B<-integrated-as> B<-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.
|
||||
|
||||
=item B<-time>
|
||||
|
||||
Time individual commands.
|
||||
|
||||
=item B<-ftime-report>
|
||||
|
||||
Print timing summary of each stage of compilation.
|
||||
|
||||
=item B<-v>
|
||||
|
||||
Show commands to run and use verbose output.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Diagnostics Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-fshow-column>
|
||||
B<-fshow-source-location>
|
||||
B<-fcaret-diagnostics>
|
||||
B<-fdiagnostics-fixit-info>
|
||||
B<-fdiagnostics-parseable-fixits>
|
||||
B<-fdiagnostics-print-source-range-info>
|
||||
B<-fprint-source-range-info>
|
||||
B<-fdiagnostics-show-option>
|
||||
B<-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.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Preprocessor Options
|
||||
|
||||
=over
|
||||
|
||||
=item B<-D>I<macroname=value>
|
||||
|
||||
Adds an implicit #define into the predefines buffer which is read before the
|
||||
source file is preprocessed.
|
||||
|
||||
=item B<-U>I<macroname>
|
||||
|
||||
Adds an implicit #undef into the predefines buffer which is read before the
|
||||
source file is preprocessed.
|
||||
|
||||
=item B<-include> I<filename>
|
||||
|
||||
Adds an implicit #include into the predefines buffer which is read before the
|
||||
source file is preprocessed.
|
||||
|
||||
=item B<-I>I<directory>
|
||||
|
||||
Add the specified directory to the search path for include files.
|
||||
|
||||
=item B<-F>I<directory>
|
||||
|
||||
Add the specified directory to the search path for framework include files.
|
||||
|
||||
=item B<-nostdinc>
|
||||
|
||||
Do not search the standard system directories or compiler builtin directories
|
||||
for include files.
|
||||
|
||||
=item B<-nostdlibinc>
|
||||
|
||||
Do not search the standard system directories for include files, but do search
|
||||
compiler builtin include directories.
|
||||
|
||||
=item B<-nobuiltininc>
|
||||
|
||||
Do not search clang's builtin directory for include files.
|
||||
|
||||
=cut
|
||||
|
||||
## TODO, but do we really want people using this stuff?
|
||||
#=item B<-idirafter>I<directory>
|
||||
#=item B<-iquote>I<directory>
|
||||
#=item B<-isystem>I<directory>
|
||||
#=item B<-iprefix>I<directory>
|
||||
#=item B<-iwithprefix>I<directory>
|
||||
#=item B<-iwithprefixbefore>I<directory>
|
||||
#=item B<-isysroot>
|
||||
|
||||
=pod
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
### TODO someday.
|
||||
#=head2 Warning Control Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Code Generation and Optimization Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Assembler Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Linker Options
|
||||
#=over
|
||||
#=back
|
||||
#=head2 Static Analyzer Options
|
||||
#=over
|
||||
#=back
|
||||
|
||||
=pod
|
||||
|
||||
|
||||
=head1 ENVIRONMENT
|
||||
|
||||
=over
|
||||
|
||||
=item B<TMPDIR>, B<TEMP>, B<TMP>
|
||||
|
||||
These environment variables are checked, in order, for the location to
|
||||
write temporary files used during the compilation process.
|
||||
|
||||
=item B<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 delimitor, as used in the I<PATH>
|
||||
environment variable.
|
||||
|
||||
Empty components in the environment variable are ignored.
|
||||
|
||||
=item B<C_INCLUDE_PATH>, B<OBJC_INCLUDE_PATH>, B<CPLUS_INCLUDE_PATH>,
|
||||
B<OBJCPLUS_INCLUDE_PATH>
|
||||
|
||||
These environment variables specify additional paths, as for CPATH,
|
||||
which are only used when processing the appropriate language.
|
||||
|
||||
=item B<MACOSX_DEPLOYMENT_TARGET>
|
||||
|
||||
If -mmacosx-version-min is unspecified, the default deployment target
|
||||
is read from this environment variable. This option only affects darwin
|
||||
targets.
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
To report bugs, please visit L<http://llvm.org/bugs/>. Most bug reports should
|
||||
include preprocessed source files (use the B<-E> option) and the full output of
|
||||
the compiler, along with information to reproduce.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
as(1), ld(1)
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Maintained by the Clang / LLVM Team (L<http://clang.llvm.org>).
|
||||
|
||||
=cut
|
|
@ -0,0 +1,256 @@
|
|||
/* Based on http://www.perldoc.com/css/perldoc.css */
|
||||
|
||||
@import url("../llvm.css");
|
||||
|
||||
body { font-family: Arial,Helvetica; }
|
||||
|
||||
blockquote { margin: 10pt; }
|
||||
|
||||
h1, a { color: #336699; }
|
||||
|
||||
|
||||
/*** Top menu style ****/
|
||||
.mmenuon {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ff6600; font-size: 10pt;
|
||||
}
|
||||
.mmenuoff {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ffffff; font-size: 10pt;
|
||||
}
|
||||
.cpyright {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ffffff; font-size: xx-small;
|
||||
}
|
||||
.cpyrightText {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #ffffff; font-size: xx-small;
|
||||
}
|
||||
.sections {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 11pt;
|
||||
}
|
||||
.dsections {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 12pt;
|
||||
}
|
||||
.slink {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #000000; font-size: 9pt;
|
||||
}
|
||||
|
||||
.slink2 { font-family: Arial,Helvetica; text-decoration: none; color: #336699; }
|
||||
|
||||
.maintitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 18pt;
|
||||
}
|
||||
.dblArrow {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: small;
|
||||
}
|
||||
.menuSec {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: small;
|
||||
}
|
||||
|
||||
.newstext {
|
||||
font-family: Arial,Helvetica; font-size: small;
|
||||
}
|
||||
|
||||
.linkmenu {
|
||||
font-family: Arial,Helvetica; color: #000000; font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
P {
|
||||
font-family: Arial,Helvetica;
|
||||
}
|
||||
|
||||
PRE {
|
||||
font-size: 10pt;
|
||||
}
|
||||
.quote {
|
||||
font-family: Times; text-decoration: none;
|
||||
color: #000000; font-size: 9pt; font-style: italic;
|
||||
}
|
||||
.smstd { font-family: Arial,Helvetica; color: #000000; font-size: x-small; }
|
||||
.std { font-family: Arial,Helvetica; color: #000000; }
|
||||
.meerkatTitle {
|
||||
font-family: sans-serif; font-size: x-small; color: black; }
|
||||
|
||||
.meerkatDescription { font-family: sans-serif; font-size: 10pt; color: black }
|
||||
.meerkatCategory {
|
||||
font-family: sans-serif; font-size: 9pt; font-weight: bold; font-style: italic;
|
||||
color: brown; }
|
||||
.meerkatChannel {
|
||||
font-family: sans-serif; font-size: 9pt; font-style: italic; color: brown; }
|
||||
.meerkatDate { font-family: sans-serif; font-size: xx-small; color: #336699; }
|
||||
|
||||
.tocTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #333333; font-size: 10pt;
|
||||
}
|
||||
|
||||
.toc-item {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #336699; font-size: 10pt; text-decoration: underline;
|
||||
}
|
||||
|
||||
.perlVersion {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #336699; font-size: 10pt; text-decoration: none;
|
||||
}
|
||||
|
||||
.podTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.docTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #000000; font-size: 10pt;
|
||||
}
|
||||
.dotDot {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #000000; font-size: 9pt;
|
||||
}
|
||||
|
||||
.docSec {
|
||||
font-family: Arial,Helvetica; font-weight: normal;
|
||||
color: #333333; font-size: 9pt;
|
||||
}
|
||||
.docVersion {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 10pt;
|
||||
}
|
||||
|
||||
.docSecs-on {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #ff0000; font-size: 10pt;
|
||||
}
|
||||
.docSecs-off {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #333333; font-size: 10pt;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: medium;
|
||||
}
|
||||
h1 {
|
||||
font-family: Verdana,Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: large;
|
||||
}
|
||||
|
||||
DL {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
|
||||
color: #333333; font-size: 10pt;
|
||||
}
|
||||
|
||||
UL > LI > A {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #336699; font-size: 10pt;
|
||||
}
|
||||
|
||||
.moduleInfo {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #333333; font-size: 11pt;
|
||||
}
|
||||
|
||||
.moduleInfoSec {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 10pt;
|
||||
}
|
||||
|
||||
.moduleInfoVal {
|
||||
font-family: Arial,Helvetica; font-weight: normal; text-decoration: underline;
|
||||
color: #000000; font-size: 10pt;
|
||||
}
|
||||
|
||||
.cpanNavTitle {
|
||||
font-family: Arial,Helvetica; font-weight: bold;
|
||||
color: #ffffff; font-size: 10pt;
|
||||
}
|
||||
.cpanNavLetter {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #333333; font-size: 9pt;
|
||||
}
|
||||
.cpanCat {
|
||||
font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
|
||||
color: #336699; font-size: 9pt;
|
||||
}
|
||||
|
||||
.bttndrkblue-bkgd-top {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgtop.gif);
|
||||
}
|
||||
.bttndrkblue-bkgd-left {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgleft.gif);
|
||||
}
|
||||
.bttndrkblue-bkgd {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgmiddle.gif);
|
||||
vertical-align: top;
|
||||
}
|
||||
.bttndrkblue-bkgd-right {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgright.gif);
|
||||
}
|
||||
.bttndrkblue-bkgd-bottom {
|
||||
background-color: #225688;
|
||||
background-image: url(/global/mvc_objects/images/bttndrkblue_bgbottom.gif);
|
||||
}
|
||||
.bttndrkblue-text a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.bttndrkblue-text:hover {
|
||||
color: #ffDD3C;
|
||||
text-decoration: none;
|
||||
}
|
||||
.bg-ltblue {
|
||||
background-color: #f0f5fa;
|
||||
}
|
||||
|
||||
.border-left-b {
|
||||
background: #f0f5fa url(/i/corner-leftline.gif) repeat-y;
|
||||
}
|
||||
|
||||
.border-right-b {
|
||||
background: #f0f5fa url(/i/corner-rightline.gif) repeat-y;
|
||||
}
|
||||
|
||||
.border-top-b {
|
||||
background: #f0f5fa url(/i/corner-topline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.border-bottom-b {
|
||||
background: #f0f5fa url(/i/corner-botline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.border-right-w {
|
||||
background: #ffffff url(/i/corner-rightline.gif) repeat-y;
|
||||
}
|
||||
|
||||
.border-top-w {
|
||||
background: #ffffff url(/i/corner-topline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.border-bottom-w {
|
||||
background: #ffffff url(/i/corner-botline.gif) repeat-x;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.border-left-w {
|
||||
background: #ffffff url(/i/corner-leftline.gif) repeat-y;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
if(NOT CLANG_BUILD_EXAMPLES)
|
||||
set(EXCLUDE_FROM_ALL ON)
|
||||
endif()
|
||||
|
||||
add_subdirectory(analyzer-plugin)
|
||||
add_subdirectory(clang-interpreter)
|
||||
add_subdirectory(PrintFunctionNames)
|
|
@ -0,0 +1,14 @@
|
|||
##===- examples/Makefile -----------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ..
|
||||
|
||||
PARALLEL_DIRS := analyzer-plugin clang-interpreter PrintFunctionNames
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
|
@ -0,0 +1,15 @@
|
|||
set(MODULE TRUE)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangFrontend
|
||||
clangAST
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(PrintFunctionNames PrintFunctionNames.cpp)
|
||||
|
||||
set_target_properties(PrintFunctionNames
|
||||
PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
PREFIX "")
|
|
@ -0,0 +1,28 @@
|
|||
##===- examples/PrintFunctionNames/Makefile ----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
LIBRARYNAME = PrintFunctionNames
|
||||
|
||||
# If we don't need RTTI or EH, there's no reason to export anything
|
||||
# from the plugin.
|
||||
ifneq ($(REQUIRES_RTTI), 1)
|
||||
ifneq ($(REQUIRES_EH), 1)
|
||||
EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/PrintFunctionNames.exports
|
||||
endif
|
||||
endif
|
||||
|
||||
LINK_LIBS_IN_SHARED = 0
|
||||
SHARED_LIBRARY = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
LDFLAGS=-Wl,-undefined,dynamic_lookup
|
||||
endif
|
|
@ -0,0 +1,71 @@
|
|||
//===- PrintFunctionNames.cpp ---------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Example clang plugin which simply prints the names of all the top-level decls
|
||||
// in the input file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Frontend/FrontendPluginRegistry.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
class PrintFunctionsConsumer : public ASTConsumer {
|
||||
public:
|
||||
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
|
||||
for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
|
||||
const Decl *D = *i;
|
||||
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
|
||||
llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class PrintFunctionNamesAction : public PluginASTAction {
|
||||
protected:
|
||||
ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) {
|
||||
return new PrintFunctionsConsumer();
|
||||
}
|
||||
|
||||
bool ParseArgs(const CompilerInstance &CI,
|
||||
const std::vector<std::string>& args) {
|
||||
for (unsigned i = 0, e = args.size(); i != e; ++i) {
|
||||
llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";
|
||||
|
||||
// Example error handling.
|
||||
if (args[i] == "-an-error") {
|
||||
DiagnosticsEngine &D = CI.getDiagnostics();
|
||||
unsigned DiagID = D.getCustomDiagID(
|
||||
DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
|
||||
D.Report(DiagID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (args.size() && args[0] == "help")
|
||||
PrintHelp(llvm::errs());
|
||||
|
||||
return true;
|
||||
}
|
||||
void PrintHelp(llvm::raw_ostream& ros) {
|
||||
ros << "Help for PrintFunctionNames plugin goes here\n";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
|
||||
X("print-fns", "print function names");
|
|
@ -0,0 +1 @@
|
|||
_ZN4llvm8Registry*
|
|
@ -0,0 +1,16 @@
|
|||
This is a simple example demonstrating how to use clang's facility for
|
||||
providing AST consumers using a plugin.
|
||||
|
||||
Build the plugin by running `make` in this directory.
|
||||
|
||||
Once the plugin is built, you can run it using:
|
||||
--
|
||||
Linux:
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
|
||||
|
||||
Mac:
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
|
|
@ -0,0 +1,14 @@
|
|||
set(MODULE TRUE)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangStaticAnalyzerCore
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(SampleAnalyzerPlugin MainCallChecker.cpp)
|
||||
|
||||
set_target_properties(SampleAnalyzerPlugin
|
||||
PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
PREFIX "")
|
|
@ -0,0 +1,53 @@
|
|||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class MainCallChecker : public Checker < check::PreStmt<CallExpr> > {
|
||||
mutable OwningPtr<BugType> BT;
|
||||
|
||||
public:
|
||||
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
|
||||
const ProgramStateRef state = C.getState();
|
||||
const LocationContext *LC = C.getLocationContext();
|
||||
const Expr *Callee = CE->getCallee();
|
||||
const FunctionDecl *FD = state->getSVal(Callee, LC).getAsFunctionDecl();
|
||||
|
||||
if (!FD)
|
||||
return;
|
||||
|
||||
// Get the name of the callee.
|
||||
IdentifierInfo *II = FD->getIdentifier();
|
||||
if (!II) // if no identifier, not a simple C function
|
||||
return;
|
||||
|
||||
if (II->isStr("main")) {
|
||||
ExplodedNode *N = C.generateSink();
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
if (!BT)
|
||||
BT.reset(new BugType("call to main", "example analyzer plugin"));
|
||||
|
||||
BugReport *report = new BugReport(*BT, BT->getName(), N);
|
||||
report->addRange(Callee->getSourceRange());
|
||||
C.EmitReport(report);
|
||||
}
|
||||
}
|
||||
|
||||
// Register plugin!
|
||||
extern "C"
|
||||
void clang_registerCheckers (CheckerRegistry ®istry) {
|
||||
registry.addChecker<MainCallChecker>("example.MainCallChecker", "Disallows calls to functions called main");
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char clang_analyzerAPIVersionString[] = CLANG_ANALYZER_API_VERSION_STRING;
|
|
@ -0,0 +1,20 @@
|
|||
##===- examples/analyzer-plugin/Makefile -------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
LIBRARYNAME = SampleAnalyzerPlugin
|
||||
|
||||
LINK_LIBS_IN_SHARED = 0
|
||||
LOADABLE_MODULE = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
LDFLAGS=-Wl,-undefined,dynamic_lookup
|
||||
endif
|
|
@ -0,0 +1,34 @@
|
|||
set(LLVM_USED_LIBS
|
||||
clangFrontend
|
||||
clangSerialization
|
||||
clangDriver
|
||||
clangCodeGen
|
||||
clangSema
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
clangAST
|
||||
clangParse
|
||||
clangLex
|
||||
clangBasic
|
||||
)
|
||||
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
jit
|
||||
interpreter
|
||||
nativecodegen
|
||||
asmparser
|
||||
bitreader
|
||||
bitwriter
|
||||
codegen
|
||||
ipo
|
||||
linker
|
||||
selectiondag
|
||||
)
|
||||
|
||||
add_clang_executable(clang-interpreter
|
||||
main.cpp
|
||||
)
|
||||
add_dependencies(clang-interpreter clang-headers)
|
|
@ -0,0 +1,26 @@
|
|||
##===- examples/clang-interpreter/Makefile -----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
|
||||
TOOLNAME = clang-interpreter
|
||||
NO_INSTALL = 1
|
||||
|
||||
# No plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
linker selectiondag asmparser instrumentation
|
||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
||||
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
|
||||
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
|
||||
clangAnalysis.a clangRewrite.a \
|
||||
clangEdit.a clangAST.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
|
@ -0,0 +1,17 @@
|
|||
This is an example of Clang based interpreter, for executing standalone C
|
||||
programs.
|
||||
|
||||
It demonstrates the following features:
|
||||
1. Parsing standard compiler command line arguments using the Driver library.
|
||||
|
||||
2. Constructing a Clang compiler instance, using the appropriate arguments
|
||||
derived in step #1.
|
||||
|
||||
3. Invoking the Clang compiler to lex, parse, syntax check, and then generate
|
||||
LLVM code.
|
||||
|
||||
4. Use the LLVM JIT functionality to execute the final module.
|
||||
|
||||
The implementation has many limitations and is not designed to be a full fledged
|
||||
C interpreter. It is designed to demonstrate a simple but functional use of the
|
||||
Clang compiler libraries.
|
|
@ -0,0 +1,156 @@
|
|||
//===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/CodeGen/CodeGenAction.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/DiagnosticOptions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
using namespace clang;
|
||||
using namespace clang::driver;
|
||||
|
||||
// This function isn't referenced outside its translation unit, but it
|
||||
// can't use the "static" keyword because its address is used for
|
||||
// GetMainExecutable (since some platforms don't support taking the
|
||||
// address of main, and some platforms can't implement GetMainExecutable
|
||||
// without being given the address of a function in the main executable).
|
||||
llvm::sys::Path GetExecutablePath(const char *Argv0) {
|
||||
// This just needs to be some symbol in the binary; C++ doesn't
|
||||
// allow taking the address of ::main however.
|
||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
|
||||
}
|
||||
|
||||
static int Execute(llvm::Module *Mod, char * const *envp) {
|
||||
llvm::InitializeNativeTarget();
|
||||
|
||||
std::string Error;
|
||||
OwningPtr<llvm::ExecutionEngine> EE(
|
||||
llvm::ExecutionEngine::createJIT(Mod, &Error));
|
||||
if (!EE) {
|
||||
llvm::errs() << "unable to make execution engine: " << Error << "\n";
|
||||
return 255;
|
||||
}
|
||||
|
||||
llvm::Function *EntryFn = Mod->getFunction("main");
|
||||
if (!EntryFn) {
|
||||
llvm::errs() << "'main' function not found in module.\n";
|
||||
return 255;
|
||||
}
|
||||
|
||||
// FIXME: Support passing arguments.
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back(Mod->getModuleIdentifier());
|
||||
|
||||
return EE->runFunctionAsMain(EntryFn, Args, envp);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv, char * const *envp) {
|
||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||
llvm::sys::Path Path = GetExecutablePath(argv[0]);
|
||||
TextDiagnosticPrinter *DiagClient =
|
||||
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
|
||||
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
DiagnosticsEngine Diags(DiagID, DiagClient);
|
||||
Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
|
||||
"a.out", /*IsProduction=*/false, Diags);
|
||||
TheDriver.setTitle("clang interpreter");
|
||||
|
||||
// FIXME: This is a hack to try to force the driver to do something we can
|
||||
// recognize. We need to extend the driver library to support this use model
|
||||
// (basically, exactly one input, and the operation mode is hard wired).
|
||||
llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
|
||||
Args.push_back("-fsyntax-only");
|
||||
OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
|
||||
if (!C)
|
||||
return 0;
|
||||
|
||||
// FIXME: This is copied from ASTUnit.cpp; simplify and eliminate.
|
||||
|
||||
// We expect to get back exactly one command job, if we didn't something
|
||||
// failed. Extract that job from the compilation.
|
||||
const driver::JobList &Jobs = C->getJobs();
|
||||
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
|
||||
SmallString<256> Msg;
|
||||
llvm::raw_svector_ostream OS(Msg);
|
||||
C->PrintJob(OS, C->getJobs(), "; ", true);
|
||||
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
|
||||
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
|
||||
Diags.Report(diag::err_fe_expected_clang_command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize a compiler invocation object from the clang (-cc1) arguments.
|
||||
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
||||
OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
|
||||
CompilerInvocation::CreateFromArgs(*CI,
|
||||
const_cast<const char **>(CCArgs.data()),
|
||||
const_cast<const char **>(CCArgs.data()) +
|
||||
CCArgs.size(),
|
||||
Diags);
|
||||
|
||||
// Show the invocation, with -v.
|
||||
if (CI->getHeaderSearchOpts().Verbose) {
|
||||
llvm::errs() << "clang invocation:\n";
|
||||
C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
|
||||
llvm::errs() << "\n";
|
||||
}
|
||||
|
||||
// FIXME: This is copied from cc1_main.cpp; simplify and eliminate.
|
||||
|
||||
// Create a compiler instance to handle the actual work.
|
||||
CompilerInstance Clang;
|
||||
Clang.setInvocation(CI.take());
|
||||
|
||||
// Create the compilers actual diagnostics engine.
|
||||
Clang.createDiagnostics(int(CCArgs.size()),const_cast<char**>(CCArgs.data()));
|
||||
if (!Clang.hasDiagnostics())
|
||||
return 1;
|
||||
|
||||
// Infer the builtin include path if unspecified.
|
||||
if (Clang.getHeaderSearchOpts().UseBuiltinIncludes &&
|
||||
Clang.getHeaderSearchOpts().ResourceDir.empty())
|
||||
Clang.getHeaderSearchOpts().ResourceDir =
|
||||
CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
|
||||
|
||||
// Create and execute the frontend to generate an LLVM bitcode module.
|
||||
OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
|
||||
if (!Clang.ExecuteAction(*Act))
|
||||
return 1;
|
||||
|
||||
int Res = 255;
|
||||
if (llvm::Module *Module = Act->takeModule())
|
||||
Res = Execute(Module, envp);
|
||||
|
||||
// Shutdown.
|
||||
|
||||
llvm::llvm_shutdown();
|
||||
|
||||
return Res;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(clang)
|
|
@ -0,0 +1,4 @@
|
|||
CLANG_LEVEL := ..
|
||||
DIRS := clang clang-c
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,38 @@
|
|||
CLANG_LEVEL := ../..
|
||||
DIRS :=
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
IntIncludeDir = $(DESTDIR)$(PROJ_internal_prefix)/include
|
||||
|
||||
install-local::
|
||||
$(Echo) Installing Clang C API include files
|
||||
$(Verb) $(MKDIR) $(IntIncludeDir)
|
||||
$(Verb) if test -d "$(PROJ_SRC_DIR)" ; then \
|
||||
cd $(PROJ_SRC_DIR)/.. && \
|
||||
for hdr in `find clang-c -type f '!' '(' -name '*~' \
|
||||
-o -name '.#*' -o -name '*.in' -o -name '*.txt' \
|
||||
-o -name 'Makefile' -o -name '*.td' ')' -print \
|
||||
| grep -v CVS | grep -v .svn | grep -v .dir` ; do \
|
||||
instdir=`dirname "$(IntIncludeDir)/$$hdr"` ; \
|
||||
if test \! -d "$$instdir" ; then \
|
||||
$(EchoCmd) Making install directory $$instdir ; \
|
||||
$(MKDIR) $$instdir ;\
|
||||
fi ; \
|
||||
$(DataInstall) $$hdr $(IntIncludeDir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
$(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include/clang-c" ; then \
|
||||
cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
|
||||
for hdr in `find clang-c -type f '!' '(' -name 'Makefile' ')' -print \
|
||||
| grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
|
||||
instdir=`dirname "$(IntIncludeDir)/$$hdr"` ; \
|
||||
if test \! -d "$$instdir" ; then \
|
||||
$(EchoCmd) Making install directory $$instdir ; \
|
||||
$(MKDIR) $$instdir ;\
|
||||
fi ; \
|
||||
$(DataInstall) $$hdr $(IntIncludeDir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
endif
|
|
@ -0,0 +1,122 @@
|
|||
//===-- ARCMT.h - ARC Migration Rewriter ------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_H
|
||||
#define LLVM_CLANG_ARCMIGRATE_ARCMT_H
|
||||
|
||||
#include "clang/ARCMigrate/FileRemapper.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class DiagnosticConsumer;
|
||||
|
||||
namespace arcmt {
|
||||
class MigrationPass;
|
||||
|
||||
/// \brief Creates an AST with the provided CompilerInvocation but with these
|
||||
/// changes:
|
||||
/// -if a PCH/PTH is set, the original header is used instead
|
||||
/// -Automatic Reference Counting mode is enabled
|
||||
///
|
||||
/// It then checks the AST and produces errors/warning for ARC migration issues
|
||||
/// that the user needs to handle manually.
|
||||
///
|
||||
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
|
||||
/// even if the migrator can fix them, but the function will still return false
|
||||
/// if all ARC errors can be fixed.
|
||||
///
|
||||
/// \param plistOut if non-empty, it is the file path to store the plist with
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool checkForManualIssues(CompilerInvocation &CI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
bool emitPremigrationARCErrors = false,
|
||||
StringRef plistOut = StringRef());
|
||||
|
||||
/// \brief Works similar to checkForManualIssues but instead of checking, it
|
||||
/// applies automatic modifications to source files to conform to ARC.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool applyTransformations(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
/// \brief Applies automatic modifications and produces temporary files
|
||||
/// and metadata into the \arg outputDir path.
|
||||
///
|
||||
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
|
||||
/// even if the migrator can fix them, but the function will still return false
|
||||
/// if all ARC errors can be fixed.
|
||||
///
|
||||
/// \param plistOut if non-empty, it is the file path to store the plist with
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
StringRef plistOut);
|
||||
|
||||
/// \brief Get the set of file remappings from the \arg outputDir path that
|
||||
/// migrateWithTemporaryFiles produced.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
|
||||
StringRef outputDir,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
/// \brief Get the set of file remappings from a list of files with remapping
|
||||
/// info.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool getFileRemappingsFromFileList(
|
||||
std::vector<std::pair<std::string,std::string> > &remap,
|
||||
ArrayRef<StringRef> remapFiles,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
typedef void (*TransformFn)(MigrationPass &pass);
|
||||
|
||||
std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode,
|
||||
bool NoFinalizeRemoval);
|
||||
|
||||
class MigrationProcess {
|
||||
CompilerInvocation OrigCI;
|
||||
DiagnosticConsumer *DiagClient;
|
||||
FileRemapper Remapper;
|
||||
|
||||
public:
|
||||
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
class RewriteListener {
|
||||
public:
|
||||
virtual ~RewriteListener();
|
||||
|
||||
virtual void start(ASTContext &Ctx) { }
|
||||
virtual void finish() { }
|
||||
|
||||
virtual void insert(SourceLocation loc, StringRef text) { }
|
||||
virtual void remove(CharSourceRange range) { }
|
||||
};
|
||||
|
||||
bool applyTransform(TransformFn trans, RewriteListener *listener = 0);
|
||||
|
||||
FileRemapper &getRemapper() { return Remapper; }
|
||||
};
|
||||
|
||||
} // end namespace arcmt
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
//===--- ARCMTActions.h - ARC Migrate Tool Frontend Actions -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
|
||||
#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
|
||||
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/ARCMigrate/FileRemapper.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
namespace clang {
|
||||
namespace arcmt {
|
||||
|
||||
class CheckAction : public WrapperFrontendAction {
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
|
||||
public:
|
||||
CheckAction(FrontendAction *WrappedAction);
|
||||
};
|
||||
|
||||
class ModifyAction : public WrapperFrontendAction {
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
|
||||
public:
|
||||
ModifyAction(FrontendAction *WrappedAction);
|
||||
};
|
||||
|
||||
class MigrateSourceAction : public ASTFrontendAction {
|
||||
FileRemapper Remapper;
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile);
|
||||
};
|
||||
|
||||
class MigrateAction : public WrapperFrontendAction {
|
||||
std::string MigrateDir;
|
||||
std::string PlistOut;
|
||||
bool EmitPremigrationARCErros;
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
|
||||
public:
|
||||
MigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
||||
StringRef plistOut,
|
||||
bool emitPremigrationARCErrors);
|
||||
};
|
||||
|
||||
/// \brief Migrates to modern ObjC syntax.
|
||||
class ObjCMigrateAction : public WrapperFrontendAction {
|
||||
std::string MigrateDir;
|
||||
bool MigrateLiterals;
|
||||
bool MigrateSubscripting;
|
||||
FileRemapper Remapper;
|
||||
CompilerInstance *CompInst;
|
||||
public:
|
||||
ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
||||
bool migrateLiterals,
|
||||
bool migrateSubscripting);
|
||||
|
||||
protected:
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,80 @@
|
|||
//===-- FileRemapper.h - File Remapping Helper ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
|
||||
#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class FileManager;
|
||||
class FileEntry;
|
||||
class DiagnosticsEngine;
|
||||
class PreprocessorOptions;
|
||||
|
||||
namespace arcmt {
|
||||
|
||||
class FileRemapper {
|
||||
// FIXME: Reuse the same FileManager for multiple ASTContexts.
|
||||
OwningPtr<FileManager> FileMgr;
|
||||
|
||||
typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target;
|
||||
typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy;
|
||||
MappingsTy FromToMappings;
|
||||
|
||||
llvm::DenseMap<const FileEntry *, const FileEntry *> ToFromMappings;
|
||||
|
||||
public:
|
||||
FileRemapper();
|
||||
~FileRemapper();
|
||||
|
||||
bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
|
||||
bool ignoreIfFilesChanged);
|
||||
bool initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
|
||||
bool ignoreIfFilesChanged);
|
||||
bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag);
|
||||
bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag);
|
||||
|
||||
bool overwriteOriginal(DiagnosticsEngine &Diag,
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
|
||||
void remap(StringRef filePath, StringRef newPath);
|
||||
|
||||
void applyMappings(PreprocessorOptions &PPOpts) const;
|
||||
|
||||
void transferMappingsAndClear(PreprocessorOptions &PPOpts);
|
||||
|
||||
void clear(StringRef outputDir = StringRef());
|
||||
|
||||
private:
|
||||
void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf);
|
||||
void remap(const FileEntry *file, const FileEntry *newfile);
|
||||
|
||||
const FileEntry *getOriginalFile(StringRef filePath);
|
||||
void resetTarget(Target &targ);
|
||||
|
||||
bool report(const Twine &err, DiagnosticsEngine &Diag);
|
||||
|
||||
std::string getRemapInfoFile(StringRef outputDir);
|
||||
};
|
||||
|
||||
} // end namespace arcmt
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,446 @@
|
|||
//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the APValue class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_APVALUE_H
|
||||
#define LLVM_CLANG_AST_APVALUE_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace clang {
|
||||
class AddrLabelExpr;
|
||||
class ASTContext;
|
||||
class CharUnits;
|
||||
class DiagnosticBuilder;
|
||||
class Expr;
|
||||
class FieldDecl;
|
||||
class Decl;
|
||||
class ValueDecl;
|
||||
class CXXRecordDecl;
|
||||
class QualType;
|
||||
|
||||
/// APValue - This class implements a discriminated union of [uninitialized]
|
||||
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
|
||||
/// [Vector: N * APValue], [Array: N * APValue]
|
||||
class APValue {
|
||||
typedef llvm::APSInt APSInt;
|
||||
typedef llvm::APFloat APFloat;
|
||||
public:
|
||||
enum ValueKind {
|
||||
Uninitialized,
|
||||
Int,
|
||||
Float,
|
||||
ComplexInt,
|
||||
ComplexFloat,
|
||||
LValue,
|
||||
Vector,
|
||||
Array,
|
||||
Struct,
|
||||
Union,
|
||||
MemberPointer,
|
||||
AddrLabelDiff
|
||||
};
|
||||
typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase;
|
||||
typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType;
|
||||
union LValuePathEntry {
|
||||
/// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item
|
||||
/// in the path. An opaque value of type BaseOrMemberType.
|
||||
void *BaseOrMember;
|
||||
/// ArrayIndex - The array index of the next item in the path.
|
||||
uint64_t ArrayIndex;
|
||||
};
|
||||
struct NoLValuePath {};
|
||||
struct UninitArray {};
|
||||
struct UninitStruct {};
|
||||
private:
|
||||
ValueKind Kind;
|
||||
|
||||
struct ComplexAPSInt {
|
||||
APSInt Real, Imag;
|
||||
ComplexAPSInt() : Real(1), Imag(1) {}
|
||||
};
|
||||
struct ComplexAPFloat {
|
||||
APFloat Real, Imag;
|
||||
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
|
||||
};
|
||||
struct LV;
|
||||
struct Vec {
|
||||
APValue *Elts;
|
||||
unsigned NumElts;
|
||||
Vec() : Elts(0), NumElts(0) {}
|
||||
~Vec() { delete[] Elts; }
|
||||
};
|
||||
struct Arr {
|
||||
APValue *Elts;
|
||||
unsigned NumElts, ArrSize;
|
||||
Arr(unsigned NumElts, unsigned ArrSize);
|
||||
~Arr();
|
||||
};
|
||||
struct StructData {
|
||||
APValue *Elts;
|
||||
unsigned NumBases;
|
||||
unsigned NumFields;
|
||||
StructData(unsigned NumBases, unsigned NumFields);
|
||||
~StructData();
|
||||
};
|
||||
struct UnionData {
|
||||
const FieldDecl *Field;
|
||||
APValue *Value;
|
||||
UnionData();
|
||||
~UnionData();
|
||||
};
|
||||
struct AddrLabelDiffData {
|
||||
const AddrLabelExpr* LHSExpr;
|
||||
const AddrLabelExpr* RHSExpr;
|
||||
};
|
||||
struct MemberPointerData;
|
||||
|
||||
enum {
|
||||
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
|
||||
sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat))
|
||||
};
|
||||
|
||||
union {
|
||||
void *Aligner;
|
||||
char Data[MaxSize];
|
||||
};
|
||||
|
||||
public:
|
||||
APValue() : Kind(Uninitialized) {}
|
||||
explicit APValue(const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeInt(); setInt(I);
|
||||
}
|
||||
explicit APValue(const APFloat &F) : Kind(Uninitialized) {
|
||||
MakeFloat(); setFloat(F);
|
||||
}
|
||||
explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) {
|
||||
MakeVector(); setVector(E, N);
|
||||
}
|
||||
APValue(const APSInt &R, const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeComplexInt(); setComplexInt(R, I);
|
||||
}
|
||||
APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) {
|
||||
MakeComplexFloat(); setComplexFloat(R, I);
|
||||
}
|
||||
APValue(const APValue &RHS);
|
||||
APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex)
|
||||
: Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O, N, CallIndex);
|
||||
}
|
||||
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
|
||||
bool OnePastTheEnd, unsigned CallIndex)
|
||||
: Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex);
|
||||
}
|
||||
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
|
||||
MakeArray(InitElts, Size);
|
||||
}
|
||||
APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) {
|
||||
MakeStruct(B, M);
|
||||
}
|
||||
explicit APValue(const FieldDecl *D, const APValue &V = APValue())
|
||||
: Kind(Uninitialized) {
|
||||
MakeUnion(); setUnion(D, V);
|
||||
}
|
||||
APValue(const ValueDecl *Member, bool IsDerivedMember,
|
||||
ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) {
|
||||
MakeMemberPointer(Member, IsDerivedMember, Path);
|
||||
}
|
||||
APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr)
|
||||
: Kind(Uninitialized) {
|
||||
MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr);
|
||||
}
|
||||
|
||||
~APValue() {
|
||||
MakeUninit();
|
||||
}
|
||||
|
||||
/// \brief Swaps the contents of this and the given APValue.
|
||||
void swap(APValue &RHS);
|
||||
|
||||
ValueKind getKind() const { return Kind; }
|
||||
bool isUninit() const { return Kind == Uninitialized; }
|
||||
bool isInt() const { return Kind == Int; }
|
||||
bool isFloat() const { return Kind == Float; }
|
||||
bool isComplexInt() const { return Kind == ComplexInt; }
|
||||
bool isComplexFloat() const { return Kind == ComplexFloat; }
|
||||
bool isLValue() const { return Kind == LValue; }
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
bool isArray() const { return Kind == Array; }
|
||||
bool isStruct() const { return Kind == Struct; }
|
||||
bool isUnion() const { return Kind == Union; }
|
||||
bool isMemberPointer() const { return Kind == MemberPointer; }
|
||||
bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; }
|
||||
|
||||
void dump() const;
|
||||
void dump(raw_ostream &OS) const;
|
||||
|
||||
void printPretty(raw_ostream &OS, ASTContext &Ctx, QualType Ty) const;
|
||||
std::string getAsString(ASTContext &Ctx, QualType Ty) const;
|
||||
|
||||
APSInt &getInt() {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
return *(APSInt*)(char*)Data;
|
||||
}
|
||||
const APSInt &getInt() const {
|
||||
return const_cast<APValue*>(this)->getInt();
|
||||
}
|
||||
|
||||
APFloat &getFloat() {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
return *(APFloat*)(char*)Data;
|
||||
}
|
||||
const APFloat &getFloat() const {
|
||||
return const_cast<APValue*>(this)->getFloat();
|
||||
}
|
||||
|
||||
APSInt &getComplexIntReal() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(char*)Data)->Real;
|
||||
}
|
||||
const APSInt &getComplexIntReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntReal();
|
||||
}
|
||||
|
||||
APSInt &getComplexIntImag() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(char*)Data)->Imag;
|
||||
}
|
||||
const APSInt &getComplexIntImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntImag();
|
||||
}
|
||||
|
||||
APFloat &getComplexFloatReal() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(char*)Data)->Real;
|
||||
}
|
||||
const APFloat &getComplexFloatReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatReal();
|
||||
}
|
||||
|
||||
APFloat &getComplexFloatImag() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(char*)Data)->Imag;
|
||||
}
|
||||
const APFloat &getComplexFloatImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
}
|
||||
|
||||
const LValueBase getLValueBase() const;
|
||||
CharUnits &getLValueOffset();
|
||||
const CharUnits &getLValueOffset() const {
|
||||
return const_cast<APValue*>(this)->getLValueOffset();
|
||||
}
|
||||
bool isLValueOnePastTheEnd() const;
|
||||
bool hasLValuePath() const;
|
||||
ArrayRef<LValuePathEntry> getLValuePath() const;
|
||||
unsigned getLValueCallIndex() const;
|
||||
|
||||
APValue &getVectorElt(unsigned I) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
assert(I < getVectorLength() && "Index out of range");
|
||||
return ((Vec*)(char*)Data)->Elts[I];
|
||||
}
|
||||
const APValue &getVectorElt(unsigned I) const {
|
||||
return const_cast<APValue*>(this)->getVectorElt(I);
|
||||
}
|
||||
unsigned getVectorLength() const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((const Vec*)(const void *)Data)->NumElts;
|
||||
}
|
||||
|
||||
APValue &getArrayInitializedElt(unsigned I) {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
assert(I < getArrayInitializedElts() && "Index out of range");
|
||||
return ((Arr*)(char*)Data)->Elts[I];
|
||||
}
|
||||
const APValue &getArrayInitializedElt(unsigned I) const {
|
||||
return const_cast<APValue*>(this)->getArrayInitializedElt(I);
|
||||
}
|
||||
bool hasArrayFiller() const {
|
||||
return getArrayInitializedElts() != getArraySize();
|
||||
}
|
||||
APValue &getArrayFiller() {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
assert(hasArrayFiller() && "No array filler");
|
||||
return ((Arr*)(char*)Data)->Elts[getArrayInitializedElts()];
|
||||
}
|
||||
const APValue &getArrayFiller() const {
|
||||
return const_cast<APValue*>(this)->getArrayFiller();
|
||||
}
|
||||
unsigned getArrayInitializedElts() const {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
return ((const Arr*)(const void *)Data)->NumElts;
|
||||
}
|
||||
unsigned getArraySize() const {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
return ((const Arr*)(const void *)Data)->ArrSize;
|
||||
}
|
||||
|
||||
unsigned getStructNumBases() const {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((const StructData*)(const char*)Data)->NumBases;
|
||||
}
|
||||
unsigned getStructNumFields() const {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((const StructData*)(const char*)Data)->NumFields;
|
||||
}
|
||||
APValue &getStructBase(unsigned i) {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((StructData*)(char*)Data)->Elts[i];
|
||||
}
|
||||
APValue &getStructField(unsigned i) {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((StructData*)(char*)Data)->Elts[getStructNumBases() + i];
|
||||
}
|
||||
const APValue &getStructBase(unsigned i) const {
|
||||
return const_cast<APValue*>(this)->getStructBase(i);
|
||||
}
|
||||
const APValue &getStructField(unsigned i) const {
|
||||
return const_cast<APValue*>(this)->getStructField(i);
|
||||
}
|
||||
|
||||
const FieldDecl *getUnionField() const {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
return ((const UnionData*)(const char*)Data)->Field;
|
||||
}
|
||||
APValue &getUnionValue() {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
return *((UnionData*)(char*)Data)->Value;
|
||||
}
|
||||
const APValue &getUnionValue() const {
|
||||
return const_cast<APValue*>(this)->getUnionValue();
|
||||
}
|
||||
|
||||
const ValueDecl *getMemberPointerDecl() const;
|
||||
bool isMemberPointerToDerivedMember() const;
|
||||
ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const;
|
||||
|
||||
const AddrLabelExpr* getAddrLabelDiffLHS() const {
|
||||
assert(isAddrLabelDiff() && "Invalid accessor");
|
||||
return ((const AddrLabelDiffData*)(const char*)Data)->LHSExpr;
|
||||
}
|
||||
const AddrLabelExpr* getAddrLabelDiffRHS() const {
|
||||
assert(isAddrLabelDiff() && "Invalid accessor");
|
||||
return ((const AddrLabelDiffData*)(const char*)Data)->RHSExpr;
|
||||
}
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
*(APSInt*)(char*)Data = I;
|
||||
}
|
||||
void setFloat(const APFloat &F) {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
*(APFloat*)(char*)Data = F;
|
||||
}
|
||||
void setVector(const APValue *E, unsigned N) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
((Vec*)(char*)Data)->Elts = new APValue[N];
|
||||
((Vec*)(char*)Data)->NumElts = N;
|
||||
for (unsigned i = 0; i != N; ++i)
|
||||
((Vec*)(char*)Data)->Elts[i] = E[i];
|
||||
}
|
||||
void setComplexInt(const APSInt &R, const APSInt &I) {
|
||||
assert(R.getBitWidth() == I.getBitWidth() &&
|
||||
"Invalid complex int (type mismatch).");
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
((ComplexAPSInt*)(char*)Data)->Real = R;
|
||||
((ComplexAPSInt*)(char*)Data)->Imag = I;
|
||||
}
|
||||
void setComplexFloat(const APFloat &R, const APFloat &I) {
|
||||
assert(&R.getSemantics() == &I.getSemantics() &&
|
||||
"Invalid complex float (type mismatch).");
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
((ComplexAPFloat*)(char*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(char*)Data)->Imag = I;
|
||||
}
|
||||
void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
|
||||
unsigned CallIndex);
|
||||
void setLValue(LValueBase B, const CharUnits &O,
|
||||
ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
|
||||
unsigned CallIndex);
|
||||
void setUnion(const FieldDecl *Field, const APValue &Value) {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
((UnionData*)(char*)Data)->Field = Field;
|
||||
*((UnionData*)(char*)Data)->Value = Value;
|
||||
}
|
||||
void setAddrLabelDiff(const AddrLabelExpr* LHSExpr,
|
||||
const AddrLabelExpr* RHSExpr) {
|
||||
((AddrLabelDiffData*)(char*)Data)->LHSExpr = LHSExpr;
|
||||
((AddrLabelDiffData*)(char*)Data)->RHSExpr = RHSExpr;
|
||||
}
|
||||
|
||||
/// Assign by swapping from a copy of the RHS.
|
||||
APValue &operator=(APValue RHS) {
|
||||
swap(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void DestroyDataAndMakeUninit();
|
||||
void MakeUninit() {
|
||||
if (Kind != Uninitialized)
|
||||
DestroyDataAndMakeUninit();
|
||||
}
|
||||
void MakeInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)Data) APSInt(1);
|
||||
Kind = Int;
|
||||
}
|
||||
void MakeFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) APFloat(0.0);
|
||||
Kind = Float;
|
||||
}
|
||||
void MakeVector() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) Vec();
|
||||
Kind = Vector;
|
||||
}
|
||||
void MakeComplexInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) ComplexAPSInt();
|
||||
Kind = ComplexInt;
|
||||
}
|
||||
void MakeComplexFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) ComplexAPFloat();
|
||||
Kind = ComplexFloat;
|
||||
}
|
||||
void MakeLValue();
|
||||
void MakeArray(unsigned InitElts, unsigned Size);
|
||||
void MakeStruct(unsigned B, unsigned M) {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) StructData(B, M);
|
||||
Kind = Struct;
|
||||
}
|
||||
void MakeUnion() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) UnionData();
|
||||
Kind = Union;
|
||||
}
|
||||
void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
|
||||
ArrayRef<const CXXRecordDecl*> Path);
|
||||
void MakeAddrLabelDiff() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) AddrLabelDiffData();
|
||||
Kind = AddrLabelDiff;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
//===--- AST.h - "Umbrella" header for AST library --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface to the AST classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_AST_H
|
||||
#define LLVM_CLANG_AST_AST_H
|
||||
|
||||
// This header exports all AST interfaces.
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,128 @@
|
|||
//===--- ASTConsumer.h - Abstract interface for reading ASTs ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ASTConsumer class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
#define LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class DeclGroupRef;
|
||||
class HandleTagDeclDefinition;
|
||||
class ASTMutationListener;
|
||||
class ASTDeserializationListener; // layering violation because void* is ugly
|
||||
class SemaConsumer; // layering violation required for safe SemaConsumer
|
||||
class TagDecl;
|
||||
class VarDecl;
|
||||
class FunctionDecl;
|
||||
|
||||
/// ASTConsumer - This is an abstract interface that should be implemented by
|
||||
/// clients that read ASTs. This abstraction layer allows the client to be
|
||||
/// independent of the AST producer (e.g. parser vs AST dump file reader, etc).
|
||||
class ASTConsumer {
|
||||
/// \brief Whether this AST consumer also requires information about
|
||||
/// semantic analysis.
|
||||
bool SemaConsumer;
|
||||
|
||||
friend class SemaConsumer;
|
||||
|
||||
public:
|
||||
ASTConsumer() : SemaConsumer(false) { }
|
||||
|
||||
virtual ~ASTConsumer() {}
|
||||
|
||||
/// Initialize - This is called to initialize the consumer, providing the
|
||||
/// ASTContext.
|
||||
virtual void Initialize(ASTContext &Context) {}
|
||||
|
||||
/// HandleTopLevelDecl - Handle the specified top-level declaration. This is
|
||||
/// called by the parser to process every top-level Decl*. Note that D can be
|
||||
/// the head of a chain of Decls (e.g. for `int a, b` the chain will have two
|
||||
/// elements). Use Decl::getNextDeclarator() to walk the chain.
|
||||
///
|
||||
/// \returns true to continue parsing, or false to abort parsing.
|
||||
virtual bool HandleTopLevelDecl(DeclGroupRef D);
|
||||
|
||||
/// HandleInterestingDecl - Handle the specified interesting declaration. This
|
||||
/// is called by the AST reader when deserializing things that might interest
|
||||
/// the consumer. The default implementation forwards to HandleTopLevelDecl.
|
||||
virtual void HandleInterestingDecl(DeclGroupRef D);
|
||||
|
||||
/// HandleTranslationUnit - This method is called when the ASTs for entire
|
||||
/// translation unit have been parsed.
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx) {}
|
||||
|
||||
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
|
||||
/// (e.g. struct, union, enum, class) is completed. This allows the client to
|
||||
/// hack on the type, which can occur at any point in the file (because these
|
||||
/// can be defined in declspecs).
|
||||
virtual void HandleTagDeclDefinition(TagDecl *D) {}
|
||||
|
||||
/// \brief Invoked when a function is implicitly instantiated.
|
||||
/// Note that at this point point it does not have a body, its body is
|
||||
/// instantiated at the end of the translation unit and passed to
|
||||
/// HandleTopLevelDecl.
|
||||
virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {}
|
||||
|
||||
/// \brief Handle the specified top-level declaration that occurred inside
|
||||
/// and ObjC container.
|
||||
/// The default implementation ignored them.
|
||||
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
|
||||
|
||||
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
|
||||
/// unit to notify the consumer that the given tentative definition should be
|
||||
/// completed.
|
||||
///
|
||||
/// The variable declaration itself will be a tentative
|
||||
/// definition. If it had an incomplete array type, its type will
|
||||
/// have already been changed to an array of size 1. However, the
|
||||
/// declaration remains a tentative definition and has not been
|
||||
/// modified by the introduction of an implicit zero initializer.
|
||||
virtual void CompleteTentativeDefinition(VarDecl *D) {}
|
||||
|
||||
/// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this
|
||||
// variable has been instantiated.
|
||||
virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *D) {}
|
||||
|
||||
/// \brief Callback involved at the end of a translation unit to
|
||||
/// notify the consumer that a vtable for the given C++ class is
|
||||
/// required.
|
||||
///
|
||||
/// \param RD The class whose vtable was used.
|
||||
///
|
||||
/// \param DefinitionRequired Whether a definition of this vtable is
|
||||
/// required in this translation unit; otherwise, it is only needed if
|
||||
/// it was actually used.
|
||||
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
|
||||
|
||||
/// \brief If the consumer is interested in entities getting modified after
|
||||
/// their initial creation, it should return a pointer to
|
||||
/// an ASTMutationListener here.
|
||||
virtual ASTMutationListener *GetASTMutationListener() { return 0; }
|
||||
|
||||
/// \brief If the consumer is interested in entities being deserialized from
|
||||
/// AST files, it should return a pointer to a ASTDeserializationListener here
|
||||
virtual ASTDeserializationListener *GetASTDeserializationListener() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// PrintStats - If desired, print any statistics.
|
||||
virtual void PrintStats() {}
|
||||
|
||||
// Support isa/cast/dyn_cast
|
||||
static bool classof(const ASTConsumer *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,50 @@
|
|||
//===--- ASTDiagnostic.h - Diagnostics for the AST library ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTICAST_H
|
||||
#define LLVM_CLANG_DIAGNOSTICAST_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||
#undef DIAG
|
||||
NUM_BUILTIN_AST_DIAGNOSTICS
|
||||
};
|
||||
} // end namespace diag
|
||||
|
||||
/// \brief DiagnosticsEngine argument formatting function for diagnostics that
|
||||
/// involve AST nodes.
|
||||
///
|
||||
/// This function formats diagnostic arguments for various AST nodes,
|
||||
/// including types, declaration names, nested name specifiers, and
|
||||
/// declaration contexts, into strings that can be printed as part of
|
||||
/// diagnostics. It is meant to be used as the argument to
|
||||
/// \c DiagnosticsEngine::SetArgToStringFn(), where the cookie is an \c
|
||||
/// ASTContext pointer.
|
||||
void FormatASTNodeDiagnosticArgument(
|
||||
DiagnosticsEngine::ArgumentKind Kind,
|
||||
intptr_t Val,
|
||||
const char *Modifier,
|
||||
unsigned ModLen,
|
||||
const char *Argument,
|
||||
unsigned ArgLen,
|
||||
const DiagnosticsEngine::ArgumentValue *PrevArgs,
|
||||
unsigned NumPrevArgs,
|
||||
SmallVectorImpl<char> &Output,
|
||||
void *Cookie,
|
||||
ArrayRef<intptr_t> QualTypeVals);
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,278 @@
|
|||
//===--- ASTImporter.h - Importing ASTs from other Contexts -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ASTImporter class which imports AST nodes from one
|
||||
// context into another context.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_ASTIMPORTER_H
|
||||
#define LLVM_CLANG_AST_ASTIMPORTER_H
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class DiagnosticsEngine;
|
||||
class Expr;
|
||||
class FileManager;
|
||||
class IdentifierInfo;
|
||||
class NestedNameSpecifier;
|
||||
class Stmt;
|
||||
class TypeSourceInfo;
|
||||
|
||||
/// \brief Imports selected nodes from one AST context into another context,
|
||||
/// merging AST nodes where appropriate.
|
||||
class ASTImporter {
|
||||
public:
|
||||
typedef llvm::DenseSet<std::pair<Decl *, Decl *> > NonEquivalentDeclSet;
|
||||
|
||||
private:
|
||||
/// \brief The contexts we're importing to and from.
|
||||
ASTContext &ToContext, &FromContext;
|
||||
|
||||
/// \brief The file managers we're importing to and from.
|
||||
FileManager &ToFileManager, &FromFileManager;
|
||||
|
||||
/// \brief Whether to perform a minimal import.
|
||||
bool Minimal;
|
||||
|
||||
/// \brief Mapping from the already-imported types in the "from" context
|
||||
/// to the corresponding types in the "to" context.
|
||||
llvm::DenseMap<const Type *, const Type *> ImportedTypes;
|
||||
|
||||
/// \brief Mapping from the already-imported declarations in the "from"
|
||||
/// context to the corresponding declarations in the "to" context.
|
||||
llvm::DenseMap<Decl *, Decl *> ImportedDecls;
|
||||
|
||||
/// \brief Mapping from the already-imported statements in the "from"
|
||||
/// context to the corresponding statements in the "to" context.
|
||||
llvm::DenseMap<Stmt *, Stmt *> ImportedStmts;
|
||||
|
||||
/// \brief Mapping from the already-imported FileIDs in the "from" source
|
||||
/// manager to the corresponding FileIDs in the "to" source manager.
|
||||
llvm::DenseMap<FileID, FileID> ImportedFileIDs;
|
||||
|
||||
/// \brief Imported, anonymous tag declarations that are missing their
|
||||
/// corresponding typedefs.
|
||||
SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
|
||||
|
||||
/// \brief Declaration (from, to) pairs that are known not to be equivalent
|
||||
/// (which we have already complained about).
|
||||
NonEquivalentDeclSet NonEquivalentDecls;
|
||||
|
||||
public:
|
||||
/// \brief Create a new AST importer.
|
||||
///
|
||||
/// \param ToContext The context we'll be importing into.
|
||||
///
|
||||
/// \param ToFileManager The file manager we'll be importing into.
|
||||
///
|
||||
/// \param FromContext The context we'll be importing from.
|
||||
///
|
||||
/// \param FromFileManager The file manager we'll be importing into.
|
||||
///
|
||||
/// \param MinimalImport If true, the importer will attempt to import
|
||||
/// as little as it can, e.g., by importing declarations as forward
|
||||
/// declarations that can be completed at a later point.
|
||||
ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
|
||||
ASTContext &FromContext, FileManager &FromFileManager,
|
||||
bool MinimalImport);
|
||||
|
||||
virtual ~ASTImporter();
|
||||
|
||||
/// \brief Whether the importer will perform a minimal import, creating
|
||||
/// to-be-completed forward declarations when possible.
|
||||
bool isMinimalImport() const { return Minimal; }
|
||||
|
||||
/// \brief Import the given type from the "from" context into the "to"
|
||||
/// context.
|
||||
///
|
||||
/// \returns the equivalent type in the "to" context, or a NULL type if
|
||||
/// an error occurred.
|
||||
QualType Import(QualType FromT);
|
||||
|
||||
/// \brief Import the given type source information from the
|
||||
/// "from" context into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent type source information in the "to"
|
||||
/// context, or NULL if an error occurred.
|
||||
TypeSourceInfo *Import(TypeSourceInfo *FromTSI);
|
||||
|
||||
/// \brief Import the given declaration from the "from" context into the
|
||||
/// "to" context.
|
||||
///
|
||||
/// \returns the equivalent declaration in the "to" context, or a NULL type
|
||||
/// if an error occurred.
|
||||
Decl *Import(Decl *FromD);
|
||||
|
||||
/// \brief Import the given declaration context from the "from"
|
||||
/// AST context into the "to" AST context.
|
||||
///
|
||||
/// \returns the equivalent declaration context in the "to"
|
||||
/// context, or a NULL type if an error occurred.
|
||||
DeclContext *ImportContext(DeclContext *FromDC);
|
||||
|
||||
/// \brief Import the given expression from the "from" context into the
|
||||
/// "to" context.
|
||||
///
|
||||
/// \returns the equivalent expression in the "to" context, or NULL if
|
||||
/// an error occurred.
|
||||
Expr *Import(Expr *FromE);
|
||||
|
||||
/// \brief Import the given statement from the "from" context into the
|
||||
/// "to" context.
|
||||
///
|
||||
/// \returns the equivalent statement in the "to" context, or NULL if
|
||||
/// an error occurred.
|
||||
Stmt *Import(Stmt *FromS);
|
||||
|
||||
/// \brief Import the given nested-name-specifier from the "from"
|
||||
/// context into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent nested-name-specifier in the "to"
|
||||
/// context, or NULL if an error occurred.
|
||||
NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS);
|
||||
|
||||
/// \brief Import the given nested-name-specifier from the "from"
|
||||
/// context into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent nested-name-specifier in the "to"
|
||||
/// context.
|
||||
NestedNameSpecifierLoc Import(NestedNameSpecifierLoc FromNNS);
|
||||
|
||||
/// \brief Import the goven template name from the "from" context into the
|
||||
/// "to" context.
|
||||
TemplateName Import(TemplateName From);
|
||||
|
||||
/// \brief Import the given source location from the "from" context into
|
||||
/// the "to" context.
|
||||
///
|
||||
/// \returns the equivalent source location in the "to" context, or an
|
||||
/// invalid source location if an error occurred.
|
||||
SourceLocation Import(SourceLocation FromLoc);
|
||||
|
||||
/// \brief Import the given source range from the "from" context into
|
||||
/// the "to" context.
|
||||
///
|
||||
/// \returns the equivalent source range in the "to" context, or an
|
||||
/// invalid source location if an error occurred.
|
||||
SourceRange Import(SourceRange FromRange);
|
||||
|
||||
/// \brief Import the given declaration name from the "from"
|
||||
/// context into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent declaration name in the "to" context,
|
||||
/// or an empty declaration name if an error occurred.
|
||||
DeclarationName Import(DeclarationName FromName);
|
||||
|
||||
/// \brief Import the given identifier from the "from" context
|
||||
/// into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent identifier in the "to" context.
|
||||
IdentifierInfo *Import(const IdentifierInfo *FromId);
|
||||
|
||||
/// \brief Import the given Objective-C selector from the "from"
|
||||
/// context into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent selector in the "to" context.
|
||||
Selector Import(Selector FromSel);
|
||||
|
||||
/// \brief Import the given file ID from the "from" context into the
|
||||
/// "to" context.
|
||||
///
|
||||
/// \returns the equivalent file ID in the source manager of the "to"
|
||||
/// context.
|
||||
FileID Import(FileID);
|
||||
|
||||
/// \brief Import the definition of the given declaration, including all of
|
||||
/// the declarations it contains.
|
||||
///
|
||||
/// This routine is intended to be used
|
||||
void ImportDefinition(Decl *From);
|
||||
|
||||
/// \brief Cope with a name conflict when importing a declaration into the
|
||||
/// given context.
|
||||
///
|
||||
/// This routine is invoked whenever there is a name conflict while
|
||||
/// importing a declaration. The returned name will become the name of the
|
||||
/// imported declaration. By default, the returned name is the same as the
|
||||
/// original name, leaving the conflict unresolve such that name lookup
|
||||
/// for this name is likely to find an ambiguity later.
|
||||
///
|
||||
/// Subclasses may override this routine to resolve the conflict, e.g., by
|
||||
/// renaming the declaration being imported.
|
||||
///
|
||||
/// \param Name the name of the declaration being imported, which conflicts
|
||||
/// with other declarations.
|
||||
///
|
||||
/// \param DC the declaration context (in the "to" AST context) in which
|
||||
/// the name is being imported.
|
||||
///
|
||||
/// \param IDNS the identifier namespace in which the name will be found.
|
||||
///
|
||||
/// \param Decls the set of declarations with the same name as the
|
||||
/// declaration being imported.
|
||||
///
|
||||
/// \param NumDecls the number of conflicting declarations in \p Decls.
|
||||
///
|
||||
/// \returns the name that the newly-imported declaration should have.
|
||||
virtual DeclarationName HandleNameConflict(DeclarationName Name,
|
||||
DeclContext *DC,
|
||||
unsigned IDNS,
|
||||
NamedDecl **Decls,
|
||||
unsigned NumDecls);
|
||||
|
||||
/// \brief Retrieve the context that AST nodes are being imported into.
|
||||
ASTContext &getToContext() const { return ToContext; }
|
||||
|
||||
/// \brief Retrieve the context that AST nodes are being imported from.
|
||||
ASTContext &getFromContext() const { return FromContext; }
|
||||
|
||||
/// \brief Retrieve the file manager that AST nodes are being imported into.
|
||||
FileManager &getToFileManager() const { return ToFileManager; }
|
||||
|
||||
/// \brief Retrieve the file manager that AST nodes are being imported from.
|
||||
FileManager &getFromFileManager() const { return FromFileManager; }
|
||||
|
||||
/// \brief Report a diagnostic in the "to" context.
|
||||
DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID);
|
||||
|
||||
/// \brief Report a diagnostic in the "from" context.
|
||||
DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID);
|
||||
|
||||
/// \brief Return the set of declarations that we know are not equivalent.
|
||||
NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; }
|
||||
|
||||
/// \brief Called for ObjCInterfaceDecl, ObjCProtocolDecl, and TagDecl.
|
||||
/// Mark the Decl as complete, filling it in as much as possible.
|
||||
///
|
||||
/// \param D A declaration in the "to" context.
|
||||
virtual void CompleteDecl(Decl* D);
|
||||
|
||||
/// \brief Note that we have imported the "from" declaration by mapping it
|
||||
/// to the (potentially-newly-created) "to" declaration.
|
||||
///
|
||||
/// Subclasses can override this function to observe all of the \c From ->
|
||||
/// \c To declaration mappings as they are imported.
|
||||
virtual Decl *Imported(Decl *From, Decl *To);
|
||||
|
||||
/// \brief Determine whether the given types are structurally
|
||||
/// equivalent.
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_AST_ASTIMPORTER_H
|
|
@ -0,0 +1,84 @@
|
|||
//===--- ASTMutationListener.h - AST Mutation Interface --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ASTMutationListener interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class TagDecl;
|
||||
class CXXRecordDecl;
|
||||
class ClassTemplateDecl;
|
||||
class ClassTemplateSpecializationDecl;
|
||||
class FunctionDecl;
|
||||
class FunctionTemplateDecl;
|
||||
class ObjCCategoryDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCContainerDecl;
|
||||
class ObjCPropertyDecl;
|
||||
|
||||
/// \brief An abstract interface that should be implemented by listeners
|
||||
/// that want to be notified when an AST entity gets modified after its
|
||||
/// initial creation.
|
||||
class ASTMutationListener {
|
||||
public:
|
||||
virtual ~ASTMutationListener();
|
||||
|
||||
/// \brief A new TagDecl definition was completed.
|
||||
virtual void CompletedTagDefinition(const TagDecl *D) { }
|
||||
|
||||
/// \brief A new declaration with name has been added to a DeclContext.
|
||||
virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D) {}
|
||||
|
||||
/// \brief An implicit member was added after the definition was completed.
|
||||
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {}
|
||||
|
||||
/// \brief A template specialization (or partial one) was added to the
|
||||
/// template declaration.
|
||||
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
|
||||
const ClassTemplateSpecializationDecl *D) {}
|
||||
|
||||
/// \brief A template specialization (or partial one) was added to the
|
||||
/// template declaration.
|
||||
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
|
||||
const FunctionDecl *D) {}
|
||||
|
||||
/// \brief An implicit member got a definition.
|
||||
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
|
||||
|
||||
/// \brief A static data member was implicitly instantiated.
|
||||
virtual void StaticDataMemberInstantiated(const VarDecl *D) {}
|
||||
|
||||
/// \brief A new objc category class was added for an interface.
|
||||
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
|
||||
const ObjCInterfaceDecl *IFD) {}
|
||||
|
||||
/// \brief A objc class extension redeclared or introduced a property.
|
||||
///
|
||||
/// \param Prop the property in the class extension
|
||||
///
|
||||
/// \param OrigProp the property from the original interface that was declared
|
||||
/// or null if the property was introduced.
|
||||
///
|
||||
/// \param ClassExt the class extension.
|
||||
virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
|
||||
const ObjCPropertyDecl *OrigProp,
|
||||
const ObjCCategoryDecl *ClassExt) {}
|
||||
|
||||
// NOTE: If new methods are added they should also be added to
|
||||
// MultiplexASTMutationListener.
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,397 @@
|
|||
//===- ASTVector.h - Vector that uses ASTContext for allocation --*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides ASTVector, a vector ADT whose contents are
|
||||
// allocated using the allocator associated with an ASTContext..
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h.
|
||||
// We can refactor this core logic into something common.
|
||||
|
||||
#ifndef LLVM_CLANG_AST_VECTOR
|
||||
#define LLVM_CLANG_AST_VECTOR
|
||||
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
namespace std {
|
||||
#if _MSC_VER <= 1310
|
||||
// Work around flawed VC++ implementation of std::uninitialized_copy. Define
|
||||
// additional overloads so that elements with pointer types are recognized as
|
||||
// scalars and not objects, causing bizarre type conversion errors.
|
||||
template<class T1, class T2>
|
||||
inline _Scalar_ptr_iterator_tag _Ptr_cat(T1 **, T2 **) {
|
||||
_Scalar_ptr_iterator_tag _Cat;
|
||||
return _Cat;
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
inline _Scalar_ptr_iterator_tag _Ptr_cat(T1* const *, T2 **) {
|
||||
_Scalar_ptr_iterator_tag _Cat;
|
||||
return _Cat;
|
||||
}
|
||||
#else
|
||||
// FIXME: It is not clear if the problem is fixed in VS 2005. What is clear
|
||||
// is that the above hack won't work if it wasn't fixed.
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace clang {
|
||||
|
||||
template<typename T>
|
||||
class ASTVector {
|
||||
T *Begin, *End, *Capacity;
|
||||
|
||||
void setEnd(T *P) { this->End = P; }
|
||||
|
||||
public:
|
||||
// Default ctor - Initialize to empty.
|
||||
explicit ASTVector(ASTContext &C, unsigned N = 0)
|
||||
: Begin(NULL), End(NULL), Capacity(NULL) {
|
||||
reserve(C, N);
|
||||
}
|
||||
|
||||
~ASTVector() {
|
||||
if (llvm::is_class<T>::value) {
|
||||
// Destroy the constructed elements in the vector.
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
}
|
||||
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
|
||||
// forward iterator creation methods.
|
||||
iterator begin() { return Begin; }
|
||||
const_iterator begin() const { return Begin; }
|
||||
iterator end() { return End; }
|
||||
const_iterator end() const { return End; }
|
||||
|
||||
// reverse iterator creation methods.
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
|
||||
|
||||
bool empty() const { return Begin == End; }
|
||||
size_type size() const { return End-Begin; }
|
||||
|
||||
reference operator[](unsigned idx) {
|
||||
assert(Begin + idx < End);
|
||||
return Begin[idx];
|
||||
}
|
||||
const_reference operator[](unsigned idx) const {
|
||||
assert(Begin + idx < End);
|
||||
return Begin[idx];
|
||||
}
|
||||
|
||||
reference front() {
|
||||
return begin()[0];
|
||||
}
|
||||
const_reference front() const {
|
||||
return begin()[0];
|
||||
}
|
||||
|
||||
reference back() {
|
||||
return end()[-1];
|
||||
}
|
||||
const_reference back() const {
|
||||
return end()[-1];
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
--End;
|
||||
End->~T();
|
||||
}
|
||||
|
||||
T pop_back_val() {
|
||||
T Result = back();
|
||||
pop_back();
|
||||
return Result;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (llvm::is_class<T>::value) {
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
End = Begin;
|
||||
}
|
||||
|
||||
/// data - Return a pointer to the vector's buffer, even if empty().
|
||||
pointer data() {
|
||||
return pointer(Begin);
|
||||
}
|
||||
|
||||
/// data - Return a pointer to the vector's buffer, even if empty().
|
||||
const_pointer data() const {
|
||||
return const_pointer(Begin);
|
||||
}
|
||||
|
||||
void push_back(const_reference Elt, ASTContext &C) {
|
||||
if (End < Capacity) {
|
||||
Retry:
|
||||
new (End) T(Elt);
|
||||
++End;
|
||||
return;
|
||||
}
|
||||
grow(C);
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
void reserve(ASTContext &C, unsigned N) {
|
||||
if (unsigned(Capacity-Begin) < N)
|
||||
grow(C, N);
|
||||
}
|
||||
|
||||
/// capacity - Return the total number of elements in the currently allocated
|
||||
/// buffer.
|
||||
size_t capacity() const { return Capacity - Begin; }
|
||||
|
||||
/// append - Add the specified range to the end of the SmallVector.
|
||||
///
|
||||
template<typename in_iter>
|
||||
void append(ASTContext &C, in_iter in_start, in_iter in_end) {
|
||||
size_type NumInputs = std::distance(in_start, in_end);
|
||||
|
||||
if (NumInputs == 0)
|
||||
return;
|
||||
|
||||
// Grow allocated space if needed.
|
||||
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
|
||||
this->grow(C, this->size()+NumInputs);
|
||||
|
||||
// Copy the new elements over.
|
||||
// TODO: NEED To compile time dispatch on whether in_iter is a random access
|
||||
// iterator to use the fast uninitialized_copy.
|
||||
std::uninitialized_copy(in_start, in_end, this->end());
|
||||
this->setEnd(this->end() + NumInputs);
|
||||
}
|
||||
|
||||
/// append - Add the specified range to the end of the SmallVector.
|
||||
///
|
||||
void append(ASTContext &C, size_type NumInputs, const T &Elt) {
|
||||
// Grow allocated space if needed.
|
||||
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
|
||||
this->grow(C, this->size()+NumInputs);
|
||||
|
||||
// Copy the new elements over.
|
||||
std::uninitialized_fill_n(this->end(), NumInputs, Elt);
|
||||
this->setEnd(this->end() + NumInputs);
|
||||
}
|
||||
|
||||
/// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template<typename It1, typename It2>
|
||||
static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
|
||||
std::uninitialized_copy(I, E, Dest);
|
||||
}
|
||||
|
||||
iterator insert(ASTContext &C, iterator I, const T &Elt) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
push_back(Elt);
|
||||
return this->end()-1;
|
||||
}
|
||||
|
||||
if (this->EndX < this->CapacityX) {
|
||||
Retry:
|
||||
new (this->end()) T(this->back());
|
||||
this->setEnd(this->end()+1);
|
||||
// Push everything else over.
|
||||
std::copy_backward(I, this->end()-1, this->end());
|
||||
*I = Elt;
|
||||
return I;
|
||||
}
|
||||
size_t EltNo = I-this->begin();
|
||||
this->grow(C);
|
||||
I = this->begin()+EltNo;
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
iterator insert(ASTContext &C, iterator I, size_type NumToInsert,
|
||||
const T &Elt) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
append(C, NumToInsert, Elt);
|
||||
return this->end()-1;
|
||||
}
|
||||
|
||||
// Convert iterator to elt# to avoid invalidating iterator when we reserve()
|
||||
size_t InsertElt = I - this->begin();
|
||||
|
||||
// Ensure there is enough space.
|
||||
reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
|
||||
|
||||
// Uninvalidate the iterator.
|
||||
I = this->begin()+InsertElt;
|
||||
|
||||
// If there are more elements between the insertion point and the end of the
|
||||
// range than there are being inserted, we can use a simple approach to
|
||||
// insertion. Since we already reserved space, we know that this won't
|
||||
// reallocate the vector.
|
||||
if (size_t(this->end()-I) >= NumToInsert) {
|
||||
T *OldEnd = this->end();
|
||||
append(C, this->end()-NumToInsert, this->end());
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
|
||||
std::fill_n(I, NumToInsert, Elt);
|
||||
return I;
|
||||
}
|
||||
|
||||
// Otherwise, we're inserting more elements than exist already, and we're
|
||||
// not inserting at the end.
|
||||
|
||||
// Copy over the elements that we're about to overwrite.
|
||||
T *OldEnd = this->end();
|
||||
this->setEnd(this->end() + NumToInsert);
|
||||
size_t NumOverwritten = OldEnd-I;
|
||||
this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
|
||||
|
||||
// Replace the overwritten part.
|
||||
std::fill_n(I, NumOverwritten, Elt);
|
||||
|
||||
// Insert the non-overwritten middle part.
|
||||
std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
|
||||
return I;
|
||||
}
|
||||
|
||||
template<typename ItTy>
|
||||
iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
append(C, From, To);
|
||||
return this->end()-1;
|
||||
}
|
||||
|
||||
size_t NumToInsert = std::distance(From, To);
|
||||
// Convert iterator to elt# to avoid invalidating iterator when we reserve()
|
||||
size_t InsertElt = I - this->begin();
|
||||
|
||||
// Ensure there is enough space.
|
||||
reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
|
||||
|
||||
// Uninvalidate the iterator.
|
||||
I = this->begin()+InsertElt;
|
||||
|
||||
// If there are more elements between the insertion point and the end of the
|
||||
// range than there are being inserted, we can use a simple approach to
|
||||
// insertion. Since we already reserved space, we know that this won't
|
||||
// reallocate the vector.
|
||||
if (size_t(this->end()-I) >= NumToInsert) {
|
||||
T *OldEnd = this->end();
|
||||
append(C, this->end()-NumToInsert, this->end());
|
||||
|
||||
// Copy the existing elements that get replaced.
|
||||
std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
|
||||
|
||||
std::copy(From, To, I);
|
||||
return I;
|
||||
}
|
||||
|
||||
// Otherwise, we're inserting more elements than exist already, and we're
|
||||
// not inserting at the end.
|
||||
|
||||
// Copy over the elements that we're about to overwrite.
|
||||
T *OldEnd = this->end();
|
||||
this->setEnd(this->end() + NumToInsert);
|
||||
size_t NumOverwritten = OldEnd-I;
|
||||
this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
|
||||
|
||||
// Replace the overwritten part.
|
||||
for (; NumOverwritten > 0; --NumOverwritten) {
|
||||
*I = *From;
|
||||
++I; ++From;
|
||||
}
|
||||
|
||||
// Insert the non-overwritten middle part.
|
||||
this->uninitialized_copy(From, To, OldEnd);
|
||||
return I;
|
||||
}
|
||||
|
||||
void resize(ASTContext &C, unsigned N, const T &NV) {
|
||||
if (N < this->size()) {
|
||||
this->destroy_range(this->begin()+N, this->end());
|
||||
this->setEnd(this->begin()+N);
|
||||
} else if (N > this->size()) {
|
||||
if (this->capacity() < N)
|
||||
this->grow(C, N);
|
||||
construct_range(this->end(), this->begin()+N, NV);
|
||||
this->setEnd(this->begin()+N);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// grow - double the size of the allocated memory, guaranteeing space for at
|
||||
/// least one more element or MinSize if specified.
|
||||
void grow(ASTContext &C, size_type MinSize = 1);
|
||||
|
||||
void construct_range(T *S, T *E, const T &Elt) {
|
||||
for (; S != E; ++S)
|
||||
new (S) T(Elt);
|
||||
}
|
||||
|
||||
void destroy_range(T *S, T *E) {
|
||||
while (S != E) {
|
||||
--E;
|
||||
E->~T();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
iterator capacity_ptr() { return (iterator)this->Capacity; }
|
||||
};
|
||||
|
||||
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
||||
template <typename T>
|
||||
void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
|
||||
size_t CurCapacity = Capacity-Begin;
|
||||
size_t CurSize = size();
|
||||
size_t NewCapacity = 2*CurCapacity;
|
||||
if (NewCapacity < MinSize)
|
||||
NewCapacity = MinSize;
|
||||
|
||||
// Allocate the memory from the ASTContext.
|
||||
T *NewElts = new (C) T[NewCapacity];
|
||||
|
||||
// Copy the elements over.
|
||||
if (llvm::is_class<T>::value) {
|
||||
std::uninitialized_copy(Begin, End, NewElts);
|
||||
// Destroy the original elements.
|
||||
destroy_range(Begin, End);
|
||||
}
|
||||
else {
|
||||
// Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
|
||||
memcpy(NewElts, Begin, CurSize * sizeof(T));
|
||||
}
|
||||
|
||||
C.Deallocate(Begin);
|
||||
Begin = NewElts;
|
||||
End = NewElts+CurSize;
|
||||
Capacity = Begin+NewCapacity;
|
||||
}
|
||||
|
||||
} // end: clang namespace
|
||||
#endif
|
|
@ -0,0 +1,254 @@
|
|||
//===--- Attr.h - Classes for representing expressions ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the Attr interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ATTR_H
|
||||
#define LLVM_CLANG_AST_ATTR_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class IdentifierInfo;
|
||||
class ObjCInterfaceDecl;
|
||||
class Expr;
|
||||
class QualType;
|
||||
class FunctionDecl;
|
||||
class TypeSourceInfo;
|
||||
}
|
||||
|
||||
// Defined in ASTContext.h
|
||||
void *operator new(size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment = 16);
|
||||
// FIXME: Being forced to not have a default argument here due to redeclaration
|
||||
// rules on default arguments sucks
|
||||
void *operator new[](size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment);
|
||||
|
||||
// It is good practice to pair new/delete operators. Also, MSVC gives many
|
||||
// warnings if a matching delete overload is not declared, even though the
|
||||
// throw() spec guarantees it will not be implicitly called.
|
||||
void operator delete(void *Ptr, const clang::ASTContext &C, size_t);
|
||||
void operator delete[](void *Ptr, const clang::ASTContext &C, size_t);
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Attr - This represents one attribute.
|
||||
class Attr {
|
||||
private:
|
||||
SourceRange Range;
|
||||
unsigned AttrKind : 16;
|
||||
|
||||
protected:
|
||||
bool Inherited : 1;
|
||||
|
||||
virtual ~Attr();
|
||||
|
||||
void* operator new(size_t bytes) throw() {
|
||||
llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
|
||||
}
|
||||
void operator delete(void* data) throw() {
|
||||
llvm_unreachable("Attrs cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
public:
|
||||
// Forward so that the regular new and delete do not hide global ones.
|
||||
void* operator new(size_t Bytes, ASTContext &C,
|
||||
size_t Alignment = 16) throw() {
|
||||
return ::operator new(Bytes, C, Alignment);
|
||||
}
|
||||
void operator delete(void *Ptr, ASTContext &C,
|
||||
size_t Alignment) throw() {
|
||||
return ::operator delete(Ptr, C, Alignment);
|
||||
}
|
||||
|
||||
protected:
|
||||
Attr(attr::Kind AK, SourceRange R)
|
||||
: Range(R), AttrKind(AK), Inherited(false) {}
|
||||
|
||||
public:
|
||||
|
||||
attr::Kind getKind() const {
|
||||
return static_cast<attr::Kind>(AttrKind);
|
||||
}
|
||||
|
||||
SourceLocation getLocation() const { return Range.getBegin(); }
|
||||
SourceRange getRange() const { return Range; }
|
||||
void setRange(SourceRange R) { Range = R; }
|
||||
|
||||
bool isInherited() const { return Inherited; }
|
||||
|
||||
// Clone this attribute.
|
||||
virtual Attr* clone(ASTContext &C) const = 0;
|
||||
|
||||
virtual bool isLateParsed() const { return false; }
|
||||
|
||||
// Pretty print this attribute.
|
||||
virtual void printPretty(llvm::raw_ostream &OS, ASTContext &C) const = 0;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *) { return true; }
|
||||
};
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
InheritableAttr(attr::Kind AK, SourceRange R)
|
||||
: Attr(AK, R) {}
|
||||
|
||||
public:
|
||||
void setInherited(bool I) { Inherited = I; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() <= attr::LAST_INHERITABLE;
|
||||
}
|
||||
static bool classof(const InheritableAttr *) { return true; }
|
||||
};
|
||||
|
||||
class InheritableParamAttr : public InheritableAttr {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
InheritableParamAttr(attr::Kind AK, SourceRange R)
|
||||
: InheritableAttr(AK, R) {}
|
||||
|
||||
public:
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() <= attr::LAST_INHERITABLE_PARAM;
|
||||
}
|
||||
static bool classof(const InheritableParamAttr *) { return true; }
|
||||
};
|
||||
|
||||
#include "clang/AST/Attrs.inc"
|
||||
|
||||
/// AttrVec - A vector of Attr, which is how they are stored on the AST.
|
||||
typedef SmallVector<Attr*, 2> AttrVec;
|
||||
typedef SmallVector<const Attr*, 2> ConstAttrVec;
|
||||
|
||||
/// DestroyAttrs - Destroy the contents of an AttrVec.
|
||||
inline void DestroyAttrs (AttrVec& V, ASTContext &C) {
|
||||
}
|
||||
|
||||
/// specific_attr_iterator - Iterates over a subrange of an AttrVec, only
|
||||
/// providing attributes that are of a specifc type.
|
||||
template <typename SpecificAttr>
|
||||
class specific_attr_iterator {
|
||||
/// Current - The current, underlying iterator.
|
||||
/// In order to ensure we don't dereference an invalid iterator unless
|
||||
/// specifically requested, we don't necessarily advance this all the
|
||||
/// way. Instead, we advance it when an operation is requested; if the
|
||||
/// operation is acting on what should be a past-the-end iterator,
|
||||
/// then we offer no guarantees, but this way we do not dererence a
|
||||
/// past-the-end iterator when we move to a past-the-end position.
|
||||
mutable AttrVec::const_iterator Current;
|
||||
|
||||
void AdvanceToNext() const {
|
||||
while (!isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
void AdvanceToNext(AttrVec::const_iterator I) const {
|
||||
while (Current != I && !isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef SpecificAttr* value_type;
|
||||
typedef SpecificAttr* reference;
|
||||
typedef SpecificAttr* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
specific_attr_iterator() : Current() { }
|
||||
explicit specific_attr_iterator(AttrVec::const_iterator i) : Current(i) { }
|
||||
|
||||
reference operator*() const {
|
||||
AdvanceToNext();
|
||||
return cast<SpecificAttr>(*Current);
|
||||
}
|
||||
pointer operator->() const {
|
||||
AdvanceToNext();
|
||||
return cast<SpecificAttr>(*Current);
|
||||
}
|
||||
|
||||
specific_attr_iterator& operator++() {
|
||||
++Current;
|
||||
return *this;
|
||||
}
|
||||
specific_attr_iterator operator++(int) {
|
||||
specific_attr_iterator Tmp(*this);
|
||||
++(*this);
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(specific_attr_iterator Left,
|
||||
specific_attr_iterator Right) {
|
||||
if (Left.Current < Right.Current)
|
||||
Left.AdvanceToNext(Right.Current);
|
||||
else
|
||||
Right.AdvanceToNext(Left.Current);
|
||||
return Left.Current == Right.Current;
|
||||
}
|
||||
friend bool operator!=(specific_attr_iterator Left,
|
||||
specific_attr_iterator Right) {
|
||||
return !(Left == Right);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline specific_attr_iterator<T> specific_attr_begin(const AttrVec& vec) {
|
||||
return specific_attr_iterator<T>(vec.begin());
|
||||
}
|
||||
template <typename T>
|
||||
inline specific_attr_iterator<T> specific_attr_end(const AttrVec& vec) {
|
||||
return specific_attr_iterator<T>(vec.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool hasSpecificAttr(const AttrVec& vec) {
|
||||
return specific_attr_begin<T>(vec) != specific_attr_end<T>(vec);
|
||||
}
|
||||
template <typename T>
|
||||
inline T *getSpecificAttr(const AttrVec& vec) {
|
||||
specific_attr_iterator<T> i = specific_attr_begin<T>(vec);
|
||||
if (i != specific_attr_end<T>(vec))
|
||||
return *i;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getMaxAlignment - Returns the highest alignment value found among
|
||||
/// AlignedAttrs in an AttrVec, or 0 if there are none.
|
||||
inline unsigned getMaxAttrAlignment(const AttrVec& V, ASTContext &Ctx) {
|
||||
unsigned Align = 0;
|
||||
specific_attr_iterator<AlignedAttr> i(V.begin()), e(V.end());
|
||||
for(; i != e; ++i)
|
||||
Align = std::max(Align, i->getAlignment(Ctx));
|
||||
return Align;
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
//===--- BaseSubobject.h - BaseSubobject class ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides a definition of the BaseSubobject class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_BASESUBOBJECT_H
|
||||
#define LLVM_CLANG_AST_BASESUBOBJECT_H
|
||||
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
|
||||
namespace clang {
|
||||
class CXXRecordDecl;
|
||||
|
||||
// BaseSubobject - Uniquely identifies a direct or indirect base class.
|
||||
// Stores both the base class decl and the offset from the most derived class to
|
||||
// the base class. Used for vtable and VTT generation.
|
||||
class BaseSubobject {
|
||||
/// Base - The base class declaration.
|
||||
const CXXRecordDecl *Base;
|
||||
|
||||
/// BaseOffset - The offset from the most derived class to the base class.
|
||||
CharUnits BaseOffset;
|
||||
|
||||
public:
|
||||
BaseSubobject() { }
|
||||
BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset)
|
||||
: Base(Base), BaseOffset(BaseOffset) { }
|
||||
|
||||
/// getBase - Returns the base class declaration.
|
||||
const CXXRecordDecl *getBase() const { return Base; }
|
||||
|
||||
/// getBaseOffset - Returns the base class offset.
|
||||
CharUnits getBaseOffset() const { return BaseOffset; }
|
||||
|
||||
friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) {
|
||||
return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<> struct DenseMapInfo<clang::BaseSubobject> {
|
||||
static clang::BaseSubobject getEmptyKey() {
|
||||
return clang::BaseSubobject(
|
||||
DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(),
|
||||
clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey()));
|
||||
}
|
||||
|
||||
static clang::BaseSubobject getTombstoneKey() {
|
||||
return clang::BaseSubobject(
|
||||
DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(),
|
||||
clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey()));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::BaseSubobject &Base) {
|
||||
return
|
||||
DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
|
||||
DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity());
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::BaseSubobject &LHS,
|
||||
const clang::BaseSubobject &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// It's OK to treat BaseSubobject as a POD type.
|
||||
template <> struct isPodLike<clang::BaseSubobject> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче