Compare commits
36 Commits
llvmorg-3.
...
llvmorg-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18665516ad | ||
|
|
079a588dd1 | ||
|
|
c529f00553 | ||
|
|
2026b3fd03 | ||
|
|
3810f02f45 | ||
|
|
b466918a8c | ||
|
|
a52223b574 | ||
|
|
b76aad9fc0 | ||
|
|
e9e7d08fc6 | ||
|
|
25e67eda53 | ||
|
|
1df1d40e9f | ||
|
|
3a2ed724e3 | ||
|
|
8ab7ded56f | ||
|
|
d6db52d9b1 | ||
|
|
2db982c41f | ||
|
|
650437f2ef | ||
|
|
3e7b991362 | ||
|
|
95e705dba6 | ||
|
|
18d41baa16 | ||
|
|
6fa2343443 | ||
|
|
16b1f648f4 | ||
|
|
3c8d9e3967 | ||
|
|
406d24b588 | ||
|
|
6fdd777171 | ||
|
|
c268488db7 | ||
|
|
859d4167a0 | ||
|
|
93d8c22608 | ||
|
|
45400fd182 | ||
|
|
105e1edc48 | ||
|
|
48bc24b58e | ||
|
|
122bda50ba | ||
|
|
6e1a72fe08 | ||
|
|
2e7c26b02e | ||
|
|
acd2efdbc3 | ||
|
|
f498a646c7 | ||
|
|
e35b1819ad |
25
clang/.gitignore
vendored
25
clang/.gitignore
vendored
@@ -1,25 +0,0 @@
|
||||
#==============================================================================#
|
||||
# This file specifies intentionally untracked files that git should ignore.
|
||||
# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
|
||||
#
|
||||
# This file is intentionally different from the output of `git svn show-ignore`,
|
||||
# as most of those are useless.
|
||||
#==============================================================================#
|
||||
|
||||
#==============================================================================#
|
||||
# File extensions to be ignored anywhere in the tree.
|
||||
#==============================================================================#
|
||||
# Temp files created by most text editors.
|
||||
*~
|
||||
# Merge files created by git.
|
||||
*.orig
|
||||
# Byte compiled python modules.
|
||||
*.pyc
|
||||
# vim swap files
|
||||
.*.swp
|
||||
|
||||
#==============================================================================#
|
||||
# Explicit files to ignore (only matches one).
|
||||
#==============================================================================#
|
||||
cscope.files
|
||||
cscope.out
|
||||
@@ -1,184 +1,40 @@
|
||||
# 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)
|
||||
# Clang version information
|
||||
|
||||
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(CLANG_VENDOR "" CACHE STRING
|
||||
"Vendor-specific text for showing with version information.")
|
||||
|
||||
if( CLANG_VENDOR )
|
||||
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
|
||||
endif()
|
||||
# Make sure that CMake reconfigures when the version changes.
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/VER
|
||||
${CMAKE_CURRENT_BINARY_DIR}/VER)
|
||||
|
||||
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})
|
||||
# Compute the Clang version from the contents of VER
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VER CLANG_VERSION_DATA)
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
${CLANG_VERSION_DATA})
|
||||
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")
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
# FIXME: Turn off exceptions, RTTI:
|
||||
# -fno-exceptions -fno-rtti
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -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})
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE OR XCODE)
|
||||
file( GLOB_RECURSE headers *.h *.td *.def)
|
||||
set(srcs ${srcs} ${headers})
|
||||
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
|
||||
file( GLOB_RECURSE headers
|
||||
../../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)
|
||||
if (SHARED_LIBRARY)
|
||||
set(libkind SHARED)
|
||||
else()
|
||||
set(libkind)
|
||||
@@ -187,12 +43,18 @@ macro(add_clang_library name)
|
||||
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} )
|
||||
|
||||
if( LLVM_USED_LIBS )
|
||||
foreach(lib ${LLVM_USED_LIBS})
|
||||
target_link_libraries( ${name} ${lib} )
|
||||
endforeach(lib)
|
||||
endif( LLVM_USED_LIBS )
|
||||
if( LLVM_LINK_COMPONENTS )
|
||||
llvm_config(${name} ${LLVM_LINK_COMPONENTS})
|
||||
endif( LLVM_LINK_COMPONENTS )
|
||||
get_system_libs(llvm_system_libs)
|
||||
if( llvm_system_libs )
|
||||
target_link_libraries(${name} ${llvm_system_libs})
|
||||
endif( llvm_system_libs )
|
||||
add_dependencies(${name} ClangDiagnosticCommon)
|
||||
if(MSVC)
|
||||
get_target_property(cflag ${name} COMPILE_FLAGS)
|
||||
@@ -205,17 +67,20 @@ macro(add_clang_library name)
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
|
||||
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")
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE)
|
||||
file( GLOB_RECURSE headers *.h *.td *.def)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE)
|
||||
add_llvm_executable( ${name} ${srcs} )
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
include_directories(BEFORE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
)
|
||||
|
||||
install(DIRECTORY include/
|
||||
@@ -223,28 +88,11 @@ install(DIRECTORY include/
|
||||
FILES_MATCHING
|
||||
PATTERN "*.def"
|
||||
PATTERN "*.h"
|
||||
PATTERN "*.td"
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "*.inc"
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H )
|
||||
|
||||
# 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)
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
|
||||
if(CLANG_BUILD_EXAMPLES)
|
||||
@@ -254,25 +102,7 @@ endif ()
|
||||
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.")
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#define EXPAND_2_CASES(i, x, y) CASE(i, x, y); CASE(i + 1, x, y);
|
||||
#define EXPAND_4_CASES(i, x, y) EXPAND_2_CASES(i, x, y) EXPAND_2_CASES(i + 2, x, y)
|
||||
#define EXPAND_8_CASES(i, x, y) EXPAND_4_CASES(i, x, y) EXPAND_4_CASES(i + 4, x, y)
|
||||
#define EXPAND_16_CASES(i, x, y) EXPAND_8_CASES(i, x, y) EXPAND_8_CASES(i + 8, x, y)
|
||||
#define EXPAND_32_CASES(i, x, y) EXPAND_16_CASES(i, x, y) EXPAND_16_CASES(i + 16, x, y)
|
||||
#define EXPAND_64_CASES(i, x, y) EXPAND_32_CASES(i, x, y) EXPAND_32_CASES(i + 32, x, y)
|
||||
#define EXPAND_128_CASES(i, x, y) EXPAND_64_CASES(i, x, y) EXPAND_64_CASES(i + 64, x, y)
|
||||
#define EXPAND_256_CASES(i, x, y) EXPAND_128_CASES(i, x, y) EXPAND_128_CASES(i + 128, x, y)
|
||||
#define EXPAND_512_CASES(i, x, y) EXPAND_256_CASES(i, x, y) EXPAND_256_CASES(i + 256, x, y)
|
||||
#define EXPAND_1024_CASES(i, x, y) EXPAND_512_CASES(i, x, y) EXPAND_512_CASES(i + 512, x, y)
|
||||
#define EXPAND_2048_CASES(i, x, y) EXPAND_1024_CASES(i, x, y) EXPAND_1024_CASES(i + 1024, x, y)
|
||||
#define EXPAND_4096_CASES(i, x, y) EXPAND_2048_CASES(i, x, y) EXPAND_2048_CASES(i + 2048, x, y)
|
||||
|
||||
// This has a *monstrous* single fan-out in the CFG, across 8000 blocks inside
|
||||
// the while loop.
|
||||
unsigned cfg_big_switch(int x) {
|
||||
unsigned y = 0;
|
||||
while (x > 0) {
|
||||
switch(x) {
|
||||
#define CASE(i, x, y) \
|
||||
case i: { int case_var = 3*x + i; y += case_var - 1; break; }
|
||||
EXPAND_4096_CASES(0, x, y);
|
||||
}
|
||||
--x;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y);
|
||||
#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y)
|
||||
#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y)
|
||||
#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y)
|
||||
#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y)
|
||||
#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y)
|
||||
#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y)
|
||||
#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y)
|
||||
#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y)
|
||||
#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y)
|
||||
#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y)
|
||||
#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y)
|
||||
|
||||
unsigned cfg_long_chain_single_exit(unsigned x) {
|
||||
unsigned y = 0;
|
||||
#define BRANCH(i, x, y) if ((x % 13171) < i) { int var = x / 13171; y ^= var; }
|
||||
EXPAND_4096_BRANCHES(1, x, y);
|
||||
#undef BRANCH
|
||||
return y;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y);
|
||||
#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y)
|
||||
#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y)
|
||||
#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y)
|
||||
#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y)
|
||||
#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y)
|
||||
#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y)
|
||||
#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y)
|
||||
#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y)
|
||||
#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y)
|
||||
#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y)
|
||||
#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y)
|
||||
|
||||
unsigned cfg_long_chain_multiple_exit(unsigned x) {
|
||||
unsigned y = 0;
|
||||
#define BRANCH(i, x, y) if (((x % 13171) + ++y) < i) { int var = x / 13171 + y; return var; }
|
||||
EXPAND_4096_BRANCHES(1, x, y);
|
||||
#undef BRANCH
|
||||
return 42;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#define EXPAND_2_BRANCHES(i, x, y) BRANCH(i, x, y); BRANCH(i + 1, x, y);
|
||||
#define EXPAND_4_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i, x, y) EXPAND_2_BRANCHES(i + 2, x, y)
|
||||
#define EXPAND_8_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i, x, y) EXPAND_4_BRANCHES(i + 4, x, y)
|
||||
#define EXPAND_16_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i, x, y) EXPAND_8_BRANCHES(i + 8, x, y)
|
||||
#define EXPAND_32_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i, x, y) EXPAND_16_BRANCHES(i + 16, x, y)
|
||||
#define EXPAND_64_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i, x, y) EXPAND_32_BRANCHES(i + 32, x, y)
|
||||
#define EXPAND_128_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i, x, y) EXPAND_64_BRANCHES(i + 64, x, y)
|
||||
#define EXPAND_256_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i, x, y) EXPAND_128_BRANCHES(i + 128, x, y)
|
||||
#define EXPAND_512_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i, x, y) EXPAND_256_BRANCHES(i + 256, x, y)
|
||||
#define EXPAND_1024_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i, x, y) EXPAND_512_BRANCHES(i + 512, x, y)
|
||||
#define EXPAND_2048_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i, x, y) EXPAND_1024_BRANCHES(i + 1024, x, y)
|
||||
#define EXPAND_4096_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i, x, y) EXPAND_2048_BRANCHES(i + 2048, x, y)
|
||||
|
||||
unsigned cfg_long_chain_many_preds(unsigned x) {
|
||||
unsigned y = 0;
|
||||
#define BRANCH(i, x, y) if ((x % 13171) < i) { int var = x / 13171; y ^= var; } else
|
||||
EXPAND_4096_BRANCHES(1, x, y);
|
||||
#undef BRANCH
|
||||
int var = x / 13171; y^= var;
|
||||
return y;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#define EXPAND_2_INNER_CASES(i, x, y) INNER_CASE(i, x, y); INNER_CASE(i + 1, x, y);
|
||||
#define EXPAND_4_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i + 2, x, y)
|
||||
#define EXPAND_8_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i + 4, x, y)
|
||||
#define EXPAND_16_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i + 8, x, y)
|
||||
#define EXPAND_32_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i + 16, x, y)
|
||||
#define EXPAND_64_INNER_CASES(i, x, y) EXPAND_32_INNER_CASES(i, x, y) EXPAND_32_INNER_CASES(i + 32, x, y)
|
||||
|
||||
#define EXPAND_2_OUTER_CASES(i, x, y) OUTER_CASE(i, x, y); OUTER_CASE(i + 1, x, y);
|
||||
#define EXPAND_4_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i + 2, x, y)
|
||||
#define EXPAND_8_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i + 4, x, y)
|
||||
#define EXPAND_16_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i + 8, x, y)
|
||||
#define EXPAND_32_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i + 16, x, y)
|
||||
#define EXPAND_64_OUTER_CASES(i, x, y) EXPAND_32_OUTER_CASES(i, x, y) EXPAND_32_OUTER_CASES(i + 32, x, y)
|
||||
|
||||
// Rather than a single monstrous fan-out, this fans out in smaller increments,
|
||||
// but to a similar size.
|
||||
unsigned cfg_nested_switch(int x) {
|
||||
unsigned y = 0;
|
||||
while (x > 0) {
|
||||
switch (x) {
|
||||
#define INNER_CASE(i, x, y) \
|
||||
case i: { int case_var = 3*x + i; y += case_var - 1; break; }
|
||||
#define OUTER_CASE(i, x, y) \
|
||||
case i: { \
|
||||
int case_var = y >> 8; \
|
||||
switch (case_var) { \
|
||||
EXPAND_64_INNER_CASES(0, x, y); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
EXPAND_64_OUTER_CASES(0, x, y);
|
||||
}
|
||||
--x;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Hammer the CFG with large numbers of overlapping variable scopes, which
|
||||
// implicit destructors triggered at each edge.
|
||||
|
||||
#define EXPAND_BASIC_STRUCT(i) struct X##i { X##i(int); ~X##i(); };
|
||||
#define EXPAND_NORET_STRUCT(i) struct X##i { X##i(int); ~X##i() __attribute__((noreturn)); };
|
||||
EXPAND_BASIC_STRUCT(0000); EXPAND_NORET_STRUCT(0001);
|
||||
EXPAND_BASIC_STRUCT(0010); EXPAND_BASIC_STRUCT(0011);
|
||||
EXPAND_BASIC_STRUCT(0100); EXPAND_NORET_STRUCT(0101);
|
||||
EXPAND_NORET_STRUCT(0110); EXPAND_BASIC_STRUCT(0111);
|
||||
EXPAND_BASIC_STRUCT(1000); EXPAND_NORET_STRUCT(1001);
|
||||
EXPAND_BASIC_STRUCT(1010); EXPAND_BASIC_STRUCT(1011);
|
||||
EXPAND_NORET_STRUCT(1100); EXPAND_NORET_STRUCT(1101);
|
||||
EXPAND_BASIC_STRUCT(1110); EXPAND_BASIC_STRUCT(1111);
|
||||
|
||||
#define EXPAND_2_VARS(c, i, x) const X##i var_##c##_##i##0(x), &var_##c##_##i##1 = X##i(x)
|
||||
#define EXPAND_4_VARS(c, i, x) EXPAND_2_VARS(c, i##0, x); EXPAND_2_VARS(c, i##1, x)
|
||||
#define EXPAND_8_VARS(c, i, x) EXPAND_4_VARS(c, i##0, x); EXPAND_4_VARS(c, i##1, x)
|
||||
#define EXPAND_16_VARS(c, i, x) EXPAND_8_VARS(c, i##0, x); EXPAND_8_VARS(c, i##1, x)
|
||||
#define EXPAND_32_VARS(c, x) EXPAND_16_VARS(c, 0, x); EXPAND_16_VARS(c, 1, x)
|
||||
|
||||
#define EXPAND_2_INNER_CASES(i, x, y) INNER_CASE(i, x, y); INNER_CASE(i + 1, x, y);
|
||||
#define EXPAND_4_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i + 2, x, y)
|
||||
#define EXPAND_8_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i + 4, x, y)
|
||||
#define EXPAND_16_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i + 8, x, y)
|
||||
#define EXPAND_32_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i + 16, x, y)
|
||||
|
||||
#define EXPAND_2_OUTER_CASES(i, x, y) OUTER_CASE(i, x, y); OUTER_CASE(i + 1, x, y);
|
||||
#define EXPAND_4_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i + 2, x, y)
|
||||
#define EXPAND_8_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i + 4, x, y)
|
||||
#define EXPAND_16_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i + 8, x, y)
|
||||
#define EXPAND_32_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i + 16, x, y)
|
||||
|
||||
unsigned cfg_nested_vars(int x) {
|
||||
int y = 0;
|
||||
while (x > 0) {
|
||||
EXPAND_32_VARS(a, x);
|
||||
switch (x) {
|
||||
#define INNER_CASE(i, x, y) \
|
||||
case i: { \
|
||||
int case_var = 3*x + i; \
|
||||
EXPAND_32_VARS(c, case_var); \
|
||||
y += case_var - 1; \
|
||||
break; \
|
||||
}
|
||||
#define OUTER_CASE(i, x, y) \
|
||||
case i: { \
|
||||
int case_var = y >> 8; \
|
||||
EXPAND_32_VARS(b, y); \
|
||||
switch (case_var) { \
|
||||
EXPAND_32_INNER_CASES(0, x, y); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
EXPAND_32_OUTER_CASES(0, x, y);
|
||||
}
|
||||
--x;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ LLVM Release License
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007-2011 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2007-2010 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
112
clang/Makefile
112
clang/Makefile
@@ -1,92 +1,24 @@
|
||||
##===- 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
|
||||
LEVEL = ../..
|
||||
DIRS := include lib tools docs
|
||||
|
||||
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
|
||||
$(Verb) if [ ! -f test/Makefile ]; then \
|
||||
$(MKDIR) test; \
|
||||
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
|
||||
fi
|
||||
endif
|
||||
|
||||
test::
|
||||
@ $(MAKE) -C test
|
||||
@ $(MAKE) -C test
|
||||
|
||||
report::
|
||||
@ $(MAKE) -C test report
|
||||
@@ -94,11 +26,8 @@ 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/`
|
||||
$(Verb) etags `find . -type f -name \*.h | grep -v /lib/Headers | grep -v /test/` `find . -type f -name \*.cpp | grep -v /lib/Headers | grep -v /test/`
|
||||
|
||||
cscope.files:
|
||||
find tools lib include -name '*.cpp' \
|
||||
@@ -108,4 +37,29 @@ cscope.files:
|
||||
|
||||
.PHONY: test report clean cscope.files
|
||||
|
||||
install-local::
|
||||
$(Echo) Installing include files
|
||||
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
|
||||
$(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include" ; then \
|
||||
cd $(PROJ_SRC_ROOT)/tools/clang/include && \
|
||||
for hdr in `find . -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=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
|
||||
if test \! -d "$$instdir" ; then \
|
||||
$(EchoCmd) Making install directory $$instdir ; \
|
||||
$(MKDIR) $$instdir ;\
|
||||
fi ; \
|
||||
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
$(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include" ; then \
|
||||
cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
|
||||
for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \
|
||||
| grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
|
||||
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
endif
|
||||
|
||||
@@ -13,7 +13,8 @@ This is similar to -Eonly.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Creating and using a PTH file for performance measurement (use a release build).
|
||||
Creating and using a PTH file for performance measurement (use a release-asserts
|
||||
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
|
||||
@@ -83,21 +84,3 @@ enum VerifyConstraintResult {
|
||||
};
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
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.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
compiler intrastructure 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
|
||||
|
||||
75
clang/TODO.txt
Normal file
75
clang/TODO.txt
Normal file
@@ -0,0 +1,75 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Minor random things that can be improved
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
|
||||
Warn about "X && 0x1000" saying that the user may mean "X & 0x1000".
|
||||
We should do this for any immediate except zero, so long as it doesn't come
|
||||
from a macro expansion. Likewise for ||.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Lexer-related diagnostics should point to the problematic character, not the
|
||||
start of the token. For example:
|
||||
|
||||
int y = 0000\
|
||||
00080;
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
int y = 0000\
|
||||
^
|
||||
|
||||
should be:
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
00080;
|
||||
^
|
||||
|
||||
This specific diagnostic is implemented, but others should be updated.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C++ (checker): For iterators, warn of the use of "iterator++" instead
|
||||
of "++iterator" when when the value returned by operator++(int) is
|
||||
ignored.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
We want to keep more source range information in Declarator to help
|
||||
produce better diagnostics. Declarator::getSourceRange() should be
|
||||
implemented to give a range for the whole declarator with all of its
|
||||
specifiers, and DeclaratorChunk::ParamInfo should also have a source
|
||||
range covering the whole parameter, so that an error message like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^
|
||||
can be turned into something like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^ ~~~~~~~~~~~~~~
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
For terminal output, we should consider limiting the amount of
|
||||
diagnostic text we print once the first error has been
|
||||
encountered. For example, once we have produced an error diagnostic,
|
||||
we should only continue producing diagnostics until we have produced a
|
||||
page full of results (say, 50 lines of text). Beyond that, (1) the
|
||||
remaining errors are likely to be less interesting, and (2) the poor
|
||||
user has to scroll his terminal to find out where things went wrong.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
More ideas for code modification hints:
|
||||
- If no member of a given name is found in a class/struct, search through the names of entities that do exist in the class and suggest the closest candidate. e.g., if I write "DS.setTypeSpecType", it would suggest "DS.SetTypeSpecType" (edit distance = 1).
|
||||
- If a class member is defined out-of-line but isn't in the class declaration (and there are no close matches!), provide the option to add an in-class declaration.
|
||||
- Fix-it hints for the inclusion of headers when needed for particular features (e.g., <typeinfo> for typeid)
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Options to support:
|
||||
-ftabstop=width
|
||||
-fpreprocessed mode.
|
||||
-nostdinc++
|
||||
-imultilib
|
||||
@@ -2,9 +2,10 @@
|
||||
// Clang Python Bindings
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
This directory implements Python bindings for Clang.
|
||||
This directory implements Python bindings for Clang. Currently, only bindings
|
||||
for the CIndex C API exist.
|
||||
|
||||
You may need to alter LD_LIBRARY_PATH so that the Clang library can be
|
||||
You may need to alter LD_LIBRARY_PATH so that the CIndex library can be
|
||||
found. The unit tests are designed to be run with 'nosetests'. For example:
|
||||
--
|
||||
$ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
from clang.cindex import Index, CursorKind, TypeKind
|
||||
from clang.cindex import Index, CursorKind
|
||||
|
||||
kInput = """\
|
||||
// FIXME: Find nicer way to drop builtins and other cruft.
|
||||
@@ -47,17 +47,13 @@ def test_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
|
||||
|
||||
@@ -18,14 +18,10 @@ def test_kind_groups():
|
||||
|
||||
for k in CursorKind.get_all_kinds():
|
||||
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
|
||||
'is_statement', 'is_invalid', 'is_attribute')
|
||||
'is_statement', 'is_invalid')
|
||||
if getattr(k, n)()]
|
||||
|
||||
if k in ( CursorKind.TRANSLATION_UNIT,
|
||||
CursorKind.MACRO_DEFINITION,
|
||||
CursorKind.MACRO_INSTANTIATION,
|
||||
CursorKind.INCLUSION_DIRECTIVE,
|
||||
CursorKind.PREPROCESSING_DIRECTIVE):
|
||||
if k == CursorKind.TRANSLATION_UNIT:
|
||||
assert len(group) == 0
|
||||
else:
|
||||
assert len(group) == 1
|
||||
|
||||
@@ -3,6 +3,8 @@ from clang.cindex import *
|
||||
def tu_from_source(source):
|
||||
index = Index.create()
|
||||
tu = index.parse('INPUT.c', unsaved_files = [('INPUT.c', source)])
|
||||
# FIXME: Remove the need for this.
|
||||
tu.index = index
|
||||
return tu
|
||||
|
||||
# FIXME: We need support for invalid translation units to test better.
|
||||
@@ -36,7 +38,7 @@ def test_diagnostic_fixit():
|
||||
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].location.column == 31
|
||||
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
|
||||
@@ -44,26 +46,3 @@ def test_diagnostic_fixit():
|
||||
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():
|
||||
index = Index.create()
|
||||
tu = tu_from_source("""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
|
||||
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
from clang.cindex import Index
|
||||
|
||||
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():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.location,line=1,column=5,offset=4)
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.location,line=2,column=5,offset=13)
|
||||
|
||||
# adding a linebreak at top should keep columns same
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',"\n"+baseInput)])
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.location,line=2,column=5,offset=5)
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.location,line=3,column=5,offset=14)
|
||||
|
||||
# adding a space should affect column on first line only
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c'," "+baseInput)])
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.location,line=1,column=6,offset=5)
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.location,line=2,column=5,offset=14)
|
||||
|
||||
def test_extent():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.extent.start,line=1,column=1,offset=0)
|
||||
assert_location(n.extent.end,line=1,column=8,offset=7)
|
||||
assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int one"
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.extent.start,line=2,column=1,offset=9)
|
||||
assert_location(n.extent.end,line=2,column=8,offset=16)
|
||||
assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int two"
|
||||
@@ -25,24 +25,16 @@ def test_parse_arguments():
|
||||
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 = [
|
||||
# FIXME: Why can't we just use "fake.h" here (instead of /tmp/fake.h)?
|
||||
tu = index.parse('fake.c', unsaved_files = [
|
||||
('fake.c', """
|
||||
#include "fake.h"
|
||||
#include "/tmp/fake.h"
|
||||
int x;
|
||||
int SOME_DEFINE;
|
||||
"""),
|
||||
('./fake.h', """
|
||||
('/tmp/fake.h', """
|
||||
#define SOME_DEFINE y
|
||||
""")
|
||||
])
|
||||
@@ -58,27 +50,24 @@ def test_unsaved_files_2():
|
||||
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)
|
||||
return expected[0] == actual.source.name and \
|
||||
expected[1] == actual.include.name
|
||||
else:
|
||||
return normpaths_equal(expected[1], actual.include.name)
|
||||
return 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)]
|
||||
inc = [(None, src), (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])
|
||||
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
from clang.cindex import Index, CursorKind, TypeKind
|
||||
|
||||
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():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'teststruct':
|
||||
fields = list(n.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
|
||||
|
||||
break
|
||||
|
||||
else:
|
||||
assert False, "Didn't find teststruct??"
|
||||
|
||||
|
||||
constarrayInput="""
|
||||
struct teststruct {
|
||||
void *A[2];
|
||||
};
|
||||
"""
|
||||
def testConstantArray():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',constarrayInput)])
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'teststruct':
|
||||
fields = list(n.get_children())
|
||||
assert fields[0].spelling == 'A'
|
||||
assert fields[0].type.kind == TypeKind.CONSTANTARRAY
|
||||
break
|
||||
else:
|
||||
assert False, "Didn't find teststruct??"
|
||||
2142
clang/clang.xcodeproj/project.pbxproj
Normal file
2142
clang/clang.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,670 +0,0 @@
|
||||
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);
|
||||
|
||||
647
clang/docs/BlockImplementation.txt
Normal file
647
clang/docs/BlockImplementation.txt
Normal file
@@ -0,0 +1,647 @@
|
||||
Block Implementation Specification
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
This document describes the Apple ABI implementation specification of Blocks.
|
||||
|
||||
1. High Level
|
||||
|
||||
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);
|
||||
void (*dispose_helper)(void *src);
|
||||
} *descriptor;
|
||||
// imported variables
|
||||
};
|
||||
|
||||
The following flags bits are used by the compiler:
|
||||
|
||||
enum {
|
||||
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
|
||||
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
|
||||
BLOCK_IS_GLOBAL = (1 << 28),
|
||||
BLOCK_HAS_DESCRIPTOR = (1 << 29), // interim until complete world build is accomplished
|
||||
};
|
||||
|
||||
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), 11 };
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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 *);
|
||||
int 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 as const copies using the const copy constructor. It is an error if a stack based C++ object is used within a block if it does not have a const 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 const 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) {
|
||||
comp_ctor(&dst->foo, &src->foo);
|
||||
}
|
||||
|
||||
void __block_dispose_10(struct __block_literal_10 *src) {
|
||||
comp_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.
|
||||
|
||||
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);
|
||||
|
||||
The following functions have been used and will continue to be supported until new compiler support is complete.
|
||||
|
||||
// Obsolete functions.
|
||||
// Copy helper callback for copying a block imported into a Block
|
||||
// Called by copy_helper helper functions synthesized by the compiler.
|
||||
// The address in the destination block of an imported Block is provided as the first argument
|
||||
// and the value of the existing imported Block is the second.
|
||||
// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
|
||||
void _Block_copy_assign(struct Block_basic **dest, const struct Block_basic *src, const int flags);
|
||||
|
||||
// Destroy helper callback for releasing Blocks imported into a Block
|
||||
// Called by dispose_helper helper functions synthesized by the compiler.
|
||||
// The value of the imported Block variable is passed back.
|
||||
// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
|
||||
void _Block_destroy(const struct Block_basic *src, const int flags);
|
||||
|
||||
// Byref data block copy helper callback
|
||||
// Called by block copy helpers when copying __block structures
|
||||
// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
|
||||
void _Block_byref_assign_copy(struct Block_byref **destp, struct Block_byref *src);
|
||||
|
||||
// Byref data block release helper callback
|
||||
// Called by block release helpers when releasing a Block
|
||||
// Called at escape points in scope where __block variables live (under non-GC-only conditions)
|
||||
// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
|
||||
void <20>(struct Block_byref *shared_struct);
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ For example, given class Foo with member function fighter(void):
|
||||
...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;
|
||||
const Foo *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.
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<h3 id="components">Flexible</h3>
|
||||
<!--=======================================================================-->
|
||||
|
||||
<p>The driver was designed to be flexible and easily accommodate
|
||||
<p>The driver was designed to be flexible and easily accomodate
|
||||
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
|
||||
@@ -218,7 +218,7 @@
|
||||
|
||||
<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
|
||||
must preceed 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>
|
||||
@@ -405,7 +405,7 @@
|
||||
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>
|
||||
compilation files).</p>
|
||||
|
||||
<h4 id="int_unified_parsing">Unified Parsing & Pipelining</h4>
|
||||
|
||||
@@ -490,7 +490,7 @@
|
||||
|
||||
<li>
|
||||
<b>Specs</b>
|
||||
<p>The clang driver has no direct correspondent for
|
||||
<p>The clang driver has no direct correspondant 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
|
||||
|
||||
@@ -25,7 +25,6 @@ td {
|
||||
<li><a href="#Diagnostics">The Diagnostics Subsystem</a></li>
|
||||
<li><a href="#SourceLocation">The SourceLocation and SourceManager
|
||||
classes</a></li>
|
||||
<li><a href="#SourceRange">SourceRange and CharSourceRange</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#libdriver">The Driver Library</a>
|
||||
@@ -68,12 +67,7 @@ td {
|
||||
<li><a href="#Constants">Constant Folding in the Clang AST</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#Howtos">Howto guides</a>
|
||||
<ul>
|
||||
<li><a href="#AddingAttributes">How to add an attribute</a></li>
|
||||
<li><a href="#AddingExprStmt">How to add a new expression or statement</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="libIndex.html">The Index Library</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -124,8 +118,8 @@ classes somewhere else, or introduce some other solution.</p>
|
||||
<p>The Clang Diagnostics subsystem is an important part of how the compiler
|
||||
communicates with the human. Diagnostics are the warnings and errors produced
|
||||
when the code is incorrect or dubious. In Clang, each diagnostic produced has
|
||||
(at the minimum) a unique ID, an English translation associated with it, a <a
|
||||
href="#SourceLocation">SourceLocation</a> to "put the caret", and a severity (e.g.
|
||||
(at the minimum) a unique ID, a <a href="#SourceLocation">SourceLocation</a> to
|
||||
"put the caret", an English translation associated with it, and a severity (e.g.
|
||||
<tt>WARNING</tt> or <tt>ERROR</tt>). They can also optionally include a number
|
||||
of arguments to the dianostic (which fill in "%0"'s in the string) as well as a
|
||||
number of source ranges that related to the diagnostic.</p>
|
||||
@@ -133,7 +127,7 @@ number of source ranges that related to the diagnostic.</p>
|
||||
<p>In this section, we'll be giving examples produced by the Clang command line
|
||||
driver, but diagnostics can be <a href="#DiagnosticClient">rendered in many
|
||||
different ways</a> depending on how the DiagnosticClient interface is
|
||||
implemented. A representative example of a diagnostic is:</p>
|
||||
implemented. A representative example of a diagonstic is:</p>
|
||||
|
||||
<pre>
|
||||
t.c:38:15: error: invalid operands to binary expression ('int *' and '_Complex float')
|
||||
@@ -151,14 +145,15 @@ diagnostic :).</p>
|
||||
pieces, this section describes them and talks about best practices when adding
|
||||
a new diagnostic.</p>
|
||||
|
||||
<!-- ============================= -->
|
||||
<h4>The Diagnostic*Kinds.td files</h4>
|
||||
<!-- ============================= -->
|
||||
<!-- ============================ -->
|
||||
<h4>The DiagnosticKinds.def file</h4>
|
||||
<!-- ============================ -->
|
||||
|
||||
<p>Diagnostics are created by adding an entry to one of the <tt>
|
||||
clang/Basic/Diagnostic*Kinds.td</tt> files, depending on what library will
|
||||
be using it. From this file, tblgen generates the unique ID of the diagnostic,
|
||||
the severity of the diagnostic and the English translation + format string.</p>
|
||||
<p>Diagnostics are created by adding an entry to the <tt><a
|
||||
href="http://llvm.org/svn/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def"
|
||||
>DiagnosticKinds.def</a></tt> file. This file encodes the unique ID of the
|
||||
diagnostic (as an enum, the first argument), the severity of the diagnostic
|
||||
(second argument) and the English translation + format string.</p>
|
||||
|
||||
<p>There is little sanity with the naming of the unique ID's right now. Some
|
||||
start with err_, warn_, ext_ to encode the severity into the name. Since the
|
||||
@@ -242,7 +237,7 @@ are some simple format strings:</p>
|
||||
|
||||
<ul>
|
||||
<li>Keep the string short. It should ideally fit in the 80 column limit of the
|
||||
<tt>DiagnosticKinds.td</tt> file. This avoids the diagnostic wrapping when
|
||||
<tt>DiagnosticKinds.def</tt> file. This avoids the diagnostic wrapping when
|
||||
printed, and forces you to think about the important point you are conveying
|
||||
with the diagnostic.</li>
|
||||
<li>Take advantage of location information. The user will be able to see the
|
||||
@@ -257,7 +252,7 @@ are some simple format strings:</p>
|
||||
<p>Diagnostics should never take random English strings as arguments: you
|
||||
shouldn't use <tt>"you have a problem with %0"</tt> and pass in things like
|
||||
<tt>"your argument"</tt> or <tt>"your return value"</tt> as arguments. Doing
|
||||
this prevents <a href="#translation">translating</a> the Clang diagnostics to
|
||||
this prevents <a href="translation">translating</a> the Clang diagnostics to
|
||||
other languages (because they'll get random English words in their otherwise
|
||||
localized diagnostic). The exceptions to this are C/C++ language keywords
|
||||
(e.g. auto, const, mutable, etc) and C/C++ operators (<tt>/=</tt>). Note
|
||||
@@ -372,10 +367,10 @@ of repetitive diagnostics and/or have an idea for a useful formatter, please
|
||||
bring it up on the cfe-dev mailing list.</p>
|
||||
|
||||
<!-- ===================================================== -->
|
||||
<h4 id="producingdiag">Producing the Diagnostic</h4>
|
||||
<h4><a name="#producingdiag">Producing the Diagnostic</a></h4>
|
||||
<!-- ===================================================== -->
|
||||
|
||||
<p>Now that you've created the diagnostic in the DiagnosticKinds.td file, you
|
||||
<p>Now that you've created the diagnostic in the DiagnosticKinds.def file, you
|
||||
need to write the code that detects the condition in question and emits the
|
||||
new diagnostic. Various components of Clang (e.g. the preprocessor, Sema,
|
||||
etc) provide a helper function named "Diag". It creates a diagnostic and
|
||||
@@ -393,7 +388,7 @@ it.</p>
|
||||
|
||||
<p>This shows that use of the Diag method: they take a location (a <a
|
||||
href="#SourceLocation">SourceLocation</a> object) and a diagnostic enum value
|
||||
(which matches the name from DiagnosticKinds.td). If the diagnostic takes
|
||||
(which matches the name from DiagnosticKinds.def). If the diagnostic takes
|
||||
arguments, they are specified with the << operator: the first argument
|
||||
becomes %0, the second becomes %1, etc. The diagnostic interface allows you to
|
||||
specify arguments of many different types, including <tt>int</tt> and
|
||||
@@ -412,7 +407,7 @@ it is rendered.
|
||||
</p>
|
||||
|
||||
<!-- ==================================================== -->
|
||||
<h4 id="fix-it-hints">Fix-It Hints</h4>
|
||||
<h4 id="code-modification-hints">Code Modification Hints</h4>
|
||||
<!-- ==================================================== -->
|
||||
|
||||
<p>In some cases, the front end emits diagnostics when it is clear
|
||||
@@ -422,14 +417,14 @@ deprecated syntax that is easily rewritten into a more modern form.
|
||||
Clang tries very hard to emit the diagnostic and recover gracefully
|
||||
in these and other cases.</p>
|
||||
|
||||
<p>However, for these cases where the fix is obvious, the diagnostic
|
||||
can be annotated with a hint (referred to as a "fix-it hint") that
|
||||
describes how to change the code referenced by the diagnostic to fix
|
||||
the problem. For example, it might add the missing semicolon at the
|
||||
end of the statement or rewrite the use of a deprecated construct
|
||||
into something more palatable. Here is one such example from the C++
|
||||
front end, where we warn about the right-shift operator changing
|
||||
meaning from C++98 to C++0x:</p>
|
||||
<p>However, for these cases where the fix is obvious, the diagnostic
|
||||
can be annotated with a code
|
||||
modification "hint" that describes how to change the code referenced
|
||||
by the diagnostic to fix the problem. For example, it might add the
|
||||
missing semicolon at the end of the statement or rewrite the use of a
|
||||
deprecated construct into something more palatable. Here is one such
|
||||
example C++ front end, where we warn about the right-shift operator
|
||||
changing meaning from C++98 to C++0x:</p>
|
||||
|
||||
<pre>
|
||||
test.cpp:3:7: warning: use of right-shift operator ('>>') in template argument will require parentheses in C++0x
|
||||
@@ -438,31 +433,33 @@ A<100 >> 2> *a;
|
||||
( )
|
||||
</pre>
|
||||
|
||||
<p>Here, the fix-it hint is suggesting that parentheses be added,
|
||||
and showing exactly where those parentheses would be inserted into the
|
||||
source code. The fix-it hints themselves describe what changes to make
|
||||
to the source code in an abstract manner, which the text diagnostic
|
||||
printer renders as a line of "insertions" below the caret line. <a
|
||||
href="#DiagnosticClient">Other diagnostic clients</a> might choose
|
||||
to render the code differently (e.g., as markup inline) or even give
|
||||
the user the ability to automatically fix the problem.</p>
|
||||
<p>Here, the code modification hint is suggesting that parentheses be
|
||||
added, and showing exactly where those parentheses would be inserted
|
||||
into the source code. The code modification hints themselves describe
|
||||
what changes to make to the source code in an abstract manner, which
|
||||
the text diagnostic printer renders as a line of "insertions" below
|
||||
the caret line. <a href="#DiagnosticClient">Other diagnostic
|
||||
clients</a> might choose to render the code differently (e.g., as
|
||||
markup inline) or even give the user the ability to automatically fix
|
||||
the problem.</p>
|
||||
|
||||
<p>All fix-it hints are described by the <code>FixItHint</code> class,
|
||||
instances of which should be attached to the diagnostic using the
|
||||
<< operator in the same way that highlighted source ranges and
|
||||
arguments are passed to the diagnostic. Fix-it hints can be created
|
||||
with one of three constructors:</p>
|
||||
<p>All code modification hints are described by the
|
||||
<code>CodeModificationHint</code> class, instances of which should be
|
||||
attached to the diagnostic using the << operator in the same way
|
||||
that highlighted source ranges and arguments are passed to the
|
||||
diagnostic. Code modification hints can be created with one of three
|
||||
constructors:</p>
|
||||
|
||||
<dl>
|
||||
<dt><code>FixItHint::CreateInsertion(Loc, Code)</code></dt>
|
||||
<dt><code>CodeModificationHint::CreateInsertion(Loc, Code)</code></dt>
|
||||
<dd>Specifies that the given <code>Code</code> (a string) should be inserted
|
||||
before the source location <code>Loc</code>.</dd>
|
||||
|
||||
<dt><code>FixItHint::CreateRemoval(Range)</code></dt>
|
||||
<dt><code>CodeModificationHint::CreateRemoval(Range)</code></dt>
|
||||
<dd>Specifies that the code in the given source <code>Range</code>
|
||||
should be removed.</dd>
|
||||
|
||||
<dt><code>FixItHint::CreateReplacement(Range, Code)</code></dt>
|
||||
<dt><code>CodeModificationHint::CreateReplacement(Range, Code)</code></dt>
|
||||
<dd>Specifies that the code in the given source <code>Range</code>
|
||||
should be removed, and replaced with the given <code>Code</code> string.</dd>
|
||||
</dl>
|
||||
@@ -535,12 +532,12 @@ source code of the program. Important design points include:</p>
|
||||
</ol>
|
||||
|
||||
<p>In practice, the SourceLocation works together with the SourceManager class
|
||||
to encode two pieces of information about a location: its spelling location
|
||||
and its instantiation location. For most tokens, these will be the same.
|
||||
However, for a macro expansion (or tokens that came from a _Pragma directive)
|
||||
these will describe the location of the characters corresponding to the token
|
||||
and the location where the token was used (i.e. the macro instantiation point
|
||||
or the location of the _Pragma itself).</p>
|
||||
to encode two pieces of information about a location: it's spelling location
|
||||
and it's instantiation location. For most tokens, these will be the same. However,
|
||||
for a macro expansion (or tokens that came from a _Pragma directive) these will
|
||||
describe the location of the characters corresponding to the token and the
|
||||
location where the token was used (i.e. the macro instantiation point or the
|
||||
location of the _Pragma itself).</p>
|
||||
|
||||
<p>The Clang front-end inherently depends on the location of a token being
|
||||
tracked correctly. If it is ever incorrect, the front-end may get confused and
|
||||
@@ -548,30 +545,6 @@ die. The reason for this is that the notion of the 'spelling' of a Token in
|
||||
Clang depends on being able to find the original input characters for the token.
|
||||
This concept maps directly to the "spelling location" for the token.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="SourceRange">SourceRange and CharSourceRange</h3>
|
||||
<!-- ======================================================================= -->
|
||||
<!-- mostly taken from
|
||||
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-August/010595.html -->
|
||||
|
||||
<p>Clang represents most source ranges by [first, last], where first and last
|
||||
each point to the beginning of their respective tokens. For example
|
||||
consider the SourceRange of the following statement:</p>
|
||||
<pre>
|
||||
x = foo + bar;
|
||||
^first ^last
|
||||
</pre>
|
||||
|
||||
<p>To map from this representation to a character-based
|
||||
representation, the 'last' location needs to be adjusted to point to
|
||||
(or past) the end of that token with either
|
||||
<code>Lexer::MeasureTokenLength()</code> or
|
||||
<code>Lexer::getLocForEndOfToken()</code>. For the rare cases
|
||||
where character-level source ranges information is needed we use
|
||||
the <code>CharSourceRange</code> class.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libdriver">The Driver Library</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@@ -734,10 +707,9 @@ above, it would be the location of the "a" identifier.</li>
|
||||
last token replaced with the annotation token. In the example above, it would
|
||||
be the location of the "c" identifier.</li>
|
||||
|
||||
<li><b>void* "AnnotationValue"</b> - This contains an opaque object
|
||||
that the parser gets from Sema. The parser merely preserves the
|
||||
information for Sema to later interpret based on the annotation token
|
||||
kind.</li>
|
||||
<li><b>void* "AnnotationValue"</b> - This contains an opaque object that the
|
||||
parser gets from Sema through an Actions module, it is passed around and Sema
|
||||
intepretes it, based on the type of annotation token.</li>
|
||||
|
||||
<li><b>TokenKind "Kind"</b> - This indicates the kind of Annotation token this
|
||||
is. See below for the different valid kinds.</li>
|
||||
@@ -747,29 +719,21 @@ is. See below for the different valid kinds.</li>
|
||||
|
||||
<ol>
|
||||
<li><b>tok::annot_typename</b>: This annotation token represents a
|
||||
resolved typename token that is potentially qualified. The
|
||||
AnnotationValue field contains the <tt>QualType</tt> returned by
|
||||
Sema::getTypeName(), possibly with source location information
|
||||
attached.</li>
|
||||
resolved typename token that is potentially qualified. The AnnotationValue
|
||||
field contains a pointer returned by Action::getTypeName(). In the case of the
|
||||
Sema actions module, this is a <tt>Decl*</tt> for the type.</li>
|
||||
|
||||
<li><b>tok::annot_cxxscope</b>: This annotation token represents a C++
|
||||
scope specifier, such as "A::B::". This corresponds to the grammar
|
||||
productions "::" and ":: [opt] nested-name-specifier". The
|
||||
AnnotationValue pointer is a <tt>NestedNameSpecifier*</tt> returned by
|
||||
the Sema::ActOnCXXGlobalScopeSpecifier and
|
||||
Sema::ActOnCXXNestedNameSpecifier callbacks.</li>
|
||||
<li><b>tok::annot_cxxscope</b>: This annotation token represents a C++ scope
|
||||
specifier, such as "A::B::". This corresponds to the grammar productions "::"
|
||||
and ":: [opt] nested-name-specifier". The AnnotationValue pointer is returned
|
||||
by the Action::ActOnCXXGlobalScopeSpecifier and
|
||||
Action::ActOnCXXNestedNameSpecifier callbacks. In the case of Sema, this is a
|
||||
<tt>DeclContext*</tt>.</li>
|
||||
|
||||
<li><b>tok::annot_template_id</b>: This annotation token represents a
|
||||
C++ template-id such as "foo<int, 4>", where "foo" is the name
|
||||
of a template. The AnnotationValue pointer is a pointer to a malloc'd
|
||||
TemplateIdAnnotation object. Depending on the context, a parsed
|
||||
template-id that names a type might become a typename annotation token
|
||||
(if all we care about is the named type, e.g., because it occurs in a
|
||||
type specifier) or might remain a template-id token (if we want to
|
||||
retain more source location information or produce a new type, e.g.,
|
||||
in a declaration of a class template specialization). template-id
|
||||
annotation tokens that refer to a type can be "upgraded" to typename
|
||||
annotation tokens by the parser.</li>
|
||||
TemplateIdAnnotation object. Depending on the context, a parsed template-id that names a type might become a typename annotation token (if all we care about is the named type, e.g., because it occurs in a type specifier) or might remain a template-id token (if we want to retain more source location information or produce a new type, e.g., in a declaration of a class template specialization). template-id annotation tokens that refer to a type can be "upgraded" to typename annotation tokens by the parser.</li>
|
||||
|
||||
</ol>
|
||||
|
||||
@@ -819,7 +783,7 @@ code is vectorized on X86 and PowerPC hosts).</p>
|
||||
within the filename.</li>
|
||||
<li>When parsing a preprocessor directive (after "<tt>#</tt>") the
|
||||
ParsingPreprocessorDirective mode is entered. This changes the parser to
|
||||
return EOD at a newline.</li>
|
||||
return EOM at a newline.</li>
|
||||
<li>The Lexer uses a LangOptions object to know whether trigraphs are enabled,
|
||||
whether C++ or ObjC keywords are recognized, etc.</li>
|
||||
</ul>
|
||||
@@ -989,12 +953,11 @@ make sense to you :).</p>
|
||||
<h3 id="QualType">The QualType class</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The QualType class is designed as a trivial value class that is
|
||||
small, passed by-value and is efficient to query. The idea of
|
||||
QualType is that it stores the type qualifiers (const, volatile,
|
||||
restrict, plus some extended qualifiers required by language
|
||||
extensions) separately from the types themselves. QualType is
|
||||
conceptually a pair of "Type*" and the bits for these type qualifiers.</p>
|
||||
<p>The QualType class is designed as a trivial value class that is small,
|
||||
passed by-value and is efficient to query. The idea of QualType is that it
|
||||
stores the type qualifiers (const, volatile, restrict) separately from the types
|
||||
themselves: QualType is conceptually a pair of "Type*" and bits for the type
|
||||
qualifiers.</p>
|
||||
|
||||
<p>By storing the type qualifiers as bits in the conceptual pair, it is
|
||||
extremely efficient to get the set of qualifiers on a QualType (just return the
|
||||
@@ -1009,11 +972,10 @@ both point to the same heap allocated "int" type). This reduces the heap size
|
||||
used to represent bits and also means we do not have to consider qualifiers when
|
||||
uniquing types (<a href="#Type">Type</a> does not even contain qualifiers).</p>
|
||||
|
||||
<p>In practice, the two most common type qualifiers (const and
|
||||
restrict) are stored in the low bits of the pointer to the Type
|
||||
object, together with a flag indicating whether extended qualifiers
|
||||
are present (which must be heap-allocated). This means that QualType
|
||||
is exactly the same size as a pointer.</p>
|
||||
<p>In practice, on hosts where it is safe, the 3 type qualifiers are stored in
|
||||
the low bit of the pointer to the Type object. This means that QualType is
|
||||
exactly the same size as a pointer, and this works fine on any system where
|
||||
malloc'd objects are at least 8 byte aligned.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="DeclarationName">Declaration names</h3>
|
||||
@@ -1213,8 +1175,8 @@ void g();
|
||||
void g(int);
|
||||
</pre>
|
||||
<p>the <code>DeclContext::lookup</code> operation will return
|
||||
a <code>DeclContext::lookup_result</code> that contains a range of iterators
|
||||
over declarations of "g". Clients that perform semantic analysis on a
|
||||
an <code>OverloadedFunctionDecl</code> that contains both
|
||||
declarations of "g". Clients that perform semantic analysis on a
|
||||
program that is not concerned with the actual source code will
|
||||
primarily use this semantics-centric view.</p>
|
||||
|
||||
@@ -1396,8 +1358,8 @@ namespace N {
|
||||
nodes in Snippet #1, each of which is a declaration context that
|
||||
contains a single declaration of "f". However, the semantics-centric
|
||||
view provided by name lookup into the namespace <code>N</code> for
|
||||
"f" will return a <code>DeclContext::lookup_result</code> that contains
|
||||
a range of iterators over declarations of "f".</p>
|
||||
"f" will return an <code>OverloadedFunctionDecl</code> that contains
|
||||
both declarations of "f".</p>
|
||||
|
||||
<p><code>DeclContext</code> manages multiply-defined declaration
|
||||
contexts internally. The
|
||||
@@ -1709,304 +1671,10 @@ interacts with constant evaluation:</p>
|
||||
floating-point literal.</li>
|
||||
<li><b><tt>__builtin_abs,copysign,..</tt></b>: These are constant folded as
|
||||
general constant expressions.</li>
|
||||
<li><b><tt>__builtin_strlen</tt></b> and <b><tt>strlen</tt></b>: These are constant folded as integer constant expressions if the argument is a string literal.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="Howtos">How to change Clang</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="AddingAttributes">How to add an attribute</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>To add an attribute, you'll have to add it to the list of attributes, add it
|
||||
to the parsing phase, and look for it in the AST scan.
|
||||
<a href="http://llvm.org/viewvc/llvm-project?view=rev&revision=124217">r124217</a>
|
||||
has a good example of adding a warning attribute.</p>
|
||||
|
||||
<p>(Beware that this hasn't been reviewed/fixed by the people who designed the
|
||||
attributes system yet.)</p>
|
||||
|
||||
<h4><a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?view=markup">include/clang/Basic/Attr.td</a></h4>
|
||||
|
||||
<p>Each attribute gets a <tt>def</tt> inheriting from <tt>Attr</tt> or one of
|
||||
its subclasses. <tt>InheritableAttr</tt> means that the attribute also applies
|
||||
to subsequent declarations of the same name.</p>
|
||||
|
||||
<p><tt>Spellings</tt> lists the strings that can appear in
|
||||
<tt>__attribute__((here))</tt> or <tt>[[here]]</tt>. All such strings
|
||||
will be synonymous. If you want to allow the <tt>[[]]</tt> C++0x
|
||||
syntax, you have to define a list of <tt>Namespaces</tt>, which will
|
||||
let users write <tt>[[namespace:spelling]]</tt>. Using the empty
|
||||
string for a namespace will allow users to write just the spelling
|
||||
with no "<tt>:</tt>".</p>
|
||||
|
||||
<p><tt>Subjects</tt> restricts what kinds of AST node to which this attribute
|
||||
can appertain (roughly, attach).</p>
|
||||
|
||||
<p><tt>Args</tt> names the arguments the attribute takes, in order. If
|
||||
<tt>Args</tt> is <tt>[StringArgument<"Arg1">, IntArgument<"Arg2">]</tt>
|
||||
then <tt>__attribute__((myattribute("Hello", 3)))</tt> will be a valid use.</p>
|
||||
|
||||
<h4>Boilerplate</h4>
|
||||
|
||||
<p>Add an element to the <tt>AttributeList::Kind</tt> enum in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?view=markup">include/clang/Sema/AttributeList.h</a>
|
||||
named <tt>AT_lower_with_underscores</tt>. That is, a CamelCased
|
||||
<tt>AttributeName</tt> in <tt>Attr.td</tt> name should become
|
||||
<tt>AT_attribute_name</tt>.</p>
|
||||
|
||||
<p>Add a case to the <tt>StringSwitch</tt> in <tt>AttributeList::getKind()</tt>
|
||||
in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?view=markup">lib/Sema/AttributeList.cpp</a>
|
||||
for each spelling of your attribute. Less common attributes should come toward
|
||||
the end of that list.</p>
|
||||
|
||||
<p>Write a new <tt>HandleYourAttr()</tt> function in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?view=markup">lib/Sema/SemaDeclAttr.cpp</a>,
|
||||
and add a case to the switch in <tt>ProcessNonInheritableDeclAttr()</tt> or
|
||||
<tt>ProcessInheritableDeclAttr()</tt> forwarding to it.</p>
|
||||
|
||||
<p>If your attribute causes extra warnings to fire, define a <tt>DiagGroup</tt>
|
||||
in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?view=markup">include/clang/Basic/DiagnosticGroups.td</a>
|
||||
named after the attribute's <tt>Spelling</tt> with "_"s replaced by "-"s. If
|
||||
you're only defining one diagnostic, you can skip <tt>DiagnosticGroups.td</tt>
|
||||
and use <tt>InGroup<DiagGroup<"your-attribute">></tt> directly in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?view=markup">DiagnosticSemaKinds.td</a></p>
|
||||
|
||||
<h4>The meat of your attribute</h4>
|
||||
|
||||
<p>Find an appropriate place in Clang to do whatever your attribute needs to do.
|
||||
Check for the attribute's presence using <tt>Decl::getAttr<YourAttr>()</tt>.</p>
|
||||
|
||||
<p>Update the <a href="LanguageExtensions.html">Clang Language Extensions</a>
|
||||
document to describe your new attribute.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="AddingExprStmt">How to add an expression or statement</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Expressions and statements are one of the most fundamental constructs within a
|
||||
compiler, because they interact with many different parts of the AST,
|
||||
semantic analysis, and IR generation. Therefore, adding a new
|
||||
expression or statement kind into Clang requires some care. The following list
|
||||
details the various places in Clang where an expression or statement needs to be
|
||||
introduced, along with patterns to follow to ensure that the new
|
||||
expression or statement works well across all of the C languages. We
|
||||
focus on expressions, but statements are similar.</p>
|
||||
|
||||
<ol>
|
||||
<li>Introduce parsing actions into the parser. Recursive-descent
|
||||
parsing is mostly self-explanatory, but there are a few things that
|
||||
are worth keeping in mind:
|
||||
<ul>
|
||||
<li>Keep as much source location information as possible! You'll
|
||||
want it later to produce great diagnostics and support Clang's
|
||||
various features that map between source code and the AST.</li>
|
||||
<li>Write tests for all of the "bad" parsing cases, to make sure
|
||||
your recovery is good. If you have matched delimiters (e.g.,
|
||||
parentheses, square brackets, etc.), use
|
||||
<tt>Parser::BalancedDelimiterTracker</tt> to give nice diagnostics when
|
||||
things go wrong.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Introduce semantic analysis actions into <tt>Sema</tt>. Semantic
|
||||
analysis should always involve two functions: an <tt>ActOnXXX</tt>
|
||||
function that will be called directly from the parser, and a
|
||||
<tt>BuildXXX</tt> function that performs the actual semantic
|
||||
analysis and will (eventually!) build the AST node. It's fairly
|
||||
common for the <tt>ActOnCXX</tt> function to do very little (often
|
||||
just some minor translation from the parser's representation to
|
||||
<tt>Sema</tt>'s representation of the same thing), but the separation
|
||||
is still important: C++ template instantiation, for example,
|
||||
should always call the <tt>BuildXXX</tt> variant. Several notes on
|
||||
semantic analysis before we get into construction of the AST:
|
||||
<ul>
|
||||
<li>Your expression probably involves some types and some
|
||||
subexpressions. Make sure to fully check that those types, and the
|
||||
types of those subexpressions, meet your expectations. Add
|
||||
implicit conversions where necessary to make sure that all of the
|
||||
types line up exactly the way you want them. Write extensive tests
|
||||
to check that you're getting good diagnostics for mistakes and
|
||||
that you can use various forms of subexpressions with your
|
||||
expression.</li>
|
||||
<li>When type-checking a type or subexpression, make sure to first
|
||||
check whether the type is "dependent"
|
||||
(<tt>Type::isDependentType()</tt>) or whether a subexpression is
|
||||
type-dependent (<tt>Expr::isTypeDependent()</tt>). If any of these
|
||||
return true, then you're inside a template and you can't do much
|
||||
type-checking now. That's normal, and your AST node (when you get
|
||||
there) will have to deal with this case. At this point, you can
|
||||
write tests that use your expression within templates, but don't
|
||||
try to instantiate the templates.</li>
|
||||
<li>For each subexpression, be sure to call
|
||||
<tt>Sema::CheckPlaceholderExpr()</tt> to deal with "weird"
|
||||
expressions that don't behave well as subexpressions. Then,
|
||||
determine whether you need to perform
|
||||
lvalue-to-rvalue conversions
|
||||
(<tt>Sema::DefaultLvalueConversion</tt>e) or
|
||||
the usual unary conversions
|
||||
(<tt>Sema::UsualUnaryConversions</tt>), for places where the
|
||||
subexpression is producing a value you intend to use.</li>
|
||||
<li>Your <tt>BuildXXX</tt> function will probably just return
|
||||
<tt>ExprError()</tt> at this point, since you don't have an AST.
|
||||
That's perfectly fine, and shouldn't impact your testing.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Introduce an AST node for your new expression. This starts with
|
||||
declaring the node in <tt>include/Basic/StmtNodes.td</tt> and
|
||||
creating a new class for your expression in the appropriate
|
||||
<tt>include/AST/Expr*.h</tt> header. It's best to look at the class
|
||||
for a similar expression to get ideas, and there are some specific
|
||||
things to watch for:
|
||||
<ul>
|
||||
<li>If you need to allocate memory, use the <tt>ASTContext</tt>
|
||||
allocator to allocate memory. Never use raw <tt>malloc</tt> or
|
||||
<tt>new</tt>, and never hold any resources in an AST node, because
|
||||
the destructor of an AST node is never called.</li>
|
||||
|
||||
<li>Make sure that <tt>getSourceRange()</tt> covers the exact
|
||||
source range of your expression. This is needed for diagnostics
|
||||
and for IDE support.</li>
|
||||
|
||||
<li>Make sure that <tt>children()</tt> visits all of the
|
||||
subexpressions. This is important for a number of features (e.g., IDE
|
||||
support, C++ variadic templates). If you have sub-types, you'll
|
||||
also need to visit those sub-types in the
|
||||
<tt>RecursiveASTVisitor</tt>.</li>
|
||||
|
||||
<li>Add printing support (<tt>StmtPrinter.cpp</tt>) and dumping
|
||||
support (<tt>StmtDumper.cpp</tt>) for your expression.</li>
|
||||
|
||||
<li>Add profiling support (<tt>StmtProfile.cpp</tt>) for your AST
|
||||
node, noting the distinguishing (non-source location)
|
||||
characteristics of an instance of your expression. Omitting this
|
||||
step will lead to hard-to-diagnose failures regarding matching of
|
||||
template declarations.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Teach semantic analysis to build your AST node! At this point,
|
||||
you can wire up your <tt>Sema::BuildXXX</tt> function to actually
|
||||
create your AST. A few things to check at this point:
|
||||
<ul>
|
||||
<li>If your expression can construct a new C++ class or return a
|
||||
new Objective-C object, be sure to update and then call
|
||||
<tt>Sema::MaybeBindToTemporary</tt> for your just-created AST node
|
||||
to be sure that the object gets properly destructed. An easy way
|
||||
to test this is to return a C++ class with a private destructor:
|
||||
semantic analysis should flag an error here with the attempt to
|
||||
call the destructor.</li>
|
||||
<li>Inspect the generated AST by printing it using <tt>clang -cc1
|
||||
-ast-print</tt>, to make sure you're capturing all of the
|
||||
important information about how the AST was written.</li>
|
||||
<li>Inspect the generated AST under <tt>clang -cc1 -ast-dump</tt>
|
||||
to verify that all of the types in the generated AST line up the
|
||||
way you want them. Remember that clients of the AST should never
|
||||
have to "think" to understand what's going on. For example, all
|
||||
implicit conversions should show up explicitly in the AST.</li>
|
||||
<li>Write tests that use your expression as a subexpression of
|
||||
other, well-known expressions. Can you call a function using your
|
||||
expression as an argument? Can you use the ternary operator?</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Teach code generation to create IR to your AST node. This step
|
||||
is the first (and only) that requires knowledge of LLVM IR. There
|
||||
are several things to keep in mind:
|
||||
<ul>
|
||||
<li>Code generation is separated into scalar/aggregate/complex and
|
||||
lvalue/rvalue paths, depending on what kind of result your
|
||||
expression produces. On occasion, this requires some careful
|
||||
factoring of code to avoid duplication.</li>
|
||||
|
||||
<li><tt>CodeGenFunction</tt> contains functions
|
||||
<tt>ConvertType</tt> and <tt>ConvertTypeForMem</tt> that convert
|
||||
Clang's types (<tt>clang::Type*</tt> or <tt>clang::QualType</tt>)
|
||||
to LLVM types.
|
||||
Use the former for values, and the later for memory locations:
|
||||
test with the C++ "bool" type to check this. If you find
|
||||
that you are having to use LLVM bitcasts to make
|
||||
the subexpressions of your expression have the type that your
|
||||
expression expects, STOP! Go fix semantic analysis and the AST so
|
||||
that you don't need these bitcasts.</li>
|
||||
|
||||
<li>The <tt>CodeGenFunction</tt> class has a number of helper
|
||||
functions to make certain operations easy, such as generating code
|
||||
to produce an lvalue or an rvalue, or to initialize a memory
|
||||
location with a given value. Prefer to use these functions rather
|
||||
than directly writing loads and stores, because these functions
|
||||
take care of some of the tricky details for you (e.g., for
|
||||
exceptions).</li>
|
||||
|
||||
<li>If your expression requires some special behavior in the event
|
||||
of an exception, look at the <tt>push*Cleanup</tt> functions in
|
||||
<tt>CodeGenFunction</tt> to introduce a cleanup. You shouldn't
|
||||
have to deal with exception-handling directly.</li>
|
||||
|
||||
<li>Testing is extremely important in IR generation. Use <tt>clang
|
||||
-cc1 -emit-llvm</tt> and <a
|
||||
href="http://llvm.org/cmds/FileCheck.html">FileCheck</a> to verify
|
||||
that you're generating the right IR.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Teach template instantiation how to cope with your AST
|
||||
node, which requires some fairly simple code:
|
||||
<ul>
|
||||
<li>Make sure that your expression's constructor properly
|
||||
computes the flags for type dependence (i.e., the type your
|
||||
expression produces can change from one instantiation to the
|
||||
next), value dependence (i.e., the constant value your expression
|
||||
produces can change from one instantiation to the next),
|
||||
instantiation dependence (i.e., a template parameter occurs
|
||||
anywhere in your expression), and whether your expression contains
|
||||
a parameter pack (for variadic templates). Often, computing these
|
||||
flags just means combining the results from the various types and
|
||||
subexpressions.</li>
|
||||
|
||||
<li>Add <tt>TransformXXX</tt> and <tt>RebuildXXX</tt> functions to
|
||||
the
|
||||
<tt>TreeTransform</tt> class template in <tt>Sema</tt>.
|
||||
<tt>TransformXXX</tt> should (recursively) transform all of the
|
||||
subexpressions and types
|
||||
within your expression, using <tt>getDerived().TransformYYY</tt>.
|
||||
If all of the subexpressions and types transform without error, it
|
||||
will then call the <tt>RebuildXXX</tt> function, which will in
|
||||
turn call <tt>getSema().BuildXXX</tt> to perform semantic analysis
|
||||
and build your expression.</li>
|
||||
|
||||
<li>To test template instantiation, take those tests you wrote to
|
||||
make sure that you were type checking with type-dependent
|
||||
expressions and dependent types (from step #2) and instantiate
|
||||
those templates with various types, some of which type-check and
|
||||
some that don't, and test the error messages in each case.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>There are some "extras" that make other features work better.
|
||||
It's worth handling these extras to give your expression complete
|
||||
integration into Clang:
|
||||
<ul>
|
||||
<li>Add code completion support for your expression in
|
||||
<tt>SemaCodeComplete.cpp</tt>.</li>
|
||||
|
||||
<li>If your expression has types in it, or has any "interesting"
|
||||
features other than subexpressions, extend libclang's
|
||||
<tt>CursorVisitor</tt> to provide proper visitation for your
|
||||
expression, enabling various IDE features such as syntax
|
||||
highlighting, cross-referencing, and so on. The
|
||||
<tt>c-index-test</tt> helper program can be used to test these
|
||||
features.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ..
|
||||
LEVEL := ../../..
|
||||
DIRS := tools
|
||||
|
||||
ifdef BUILD_FOR_WEBSITE
|
||||
@@ -16,13 +16,13 @@ DOXYGEN = doxygen
|
||||
|
||||
$(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
|
||||
cat $< | sed \
|
||||
-e 's/@abs_srcdir@/./g' \
|
||||
-e 's/@abs_top_srcdir@/../g' \
|
||||
-e 's/@DOT@/dot/g' \
|
||||
-e 's/@PACKAGE_VERSION@/mainline/' \
|
||||
-e 's/@abs_builddir@/./g' > $@
|
||||
-e 's/@abs_top_builddir@/../g' > $@
|
||||
endif
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
HTML := $(wildcard $(PROJ_SRC_DIR)/*.html) \
|
||||
$(wildcard $(PROJ_SRC_DIR)/*.css)
|
||||
@@ -59,7 +59,7 @@ $(PROJ_OBJ_DIR)/html.tar.gz: $(HTML)
|
||||
$(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
|
||||
$(Verb) $(GZIP) $(PROJ_OBJ_DIR)/html.tar
|
||||
|
||||
install-doxygen: doxygen
|
||||
$(Echo) Installing doxygen documentation
|
||||
@@ -82,7 +82,7 @@ $(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) $(GZIP) $(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
|
||||
|
||||
@@ -144,15 +144,6 @@ 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" align="right" alt="Precompiled header layout">
|
||||
@@ -218,27 +209,6 @@ 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
|
||||
@@ -391,23 +361,23 @@ 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
|
||||
subexpressions of an expression are stored 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>IntegerLiteral(4)</code></td></tr>
|
||||
<tr><td><code>BinaryOperator(-)</code></td></tr>
|
||||
<tr><td><code>IntegerLiteral(5)</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,
|
||||
record it encounters, builds the appropriate abstract synax 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
|
||||
|
||||
@@ -32,20 +32,16 @@ td {
|
||||
</li>
|
||||
<li><a href="#general_features">Language and Target-Independent Features</a>
|
||||
<ul>
|
||||
<li><a href="#diagnostics">Controlling Errors and Warnings</a>
|
||||
<li><a href="#diagnostics">Controlling Errors and Warnings</a></li>
|
||||
<ul>
|
||||
<li><a href="#diagnostics_display">Controlling How Clang Displays Diagnostics</a></li>
|
||||
<li><a href="#diagnostics_mappings">Diagnostic Mappings</a></li>
|
||||
<li><a href="#diagnostics_categories">Diagnostic Categories</a></li>
|
||||
<li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li>
|
||||
<li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
|
||||
<li><a href="#diagnostics_enable_everything">Enabling All Warnings</a></li>
|
||||
<li><a href="#analyzer_diagnositics">Controlling Static Analyzer Diagnostics</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#precompiledheaders">Precompiled Headers</a></li>
|
||||
<li><a href="#codegen">Controlling Code Generation</a></li>
|
||||
</ul>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#c">C Language Features</a>
|
||||
<ul>
|
||||
@@ -56,6 +52,16 @@ td {
|
||||
<li><a href="#c_ms">Microsoft extensions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#objc">Objective-C Language Features</a>
|
||||
<ul>
|
||||
<li><a href="#objc_incompatibilities">Intentional Incompatibilities with
|
||||
GCC</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#cxx">C++ Language Features</a>
|
||||
</li>
|
||||
<li><a href="#objcxx">Objective C++ Language Features</a>
|
||||
</li>
|
||||
<li><a href="#target_features">Target-Specific Features and Limitations</a>
|
||||
<ul>
|
||||
<li><a href="#target_arch">CPU Architectures Features and Limitations</a>
|
||||
@@ -69,8 +75,8 @@ td {
|
||||
<ul>
|
||||
<li><a href="#target_os_darwin">Darwin (Mac OS/X)</a></li>
|
||||
<li>Linux, etc.</li>
|
||||
<li><a href="#target_os_win32">Windows</a></li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -183,12 +189,6 @@ introduces the language selection and other high level options like -c, -g, etc.
|
||||
<p><b>-pedantic-errors</b>: Error on language extensions.</p>
|
||||
<p><b>-Wsystem-headers</b>: Enable warnings from system headers.</p>
|
||||
|
||||
<p><b>-ferror-limit=123</b>: Stop emitting diagnostics after 123 errors have
|
||||
been produced. The default is 20, and the error limit can be disabled with
|
||||
-ferror-limit=0.</p>
|
||||
|
||||
<p><b>-ftemplate-backtrace-limit=123</b>: Only emit up to 123 template instantiation notes within the template instantiation backtrace for a single warning or error. The default is 10, and the limit can be disabled with -ftemplate-backtrace-limit=0.</p>
|
||||
|
||||
<!-- ================================================= -->
|
||||
<h4 id="cl_diag_formatting">Formatting of Diagnostics</h4>
|
||||
<!-- ================================================= -->
|
||||
@@ -207,7 +207,7 @@ diagnostics that it generates.</p>
|
||||
diagnostic.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
column number of a diagnostic. For example, when this is enabled, Clang will
|
||||
print something like:
|
||||
print something like:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
@@ -225,7 +225,7 @@ column number.</p>
|
||||
source file/line/column information in diagnostic.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
filename, line number and column number of a diagnostic. For example,
|
||||
when this is enabled, Clang will print something like:
|
||||
when this is enabled, Clang will print something like:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
@@ -242,7 +242,7 @@ when this is enabled, Clang will print something like:
|
||||
line and ranges from source code in diagnostic.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
source line, source ranges, and caret when emitting a diagnostic. For example,
|
||||
when this is enabled, Clang will print something like:
|
||||
when this is enabled, Clang will print something like:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
@@ -250,65 +250,22 @@ when this is enabled, Clang will print something like:
|
||||
^
|
||||
//
|
||||
</pre>
|
||||
</dd>
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fcolor_diagnostics"><b>-f[no-]color-diagnostics</b>: </dt>
|
||||
<dd>This option, which defaults to on when a color-capable terminal is
|
||||
detected, controls whether or not Clang prints diagnostics in color.
|
||||
When this option is enabled, Clang will use colors to highlight
|
||||
specific parts of the diagnostic, e.g.,
|
||||
<pre>
|
||||
<b><font color="black">test.c:28:8: <font color="magenta">warning</font>: extra tokens at end of #endif directive [-Wextra-tokens]</font></b>
|
||||
#endif bad
|
||||
<font color="green">^</font>
|
||||
<font color="green">//</font>
|
||||
</pre>
|
||||
|
||||
<p>When this is disabled, Clang will just print:</p>
|
||||
|
||||
<pre>
|
||||
test.c:2:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
#endif bad
|
||||
^
|
||||
//
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
</pre>
|
||||
</dd>
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-format"><b>-fdiagnostics-format=clang/msvc/vi</b>:
|
||||
Changes diagnostic output format to better match IDEs and command line tools.</dt>
|
||||
<dd>This option controls the output format of the filename, line number, and column printed in diagnostic messages. The options, and their affect on formatting a simple conversion diagnostic, follow:
|
||||
|
||||
<dl>
|
||||
<dt><b>clang</b> (default)</dt>
|
||||
<dd>
|
||||
<pre>t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
|
||||
</dd>
|
||||
|
||||
<dt><b>msvc</b></dt>
|
||||
<dd>
|
||||
<pre>t.c(3,11) : warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
|
||||
</dd>
|
||||
|
||||
<dt><b>vi</b></dt>
|
||||
<dd>
|
||||
<pre>t.c +3:11: warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-show-name"><b>-f[no-]diagnostics-show-name</b>:
|
||||
Enable the display of the diagnostic name.</dt>
|
||||
<dd>This option, which defaults to off, controls whether or not
|
||||
Clang prints the associated name.</dd>
|
||||
<br>
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
|
||||
Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
|
||||
<dd>This option, which defaults to on,
|
||||
controls whether or not Clang prints the associated <A
|
||||
href="#cl_diag_warning_groups">warning group</a> option name when outputting
|
||||
a warning diagnostic. For example, in this output:
|
||||
a warning diagnostic. For example, in this output:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
@@ -323,37 +280,13 @@ diagnostic. This information tells you the flag needed to enable or disable the
|
||||
diagnostic, either from the command line or through <a
|
||||
href="#pragma_GCC_diagnostic">#pragma GCC diagnostic</a>.</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-show-category"><b>-fdiagnostics-show-category=none/id/name</b>:
|
||||
Enable printing category information in diagnostic line.</dt>
|
||||
<dd>This option, which defaults to "none",
|
||||
controls whether or not Clang prints the category associated with a diagnostic
|
||||
when emitting it. Each diagnostic may or many not have an associated category,
|
||||
if it has one, it is listed in the diagnostic categorization field of the
|
||||
diagnostic line (in the []'s).
|
||||
|
||||
<p>For example, a format string warning will produce these three renditions
|
||||
based on the setting of this option:</p>
|
||||
|
||||
<pre>
|
||||
t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat]
|
||||
t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,1</b>]
|
||||
t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,Format String</b>]
|
||||
</pre>
|
||||
|
||||
<p>This category can be used by clients that want to group diagnostics by
|
||||
category, so it should be a high level category. We want dozens of these, not
|
||||
hundreds or thousands of them.</p>
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-fixit-info"><b>-f[no-]diagnostics-fixit-info</b>:
|
||||
Enable "FixIt" information in the diagnostics output.</dt>
|
||||
<dd>This option, which defaults to on, controls whether or not Clang prints the
|
||||
information on how to fix a specific diagnostic underneath it when it knows.
|
||||
For example, in this output:
|
||||
For example, in this output:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
@@ -376,7 +309,7 @@ Print machine parsable information about source ranges.</dt>
|
||||
information about source ranges in a machine parsable format after the
|
||||
file/line/column number information. The information is a simple sequence of
|
||||
brace enclosed ranges, where each range lists the start and end line/column
|
||||
locations. For example, in this output:
|
||||
locations. For example, in this output:</p>
|
||||
|
||||
<pre>
|
||||
exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expression ('int *' and '_Complex float')
|
||||
@@ -387,25 +320,6 @@ exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expre
|
||||
<p>The {}'s are generated by -fdiagnostics-print-source-range-info.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-parseable-fixits">
|
||||
<b>-fdiagnostics-parseable-fixits</b>:
|
||||
Print Fix-Its in a machine parseable form.</dt>
|
||||
<dd><p>This option makes Clang print available Fix-Its in a machine parseable format at the end of diagnostics. The following example illustrates the format:</p>
|
||||
|
||||
<pre>
|
||||
fix-it:"t.cpp":{7:25-7:29}:"Gamma"
|
||||
</pre>
|
||||
|
||||
<p>The range printed is a half-open range, so in this example the characters at
|
||||
column 25 up to but not including column 29 on line 7 in t.cpp should be
|
||||
replaced with the string "Gamma". Either the range or the replacement
|
||||
string may be empty (representing strict insertions and strict erasures,
|
||||
respectively). Both the file name and the insertion string escape backslash (as
|
||||
"\\"), tabs (as "\t"), newlines (as "\n"), double
|
||||
quotes(as "\"") and non-printable characters (as octal
|
||||
"\xxx").</p>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
@@ -426,7 +340,7 @@ quotes(as "\"") and non-printable characters (as octal
|
||||
<dt id="opt_Wextra-tokens"><b>-Wextra-tokens</b>: Warn about excess tokens at
|
||||
the end of a preprocessor directive.</dt>
|
||||
<dd>This option, which defaults to on, enables warnings about extra tokens at
|
||||
the end of preprocessor directives. For example:
|
||||
the end of preprocessor directives. For example:</p>
|
||||
|
||||
<pre>
|
||||
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
|
||||
@@ -441,66 +355,6 @@ by commenting them out.</p>
|
||||
and <a href="">-Wbaz</a>.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_Wambiguous-member-template"><b>-Wambiguous-member-template</b>:
|
||||
Warn about unqualified uses of a member template whose name resolves
|
||||
to another template at the location of the use.</dt>
|
||||
<dd>This option, which defaults to on, enables a warning in the
|
||||
following code:
|
||||
|
||||
<pre>
|
||||
template<typename T> struct set{};
|
||||
template<typename T> struct trait { typedef const T& type; };
|
||||
struct Value {
|
||||
template<typename T> void set(typename trait<T>::type value) {}
|
||||
};
|
||||
void foo() {
|
||||
Value v;
|
||||
v.set<double>(3.2);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>C++ [basic.lookup.classref] requires this to be an error, but,
|
||||
because it's hard to work around, Clang downgrades it to a warning as
|
||||
an extension.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_Wbind-to-temporary-copy"><b>-Wbind-to-temporary-copy</b>: Warn about
|
||||
an unusable copy constructor when binding a reference to a temporary.</dt>
|
||||
<dd>This option, which defaults to on, enables warnings about binding a
|
||||
reference to a temporary when the temporary doesn't have a usable copy
|
||||
constructor. For example:
|
||||
|
||||
<pre>
|
||||
struct NonCopyable {
|
||||
NonCopyable();
|
||||
private:
|
||||
NonCopyable(const NonCopyable&);
|
||||
};
|
||||
void foo(const NonCopyable&);
|
||||
void bar() {
|
||||
foo(NonCopyable()); // Disallowed in C++98; allowed in C++0x.
|
||||
}
|
||||
</pre>
|
||||
<pre>
|
||||
struct NonCopyable2 {
|
||||
NonCopyable2();
|
||||
NonCopyable2(NonCopyable2&);
|
||||
};
|
||||
void foo(const NonCopyable2&);
|
||||
void bar() {
|
||||
foo(NonCopyable2()); // Disallowed in C++98; allowed in C++0x.
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Note that if <tt>NonCopyable2::NonCopyable2()</tt> has a default
|
||||
argument whose instantiation produces a compile error, that error will
|
||||
still be a hard error in C++98 mode even if this warning is turned
|
||||
off.</p>
|
||||
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
@@ -522,6 +376,7 @@ and gives you fine-grain control over which information is printed. Clang has
|
||||
the ability to print this information, and these are the options that control
|
||||
it:</p>
|
||||
|
||||
<p>
|
||||
<ol>
|
||||
<li>A file/line/column indicator that shows exactly where the diagnostic occurs
|
||||
in your code [<a href="#opt_fshow-column">-fshow-column</a>, <a
|
||||
@@ -529,15 +384,9 @@ it:</p>
|
||||
<li>A categorization of the diagnostic as a note, warning, error, or fatal
|
||||
error.</li>
|
||||
<li>A text string that describes what the problem is.</li>
|
||||
<li>An option that indicates whether to print the diagnostic name [<a
|
||||
href="#opt_fdiagnostics-show-name">-fdiagnostics-show-name</a>].</li>
|
||||
<li>An option that indicates how to control the diagnostic (for diagnostics that
|
||||
support it) [<a
|
||||
href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li>
|
||||
<li>A <a href="#diagnostics_categories">high-level category</a> for the
|
||||
diagnostic for clients that want to group diagnostics by class (for
|
||||
diagnostics that support it) [<a
|
||||
href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a>].</li>
|
||||
<li>The line of source code that the issue occurs on, along with a caret and
|
||||
ranges that indicate the important locations [<a
|
||||
href="opt_fcaret-diagnostics">-fcaret-diagnostics</a>].</li>
|
||||
@@ -547,41 +396,25 @@ it:</p>
|
||||
<li>A machine-parsable representation of the ranges involved (off by
|
||||
default) [<a
|
||||
href="opt_fdiagnostics-print-source-range-info">-fdiagnostics-print-source-range-info</a>].</li>
|
||||
</ol>
|
||||
</ol></p>
|
||||
|
||||
<p>For more information please see <a href="#cl_diag_formatting">Formatting of
|
||||
Diagnostics</a>.</p>
|
||||
|
||||
|
||||
<h4 id="diagnostics_mappings">Diagnostic Mappings</h4>
|
||||
|
||||
<p>All diagnostics are mapped into one of these 5 classes:</p>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>Ignored</li>
|
||||
<li>Note</li>
|
||||
<li>Warning</li>
|
||||
<li>Error</li>
|
||||
<li>Fatal</li>
|
||||
</ul>
|
||||
</ul></p>
|
||||
|
||||
<h4 id="diagnostics_categories">Diagnostic Categories</h4>
|
||||
|
||||
<p>Though not shown by default, diagnostics may each be associated with a
|
||||
high-level category. This category is intended to make it possible to triage
|
||||
builds that produce a large number of errors or warnings in a grouped way.
|
||||
</p>
|
||||
|
||||
<p>Categories are not shown by default, but they can be turned on with the
|
||||
<a href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a> option.
|
||||
When set to "<tt>name</tt>", the category is printed textually in the diagnostic
|
||||
output. When it is set to "<tt>id</tt>", a category number is printed. The
|
||||
mapping of category names to category id's can be obtained by running '<tt>clang
|
||||
--print-diagnostic-categories</tt>'.
|
||||
</p>
|
||||
|
||||
<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line
|
||||
Flags</h4>
|
||||
<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line Flags</h4>
|
||||
|
||||
<p>-W flags, -pedantic, etc</p>
|
||||
|
||||
@@ -600,7 +433,7 @@ example code will tell Clang or GCC to ignore the -Wall warnings:</p>
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
</pre>
|
||||
|
||||
<p>In addition to all of the functionality provided by GCC's pragma, Clang
|
||||
<p>In addition to all of the functionality of provided by GCC's pragma, Clang
|
||||
also allows you to push and pop the current warning state. This is particularly
|
||||
useful when writing a header file that will be compiled by other people, because
|
||||
you don't know what warning flags they build with.</p>
|
||||
@@ -627,52 +460,6 @@ GCC do not support the exact same set of warnings, so even when using GCC
|
||||
compatible #pragmas there is no guarantee that they will have identical behaviour
|
||||
on both compilers. </p>
|
||||
|
||||
<h4 id="diagnostics_enable_everything">Enabling All Warnings</h4>
|
||||
|
||||
<p>In addition to the traditional <tt>-W</tt> flags, one can enable <b>all</b>
|
||||
warnings by passing <tt>-Weverything</tt>.
|
||||
This works as expected with <tt>-Werror</tt>,
|
||||
and also includes the warnings from <tt>-pedantic</tt>.</p>
|
||||
|
||||
<p>Note that when combined with <tt>-w</tt> (which disables all warnings), that
|
||||
flag wins.</p>
|
||||
|
||||
<h4 id="analyzer_diagnositics">Controlling Static Analyzer Diagnostics</h4>
|
||||
|
||||
<p>While not strictly part of the compiler, the diagnostics from Clang's <a
|
||||
href="http://clang-analyzer.llvm.org">static analyzer</a> can also be influenced
|
||||
by the user via changes to the source code. This can be done in two ways:
|
||||
|
||||
<ul>
|
||||
|
||||
<li id="analyzer_annotations"><b>Annotations</b>: The static analyzer recognizes various GCC-style
|
||||
attributes (e.g., <tt>__attribute__((nonnull)))</tt>) that can either suppress
|
||||
static analyzer warnings or teach the analyzer about code invariants which
|
||||
enable it to find more bugs. While many of these attributes are standard GCC
|
||||
attributes, additional ones have been added to Clang to specifically support the
|
||||
static analyzer. Detailed information on these annotations can be found in the
|
||||
<a href="http://clang-analyzer.llvm.org/annotations.html">analyzer's
|
||||
documentation</a>.</li>
|
||||
|
||||
<li><b><tt>__clang_analyzer__</tt></b>: When the static analyzer is using Clang
|
||||
to parse source files, it implicitly defines the preprocessor macro
|
||||
<tt>__clang_analyzer__</tt>. While discouraged, code can use this macro to
|
||||
selectively exclude code the analyzer examines. Here is an example:
|
||||
|
||||
<pre>
|
||||
#ifndef __clang_analyzer__
|
||||
// Code not to be analyzed
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
In general, this usage is discouraged. Instead, we prefer that users file bugs
|
||||
against the analyzer when it flags false positives. There is also active
|
||||
discussion of allowing users in the future to selectively silence specific
|
||||
analyzer warnings (some of which can already be done using <a
|
||||
href="analyzer_annotations">annotations</a>).</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="precompiledheaders">Precompiled Headers</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
@@ -687,7 +474,7 @@ Precompiled header files, which represent one of many ways to implement
|
||||
this optimization, are literally files that represent an on-disk cache that
|
||||
contains the vital information necessary to reduce some of the work
|
||||
needed to process a corresponding header file. While details of precompiled
|
||||
headers vary between compilers, precompiled headers have been shown to be
|
||||
headers vary between compilers, precompiled headers have been shown to be a
|
||||
highly effective at speeding up program compilation on systems with very large
|
||||
system headers (e.g., Mac OS/X).</p>
|
||||
|
||||
@@ -783,16 +570,15 @@ likely to affect PCH files that reference a large number of headers.</p>
|
||||
<p>Clang provides a number of ways to control code generation. The options are listed below.</p>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dl>
|
||||
<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>: Turn
|
||||
on runtime code generation to check for undefined behavior.</dt>
|
||||
|
||||
<dd>This option, which defaults to off, controls whether or not Clang
|
||||
adds runtime checks for undefined runtime behavior. If a check fails,
|
||||
adds runtime checks for undefined runtime behavior. If the check fails,
|
||||
<tt>__builtin_trap()</tt> is used to indicate failure.
|
||||
The checks are:
|
||||
<ul>
|
||||
<li>Subscripting where the static type of one operand is a variable
|
||||
<p>
|
||||
<li>Subscripting where the static type of one operand is variable
|
||||
which is decayed from an array type and the other operand is
|
||||
greater than the size of the array or less than zero.</li>
|
||||
<li>Shift operators where the amount shifted is greater or equal to the
|
||||
@@ -801,28 +587,15 @@ The checks are:
|
||||
<li>When llvm implements more __builtin_object_size support, reads and
|
||||
writes for objects that __builtin_object_size indicates we aren't
|
||||
accessing valid memory. Bit-fields and vectors are not yet checked.
|
||||
</ul>
|
||||
</p>
|
||||
</dd>
|
||||
|
||||
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
|
||||
Don't assume that the C++'s new operator is sane.</dt>
|
||||
<dd>This option tells the compiler to do not assume that C++'s global new
|
||||
operator will always return a pointer that does not
|
||||
operator will always return a pointer that do not
|
||||
alias any other pointer when the function returns.</dd>
|
||||
|
||||
<dt id="opt_ftrap-function"><b>-ftrap-function=[name]</b>: Instruct code
|
||||
generator to emit a function call to the specified function name for
|
||||
<tt>__builtin_trap()</tt>.</dt>
|
||||
|
||||
<dd>LLVM code generator translates <tt>__builtin_trap()</tt> to a trap
|
||||
instruction if it is supported by the target ISA. Otherwise, the builtin is
|
||||
translated into a call to <tt>abort</tt>. If this option is set, then the code
|
||||
generator will always lower the builtin to a call to the specified function
|
||||
regardless of whether the target ISA has a trap instruction. This option is
|
||||
useful for environments (e.g. deeply embedded) where a trap cannot be properly
|
||||
handled, or when some custom behavior is desired.</dd>
|
||||
</dl>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="c">C Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@@ -857,10 +630,6 @@ variants "__asm__" and "__typeof__" are recognized in all modes.</li>
|
||||
<li>The Apple "blocks" extension is recognized by default in gnu* modes
|
||||
on some platforms; it can be enabled in any mode with the "-fblocks"
|
||||
option.</li>
|
||||
<li>Arrays that are VLA's according to the standard, but which can be constant
|
||||
folded by the frontend are treated as fixed size arrays. This occurs for
|
||||
things like "int X[(1, 2)];", which is technically a VLA. c* modes are
|
||||
strictly compliant and treat these as VLAs.</li>
|
||||
</ul>
|
||||
|
||||
<p>Differences between *89 and *99 modes:</p>
|
||||
@@ -891,12 +660,31 @@ c94 mode (FIXME: And __STDC_VERSION__ should be defined!).</p>
|
||||
extensions are not implemented yet:</p>
|
||||
|
||||
<ul>
|
||||
<li>clang does not support __label__
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=3429">bug 3429</a>). This is
|
||||
a relatively small feature, so it is likely to be implemented relatively
|
||||
soon.</li>
|
||||
|
||||
<li>clang does not support attributes on function pointers
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=2461">bug 2461</a>). This is
|
||||
a relatively important feature, so it is likely to be implemented relatively
|
||||
soon.</li>
|
||||
|
||||
<li>clang does not support #pragma weak
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=3679">bug 3679</a>). Due to
|
||||
the uses described in the bug, this is likely to be implemented at some
|
||||
point, at least partially.</li>
|
||||
|
||||
<li>clang does not support #pragma align
|
||||
(<a href="http://llvm.org/bugs/show_bug.cgi?id=3811">bug 3811</a>). This is a
|
||||
relatively small feature, so it is likely to be implemented relatively
|
||||
soon.</li>
|
||||
|
||||
<li>clang does not support code generation for local variables pinned to
|
||||
registers (<a href="http://llvm.org/bugs/show_bug.cgi?id=3933">bug 3933</a>).
|
||||
This is a relatively small feature, so it is likely to be implemented
|
||||
relatively soon.</li>
|
||||
|
||||
<li>clang does not support decimal floating point types (_Decimal32 and
|
||||
friends) or fixed-point types (_Fract and friends); nobody has expressed
|
||||
interest in these features yet, so it's hard to say when they will be
|
||||
@@ -941,15 +729,20 @@ bug-reporting guidelines somewhere?).</p>
|
||||
<ul>
|
||||
|
||||
<li>clang does not support the gcc extension that allows variable-length arrays
|
||||
in structures. This is for a few reasons: one, it is tricky
|
||||
in structures. This is for a few of reasons: one, it is tricky
|
||||
to implement, two, the extension is completely undocumented, and three, the
|
||||
extension appears to be rarely used. Note that clang <em>does</em> support
|
||||
flexible array members (arrays with a zero or unspecified size at the end of
|
||||
a structure).</li>
|
||||
extension appears to be rarely used.</li>
|
||||
|
||||
<li>clang does not support duplicate definitions of a function where one is
|
||||
inline. This complicates clients of the AST which normally can expect there is
|
||||
at most one definition for each function. Source code using this feature should
|
||||
be changed to define the inline and out-of-line definitions in separate
|
||||
translation units.</li>
|
||||
|
||||
<li>clang does not have an equivalent to gcc's "fold"; this means that
|
||||
clang doesn't accept some constructs gcc might accept in contexts where a
|
||||
constant expression is required, like "x-x" where x is a variable.</li>
|
||||
constant expression is required, like "x-x" where x is a variable, or calls
|
||||
to C library functions like strlen.</li>
|
||||
|
||||
<li>clang does not support multiple alternative constraints in inline asm; this
|
||||
is an extremely obscure feature which would be complicated to implement
|
||||
@@ -971,13 +764,6 @@ support is incomplete; enabling Microsoft extensions will silently drop
|
||||
certain constructs (including __declspec and Microsoft-style asm statements).
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>clang allows setting _MSC_VER with -fmsc-version=. It defaults to 1300 which
|
||||
is the same as Visual C/C++ 2003. Any number is supported and can greatly affect
|
||||
what Windows SDK and c++stdlib headers clang can compile. This option will be
|
||||
removed when clang supports the full set of MS extensions required for these
|
||||
headers.</li>
|
||||
|
||||
<li>clang does not support the Microsoft extension where anonymous
|
||||
record members can be declared using user defined typedefs.</li>
|
||||
|
||||
@@ -985,7 +771,38 @@ record members can be declared using user defined typedefs.</li>
|
||||
controlling record layout. GCC also contains support for this feature,
|
||||
however where MSVC and GCC are incompatible clang follows the MSVC
|
||||
definition.</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objc">Objective-C Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="objc_incompatibilities">Intentional Incompatibilities with GCC</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>No cast of super, no lvalue casts.</p>
|
||||
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="cxx">C++ Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>At this point, Clang C++ is not production-quality and is not recommended for use beyond experimentation. However, Clang C++ support
|
||||
is under active development and is progressing rapidly. Please see the <a
|
||||
href="http://clang.llvm.org/cxx_status.html">C++ Status</a> page for details or
|
||||
ask on the mailing list about how you can help.</p>
|
||||
|
||||
<p>Note that released Clang compilers will refuse to even try to use clang to compile C++ code unless you pass the <tt>-ccc-clang-cxx</tt> option to the driver. To turn on Clang's C++ support, please pass that flag. Clang compilers built from the Subversion trunk enable C++ support by default, and do not require the <tt>-ccc-clang-cxx</tt> flag.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objcxx">Objective C++ Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>At this point, Clang C++ support is not generally useful (and therefore,
|
||||
neither is Objective-C++). Please see the <a href="#cxx">C++ section</a> for
|
||||
more information.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="target_features">Target-Specific Features and Limitations</h2>
|
||||
@@ -999,23 +816,16 @@ definition.</li>
|
||||
<!-- ======================== -->
|
||||
<h4 id="target_arch_x86">X86</h4>
|
||||
<!-- ======================== -->
|
||||
|
||||
<p>The support for X86 (both 32-bit and 64-bit) is considered stable on Darwin
|
||||
(Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested to correctly
|
||||
compile many large C, C++, Objective-C, and Objective-C++ codebases.</p>
|
||||
|
||||
<p>On x86_64-mingw32, passing i128(by value) is incompatible to Microsoft x64
|
||||
calling conversion. You might need to tweak WinX86_64ABIInfo::classify()
|
||||
in lib/CodeGen/TargetInfo.cpp.</p>
|
||||
<p>The support for X86 (both 32-bit and 64-bit) is considered stable
|
||||
on Darwin (Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested to
|
||||
correctly compile large C and Objective-C codebases. (FIXME: Anything specific
|
||||
we want to say here? Possibly mention some LLVM x86 limitations?)
|
||||
|
||||
<!-- ======================== -->
|
||||
<h4 id="target_arch_arm">ARM</h4>
|
||||
<!-- ======================== -->
|
||||
|
||||
<p>The support for ARM (specifically ARMv6 and ARMv7) is considered stable on
|
||||
Darwin (iOS): it has been tested to correctly compile many large C, C++,
|
||||
Objective-C, and Objective-C++ codebases. Clang only supports a limited number
|
||||
of ARM architectures. It does not yet fully support ARMv5, for example.</p>
|
||||
ARM support is mostly feature-complete, but still experimental; it hasn't
|
||||
undergone significant testing.
|
||||
|
||||
<!-- ======================== -->
|
||||
<h4 id="target_arch_other">Other platforms</h4>
|
||||
@@ -1024,6 +834,9 @@ clang currently contains some support for PPC and Sparc; however, significant
|
||||
pieces of code generation are still missing, and they haven't undergone
|
||||
significant testing.
|
||||
|
||||
<p>clang contains some support for the embedded PIC16 processor
|
||||
(FIXME: I haven't been keeping track of this; what should this say?).
|
||||
|
||||
<p>clang contains limited support for the MSP430 embedded processor, but both
|
||||
the clang support and the LLVM backend support are highly experimental.
|
||||
|
||||
@@ -1045,54 +858,6 @@ Generating assembly requires a suitable LLVM backend.
|
||||
|
||||
<p>No __thread support, 64-bit ObjC support requires SL tools.</p>
|
||||
|
||||
<!-- ======================================= -->
|
||||
<h4 id="target_os_win32">Windows</h4>
|
||||
<!-- ======================================= -->
|
||||
|
||||
<p>Experimental supports are on Cygming.</p>
|
||||
|
||||
<h5>Cygwin</h5>
|
||||
|
||||
<p>Clang works on Cygwin-1.7.</p>
|
||||
|
||||
<h5>MinGW32</h5>
|
||||
|
||||
<p>Clang works on some mingw32 distributions.
|
||||
Clang assumes directories as below;</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>C:/mingw/include</tt></li>
|
||||
<li><tt>C:/mingw/lib</tt></li>
|
||||
<li><tt>C:/mingw/lib/gcc/mingw32/4.[3-5].0/include/c++</tt></li>
|
||||
</ul>
|
||||
|
||||
<p>On MSYS, a few tests might fail. It is due to <a href="http://llvm.org/bugs/show_bug.cgi?id=8520">Bug 8520</a> and is fixed in <a href="http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20110314/118106.html">LLVM's r127724</a>.</p>
|
||||
|
||||
<h5>MinGW-w64</h5>
|
||||
|
||||
<p>For 32-bit (i686-w64-mingw32), and 64-bit (x86_64-w64-mingw32), Clang assumes as below;<p>
|
||||
|
||||
<ul>
|
||||
<li><tt>GCC versions 4.5.0 to 4.5.3, 4.6.0 to 4.6.2, or 4.7.0 (for the C++ header search path)</tt></li>
|
||||
<li><tt>some_directory/bin/gcc.exe</tt></li>
|
||||
<li><tt>some_directory/bin/clang.exe</tt></li>
|
||||
<li><tt>some_directory/bin/clang++.exe</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version/x86_64-w64-mingw32</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version/i686-w64-mingw32</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version/backward</tt></li>
|
||||
<li><tt>some_directory/bin/../x86_64-w64-mingw32/include</tt></li>
|
||||
<li><tt>some_directory/bin/../i686-w64-mingw32/include</tt></li>
|
||||
<li><tt>some_directory/bin/../include</tt></li>
|
||||
</ul>
|
||||
|
||||
<p>This directory layout is standard for any toolchain you will find on the official <a href="mingw-w64.sourceforge.net">MinGW-w64 website</a>.
|
||||
|
||||
<p>Clang expects the GCC executable "gcc.exe" compiled for i686-w64-mingw32 (or x86_64-w64-mingw32) to be present on PATH.</p>
|
||||
|
||||
<p><a href="http://llvm.org/bugs/show_bug.cgi?id=9072">Some tests might fail</a>
|
||||
on x86_64-w64-mingw32.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1230
clang/docs/doxygen.cfg
Normal file
1230
clang/docs/doxygen.cfg
Normal file
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@ PROJECT_NUMBER = @PACKAGE_VERSION@
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = @abs_builddir@/doxygen
|
||||
OUTPUT_DIRECTORY = @abs_top_builddir@/docs/doxygen
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
|
||||
# 4096 sub-directories (in 2 levels) under the output directory of each output
|
||||
@@ -39,7 +39,7 @@ OUTPUT_DIRECTORY = @abs_builddir@/doxygen
|
||||
# source files, where putting all generated files in the same directory would
|
||||
# otherwise cause performance problems for the file system.
|
||||
|
||||
CREATE_SUBDIRS = YES
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
@@ -450,9 +450,9 @@ WARN_LOGFILE =
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = @abs_srcdir@/../include \
|
||||
@abs_srcdir@/../lib \
|
||||
@abs_srcdir@/doxygen.intro
|
||||
INPUT = @abs_top_srcdir@/include \
|
||||
@abs_top_srcdir@/lib \
|
||||
@abs_top_srcdir@/docs/doxygen.intro
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
@@ -493,7 +493,7 @@ EXCLUDE_PATTERNS =
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH = @abs_srcdir@/../examples
|
||||
EXAMPLE_PATH = @abs_top_srcdir@/examples
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
@@ -513,7 +513,7 @@ EXAMPLE_RECURSIVE = YES
|
||||
# directories that contain image that are included in the documentation (see
|
||||
# the \image command).
|
||||
|
||||
IMAGE_PATH = @abs_srcdir@/img
|
||||
IMAGE_PATH = @abs_top_srcdir@/docs/img
|
||||
|
||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||
@@ -636,13 +636,13 @@ HTML_FILE_EXTENSION = .html
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard header.
|
||||
|
||||
HTML_HEADER = @abs_srcdir@/doxygen.header
|
||||
HTML_HEADER = @abs_top_srcdir@/docs/doxygen.header
|
||||
|
||||
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard footer.
|
||||
|
||||
HTML_FOOTER = @abs_srcdir@/doxygen.footer
|
||||
HTML_FOOTER = @abs_top_srcdir@/docs/doxygen.footer
|
||||
|
||||
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
|
||||
# style sheet that is used by each HTML page. It can be used to
|
||||
@@ -651,7 +651,7 @@ HTML_FOOTER = @abs_srcdir@/doxygen.footer
|
||||
# the style sheet file to the HTML output directory, so don't put your own
|
||||
# stylesheet in the HTML output directory as well, or it will be erased!
|
||||
|
||||
HTML_STYLESHEET = @abs_srcdir@/doxygen.css
|
||||
HTML_STYLESHEET = @abs_top_srcdir@/docs/doxygen.css
|
||||
|
||||
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
||||
# files or namespaces will be aligned in HTML using tables. If set to
|
||||
|
||||
@@ -370,39 +370,9 @@ H2 {
|
||||
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;
|
||||
}
|
||||
|
||||
4
clang/docs/index.html
Normal file
4
clang/docs/index.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<title>'clang' C frontend documentation</title>
|
||||
|
||||
None yet, sorry :(
|
||||
|
||||
267
clang/docs/libIndex.html
Normal file
267
clang/docs/libIndex.html
Normal file
@@ -0,0 +1,267 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>The Index Library</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>The Index Library</h1>
|
||||
|
||||
<p><b>Table of Contents</b></p>
|
||||
<ul>
|
||||
<li><a href="#philosophy">Design Philosophy</a></li>
|
||||
<li><a href="#classes">Classes</a>
|
||||
<ul>
|
||||
<li><a href="#entity">Entity</a></li>
|
||||
<li><a href="#astlocation">ASTLocation</a></li>
|
||||
<li><a href="#declreferencemap">DeclReferenceMap</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#functions">Functions</a>
|
||||
<ul>
|
||||
<li><a href="#resolveloc">ResolveLocationInAST</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#astfiles">AST Files</a></li>
|
||||
<li><a href="#indextest">index-test tool</a>
|
||||
<ul>
|
||||
<li><a href="#indextestusage">Usage</a></li>
|
||||
<li><a href="#indextestexamples">Examples</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="philosophy">Design Philosophy</h2>
|
||||
|
||||
<p> The Index library is meant to provide the basic infrastructure for
|
||||
cross-translation-unit analysis and is primarily focused on indexing
|
||||
related functionality. It provides an API for clients that need to
|
||||
accurately map the AST nodes of the ASTContext to the locations in the source files.
|
||||
It also allows them to analyze information across multiple translation units.</p>
|
||||
|
||||
<p>As a "general rule", ASTContexts are considered the primary source of
|
||||
information that a client wants about a translation unit. There will be no such class as an
|
||||
"indexing database" that stores, for example, source locations of identifiers separately from ASTContext.
|
||||
All the information that a client needs from a translation unit will be extracted from the ASTContext.</p>
|
||||
|
||||
<h2 id="classes">Classes</h2>
|
||||
|
||||
<h3 id="entity">Entity</h3>
|
||||
|
||||
<p>To be able to reason about semantically the same Decls that are contained in multiple ASTContexts, the 'Entity' class was introduced.
|
||||
An Entity is an ASTContext-independent "token" that can be created from a Decl (and a typename in the future) with
|
||||
the purpose to "resolve" it into a Decl belonging to another ASTContext. Some examples to make the concept of Entities more clear:</p>
|
||||
|
||||
<p>
|
||||
t1.c:
|
||||
<pre class="code_example">
|
||||
void foo(void);
|
||||
void bar(void);
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
t2.c:
|
||||
<pre class="code_example">
|
||||
void foo(void) {
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Translation unit <code>t1.c</code> contains 2 Entities <code>foo</code> and <code>bar</code>, while <code>t2.c</code> contains 1 Entity <code>foo</code>.
|
||||
Entities are uniqued in such a way that the Entity* pointer for <code>t1.c/foo</code> is the same as the Entity* pointer for <code>t2.c/foo</code>.
|
||||
An Entity doesn't convey any information about the declaration, it is more like an opaque pointer used only to get the
|
||||
associated Decl out of an ASTContext so that the actual information for the declaration can be accessed.
|
||||
Another important aspect of Entities is that they can only be created/associated for declarations that are visible outside the
|
||||
translation unit. This means that for:
|
||||
</p>
|
||||
<p>
|
||||
t3.c:
|
||||
<pre class="code_example">
|
||||
static void foo(void);
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
there can be no Entity (if you ask for the Entity* of the static function <code>foo</code> you'll get a null pointer).
|
||||
This is for 2 reasons:
|
||||
<ul>
|
||||
<li>To preserve the invariant that the same Entity* pointers refer to the same semantic Decls.
|
||||
In the above example <code>t1.c/foo</code> and <code>t2.c/foo</code> are the same, while <code>t3.c/foo</code> is different.</li>
|
||||
<li>The purpose of Entity is to get the same semantic Decl from multiple ASTContexts. For a Decl that is not visible
|
||||
outside of its own translation unit, you don't need an Entity since it won't appear in another ASTContext.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h3 id="astlocation">ASTLocation</h3>
|
||||
|
||||
Encapsulates a "point" in the AST tree of the ASTContext.
|
||||
It represents either a Decl*, or a Stmt* along with its immediate Decl* parent.
|
||||
An example for its usage is that libIndex will provide the references of <code>foo</code> in the form of ASTLocations,
|
||||
"pointing" at the expressions that reference <code>foo</code>.
|
||||
|
||||
<h3 id="declreferencemap">DeclReferenceMap</h3>
|
||||
|
||||
Accepts an ASTContext and creates a mapping from NamedDecls to the ASTLocations that reference them (in the same ASTContext).
|
||||
|
||||
<h2 id="functions">Functions</h2>
|
||||
|
||||
<h3 id="resolveloc">ResolveLocationInAST</h3>
|
||||
|
||||
A function that accepts an ASTContext and a SourceLocation which it resolves into an ASTLocation.
|
||||
|
||||
<h2 id="astfiles">AST Files</h2>
|
||||
|
||||
The precompiled headers implementation of clang (<a href="http://clang.llvm.org/docs/PCHInternals.html">PCH</a>) is ideal for storing an ASTContext in a compact form that
|
||||
will be loaded later for AST analysis. An "AST file" refers to a translation unit that was "compiled" into a precompiled header file.
|
||||
|
||||
<h2 id="indextest">index-test tool</h2>
|
||||
|
||||
<h3 id="indextestusage">Usage</h3>
|
||||
|
||||
A command-line tool that exercises the libIndex API, useful for testing its features.
|
||||
As input it accepts multiple AST files (representing multiple translation units) and a few options:
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-point-at [file:line:column]
|
||||
</pre>
|
||||
Resolves a [file:line:column] triplet into a ASTLocation from the first AST file. If no other option is specified, it prints the ASTLocation.
|
||||
It also prints a declaration's associated doxygen comment, if one is available.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-print-refs
|
||||
</pre>
|
||||
Prints the ASTLocations that reference the declaration that was resolved out of the [file:line:column] triplet
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-print-defs
|
||||
</pre>
|
||||
Prints the ASTLocations that define the resolved declaration
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<pre class="code_example">
|
||||
-print-decls
|
||||
</pre>
|
||||
Prints the ASTLocations that declare the resolved declaration
|
||||
</p>
|
||||
|
||||
<h3 id="indextestexamples">Examples</h3>
|
||||
|
||||
<p>
|
||||
Here's an example of using index-test:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We have 3 files,
|
||||
</p>
|
||||
|
||||
<p>
|
||||
foo.h:
|
||||
<pre class="code_example">
|
||||
extern int global_var;
|
||||
|
||||
void foo_func(int param1);
|
||||
void bar_func(void);
|
||||
</pre>
|
||||
|
||||
t1.c:
|
||||
<pre class="code_example">
|
||||
#include "foo.h"
|
||||
|
||||
void foo_func(int param1) {
|
||||
int local_var = global_var;
|
||||
for (int for_var = 100; for_var < 500; ++for_var) {
|
||||
local_var = param1 + for_var;
|
||||
}
|
||||
bar_func();
|
||||
}
|
||||
</pre>
|
||||
|
||||
t2.c:
|
||||
<pre class="code_example">
|
||||
#include "foo.h"
|
||||
|
||||
int global_var = 10;
|
||||
|
||||
void bar_func(void) {
|
||||
global_var += 100;
|
||||
foo_func(global_var);
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You first get AST files out of <code>t1.c</code> and <code>t2.c</code>:
|
||||
|
||||
<pre class="code_example">
|
||||
$ clang -emit-ast t1.c -o t1.ast
|
||||
$ clang -emit-ast t2.c -o t2.ast
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find the ASTLocation under this position of <code>t1.c</code>:
|
||||
<pre class="code_example">
|
||||
[...]
|
||||
void foo_func(int param1) {
|
||||
int local_var = global_var;
|
||||
^
|
||||
[...]
|
||||
</pre>
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast -point-at t1.c:4:23
|
||||
> [Decl: Var local_var | Stmt: DeclRefExpr global_var] <t1.c:4:19, t1.c:4:19>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find the declaration:
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast -point-at t1.c:4:23 -print-decls
|
||||
> [Decl: Var global_var] <foo.h:1:12, foo.h:1:12>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find the references:
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-refs
|
||||
> [Decl: Var local_var | Stmt: DeclRefExpr global_var] <t1.c:4:19, t1.c:4:19>
|
||||
> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] <t2.c:6:3, t2.c:6:3>
|
||||
> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] <t2.c:7:12, t2.c:7:12>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Find definitions:
|
||||
|
||||
<pre class="code_example">
|
||||
$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-defs
|
||||
> [Decl: Var global_var] <t2.c:3:5, t2.c:3:18>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -37,11 +37,10 @@ clean:
|
||||
else
|
||||
|
||||
# Otherwise, if not in BUILD_FOR_WEBSITE mode, use the project info.
|
||||
CLANG_LEVEL := ../..
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
LEVEL := ../../../..
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
CLANG_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \
|
||||
$(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc))
|
||||
CLANG_VERSION := $(shell cat $(PROJ_SRC_DIR)/../../VER)
|
||||
|
||||
SRC_DOC_DIR=$(PROJ_SRC_DIR)/
|
||||
DST_HTML_DIR=$(PROJ_OBJ_DIR)/
|
||||
|
||||
@@ -2,24 +2,23 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
clang - the Clang C, C++, and Objective-C compiler
|
||||
clang - the Clang 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<-O0>|B<-O1>|B<-O2>|B<-Os>|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,
|
||||
B<clang> is a 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
|
||||
@@ -38,8 +37,7 @@ the other tools.
|
||||
|
||||
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.
|
||||
this stage is typically called a ".i" (for C) or ".mi" (for Objective-C) file.
|
||||
|
||||
=item B<Parsing and Semantic Analysis>
|
||||
|
||||
@@ -52,13 +50,10 @@ 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.
|
||||
IR") and ultimately to machine code (depending on the optimization level). This
|
||||
phase is responsible for optimizing the generated code and handling
|
||||
target-specfic code generation. The output of this stage is typically called a
|
||||
".s" file or "assembly" file.
|
||||
|
||||
=item B<Assembler>
|
||||
|
||||
@@ -80,7 +75,7 @@ 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
|
||||
though code analysis. This tool uses many parts of Clang and is built into the
|
||||
same driver.
|
||||
|
||||
|
||||
@@ -132,11 +127,6 @@ Treat subsequent input files as having type 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>.
|
||||
@@ -175,14 +165,6 @@ Enable support for Pascal-style strings with "\pfoo".
|
||||
|
||||
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
|
||||
@@ -196,6 +178,7 @@ Allow loose type checking rules for implicit vector conversions.
|
||||
|
||||
Enable the "Blocks" language feature.
|
||||
|
||||
|
||||
=item B<-fobjc-gc-only>
|
||||
|
||||
Indicate that Objective-C code should be compiled in GC-only mode, which only
|
||||
@@ -206,22 +189,6 @@ works when Objective-C Garbage Collection is enabled.
|
||||
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
|
||||
|
||||
|
||||
@@ -263,13 +230,12 @@ may not exist on earlier ones.
|
||||
|
||||
=over
|
||||
|
||||
=item B<-O0> B<-O1> B<-O2> B<-Os> B<-Oz> B<-O3> B<-O4>
|
||||
=item B<-O0> B<-O1> B<-O2> B<-Os> 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>,
|
||||
B<-O2> with extra optimizations to reduce code size. 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
|
||||
@@ -357,6 +323,10 @@ Pass I<arg> to the static analyzer.
|
||||
|
||||
Pass I<arg> to the assembler.
|
||||
|
||||
=item B<-Xclang> I<arg>
|
||||
|
||||
Pass I<arg> to the clang compiler.
|
||||
|
||||
=item B<-Xlinker> I<arg>
|
||||
|
||||
Pass I<arg> to the linker.
|
||||
@@ -365,7 +335,7 @@ Pass I<arg> to the linker.
|
||||
|
||||
Pass I<arg> to the preprocessor.
|
||||
|
||||
=item B<-o> I<file>
|
||||
=item B<-o> I<file>
|
||||
|
||||
Write output to I<file>.
|
||||
|
||||
@@ -389,12 +359,6 @@ Print the paths used for finding libraries and programs.
|
||||
|
||||
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.
|
||||
@@ -418,7 +382,6 @@ Show commands to run and use verbose output.
|
||||
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>
|
||||
@@ -459,13 +422,7 @@ 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 builting include directories.
|
||||
Do not search the standard system directories for include files.
|
||||
|
||||
=item B<-nobuiltininc>
|
||||
|
||||
@@ -545,6 +502,7 @@ targets.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Clang currently does not have C++ support, and this manual page is incomplete.
|
||||
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.
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
add_subdirectory(clang-interpreter)
|
||||
add_subdirectory(PrintFunctionNames)
|
||||
add_subdirectory(wpa)
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ..
|
||||
LEVEL = ../../..
|
||||
|
||||
PARALLEL_DIRS := clang-interpreter PrintFunctionNames
|
||||
PARALLEL_DIRS := clang-interpreter PrintFunctionNames wpa
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
set(MODULE TRUE)
|
||||
set(SHARED_LIBRARY TRUE)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
set(LLVM_USED_LIBS
|
||||
clangIndex
|
||||
clangFrontend
|
||||
clangDriver
|
||||
clangSema
|
||||
clangAnalysis
|
||||
clangAST
|
||||
)
|
||||
clangParse
|
||||
clangLex
|
||||
clangBasic)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
set( LLVM_LINK_COMPONENTS
|
||||
bitreader
|
||||
mc
|
||||
core
|
||||
)
|
||||
|
||||
add_clang_library(PrintFunctionNames PrintFunctionNames.cpp)
|
||||
|
||||
set_target_properties(PrintFunctionNames
|
||||
PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
PREFIX "")
|
||||
LINKER_LANGUAGE CXX)
|
||||
|
||||
@@ -7,22 +7,21 @@
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
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
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
|
||||
|
||||
LINK_LIBS_IN_SHARED = 0
|
||||
# Include this here so we can get the configuration of the targets that have
|
||||
# been configured for construction. We have to do this early so we can set up
|
||||
# LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_LIBS_IN_SHARED = 1
|
||||
SHARED_LIBRARY = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
LINK_COMPONENTS := bitreader mc core
|
||||
USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangSema.a \
|
||||
clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
LDFLAGS=-Wl,-undefined,dynamic_lookup
|
||||
endif
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#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;
|
||||
|
||||
@@ -30,40 +29,16 @@ public:
|
||||
llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class PrintFunctionNamesAction : public PluginASTAction {
|
||||
class PrintFunctionNamesAction : public ASTFrontendAction {
|
||||
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>
|
||||
FrontendPluginRegistry::Add<PrintFunctionNamesAction>
|
||||
X("print-fns", "print function names");
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
_ZN4llvm8Registry*
|
||||
@@ -1,12 +1,10 @@
|
||||
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.
|
||||
You will probably need to build clang so that it exports all symbols (disable
|
||||
TOOL_NO_EXPORT in the tools/clang Makefile).
|
||||
|
||||
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
|
||||
|
||||
Mac:
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c
|
||||
$ clang -cc1 -load path/to/PrintFunctionNames.so -plugin print-fns some-input-file.c
|
||||
--
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
set(MODULE TRUE)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangStaticAnalyzerCore
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(SampleAnalyzerPlugin SampleAnalyzerPlugin)
|
||||
|
||||
set_target_properties(SampleAnalyzerPlugin
|
||||
PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
PREFIX "")
|
||||
@@ -1,52 +0,0 @@
|
||||
#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 llvm::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 ProgramState *state = C.getState();
|
||||
const Expr *Callee = CE->getCallee();
|
||||
const FunctionDecl *FD = state->getSVal(Callee).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;
|
||||
@@ -1,20 +0,0 @@
|
||||
##===- 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
|
||||
SHARED_LIBRARY = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
LDFLAGS=-Wl,-undefined,dynamic_lookup
|
||||
endif
|
||||
@@ -1,13 +1,11 @@
|
||||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
set(LLVM_USED_LIBS
|
||||
clangFrontend
|
||||
clangSerialization
|
||||
clangDriver
|
||||
clangCodeGen
|
||||
clangSema
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangIndex
|
||||
clangChecker
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
clangAST
|
||||
@@ -20,10 +18,8 @@ set(LLVM_LINK_COMPONENTS
|
||||
jit
|
||||
interpreter
|
||||
nativecodegen
|
||||
asmparser
|
||||
bitreader
|
||||
bitwriter
|
||||
codegen
|
||||
ipo
|
||||
selectiondag
|
||||
)
|
||||
|
||||
@@ -7,19 +7,24 @@
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
LEVEL = ../../../..
|
||||
|
||||
TOOLNAME = clang-interpreter
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
|
||||
NO_INSTALL = 1
|
||||
|
||||
# No plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
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 clangAST.a clangLex.a clangBasic.a
|
||||
# Include this here so we can get the configuration of the targets that have
|
||||
# been configured for construction. We have to do this early so we can set up
|
||||
# LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
selectiondag
|
||||
USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \
|
||||
clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \
|
||||
clangParse.a clangLex.a clangBasic.a
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
|
||||
@@ -7,36 +7,31 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/CodeGen/CodeGenAction.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Frontend/CodeGenAction.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/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Config/config.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"
|
||||
#include "llvm/System/Host.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/Target/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.
|
||||
@@ -44,7 +39,7 @@ llvm::sys::Path GetExecutablePath(const char *Argv0) {
|
||||
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
|
||||
}
|
||||
|
||||
static int Execute(llvm::Module *Mod, char * const *envp) {
|
||||
int Execute(llvm::Module *Mod, char * const *envp) {
|
||||
llvm::InitializeNativeTarget();
|
||||
|
||||
std::string Error;
|
||||
@@ -71,12 +66,11 @@ static int Execute(llvm::Module *Mod, char * const *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());
|
||||
TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions());
|
||||
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
DiagnosticsEngine Diags(DiagID, DiagClient);
|
||||
Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
|
||||
Diagnostic Diags(&DiagClient);
|
||||
Driver TheDriver(Path.getBasename(), Path.getDirname(),
|
||||
llvm::sys::getHostTriple(),
|
||||
"a.out", /*IsProduction=*/false, Diags);
|
||||
TheDriver.setTitle("clang interpreter");
|
||||
|
||||
@@ -85,7 +79,8 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
// (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");
|
||||
llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
|
||||
llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args.size(),
|
||||
Args.data()));
|
||||
if (!C)
|
||||
return 0;
|
||||
|
||||
@@ -94,7 +89,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
// 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())) {
|
||||
if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
|
||||
llvm::SmallString<256> Msg;
|
||||
llvm::raw_svector_ostream OS(Msg);
|
||||
C->PrintJob(OS, C->getJobs(), "; ", true);
|
||||
@@ -111,10 +106,8 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
// Initialize a compiler invocation object from the clang (-cc1) arguments.
|
||||
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
||||
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
|
||||
CompilerInvocation::CreateFromArgs(*CI,
|
||||
const_cast<const char **>(CCArgs.data()),
|
||||
const_cast<const char **>(CCArgs.data()) +
|
||||
CCArgs.size(),
|
||||
CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
|
||||
(const char**) CCArgs.data()+CCArgs.size(),
|
||||
Diags);
|
||||
|
||||
// Show the invocation, with -v.
|
||||
@@ -128,10 +121,11 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
|
||||
// Create a compiler instance to handle the actual work.
|
||||
CompilerInstance Clang;
|
||||
Clang.setLLVMContext(new llvm::LLVMContext);
|
||||
Clang.setInvocation(CI.take());
|
||||
|
||||
// Create the compilers actual diagnostics engine.
|
||||
Clang.createDiagnostics(int(CCArgs.size()),const_cast<char**>(CCArgs.data()));
|
||||
Clang.createDiagnostics(int(CCArgs.size()), (char**) CCArgs.data());
|
||||
if (!Clang.hasDiagnostics())
|
||||
return 1;
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
set(LLVM_USED_LIBS
|
||||
clangIndex
|
||||
clangFrontend
|
||||
clangDriver
|
||||
clangSema
|
||||
clangAnalysis
|
||||
clangSerialization
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangRewrite
|
||||
clangAST
|
||||
clangParse
|
||||
clangLex
|
||||
|
||||
@@ -7,20 +7,22 @@
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
LEVEL = ../../../..
|
||||
|
||||
TOOLNAME = clang-wpa
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
|
||||
NO_INSTALL = 1
|
||||
|
||||
# No plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
LINK_COMPONENTS := asmparser bitreader mc core
|
||||
USEDLIBS = clangStaticAnalyzerFrontend.a \
|
||||
clangStaticAnalyzerCheckers.a \
|
||||
clangStaticAnalyzerCore.a \
|
||||
clangIndex.a clangFrontend.a clangDriver.a \
|
||||
clangParse.a clangSema.a clangAnalysis.a clangSerialization.a \
|
||||
clangAST.a clangLex.a clangBasic.a
|
||||
# Include this here so we can get the configuration of the targets that have
|
||||
# been configured for construction. We have to do this early so we can set up
|
||||
# LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
LINK_COMPONENTS := bitreader mc core
|
||||
USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangSema.a \
|
||||
clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
|
||||
@@ -14,22 +14,9 @@
|
||||
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Index/CallGraph.h"
|
||||
#include "clang/Index/Indexer.h"
|
||||
#include "clang/Index/TranslationUnit.h"
|
||||
#include "clang/Index/DeclReferenceMap.h"
|
||||
#include "clang/Index/SelectorMap.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
@@ -38,144 +25,32 @@ using namespace idx;
|
||||
static llvm::cl::list<std::string>
|
||||
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
ViewCallGraph("view-call-graph", llvm::cl::desc("Display the call graph."));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
AnalyzeFunction("analyze-function",
|
||||
llvm::cl::desc("Specify the entry function."));
|
||||
|
||||
namespace {
|
||||
// A thin wrapper over ASTUnit implementing the TranslationUnit interface.
|
||||
class ASTUnitTU : public TranslationUnit {
|
||||
ASTUnit *AST;
|
||||
DeclReferenceMap DeclRefMap;
|
||||
SelectorMap SelMap;
|
||||
|
||||
public:
|
||||
ASTUnitTU(ASTUnit *ast)
|
||||
: AST(ast), DeclRefMap(AST->getASTContext()), SelMap(AST->getASTContext()) {
|
||||
}
|
||||
|
||||
virtual ASTContext &getASTContext() {
|
||||
return AST->getASTContext();
|
||||
}
|
||||
|
||||
virtual Preprocessor &getPreprocessor() {
|
||||
return AST->getPreprocessor();
|
||||
}
|
||||
|
||||
virtual Diagnostic &getDiagnostic() {
|
||||
return AST->getDiagnostics();
|
||||
}
|
||||
|
||||
virtual DeclReferenceMap &getDeclReferenceMap() {
|
||||
return DeclRefMap;
|
||||
}
|
||||
|
||||
virtual SelectorMap &getSelectorMap() {
|
||||
return SelMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
|
||||
FileManager FileMgr;
|
||||
std::vector<ASTUnit*> ASTUnits;
|
||||
|
||||
Program Prog;
|
||||
Indexer Idxer(Prog);
|
||||
|
||||
if (InputFilenames.empty())
|
||||
return 0;
|
||||
|
||||
DiagnosticOptions DiagOpts;
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic> Diags
|
||||
= CompilerInstance::createDiagnostics(DiagOpts, argc, argv);
|
||||
llvm::OwningPtr<Diagnostic> Diags(
|
||||
CompilerInstance::createDiagnostics(DiagOpts, argc, argv));
|
||||
|
||||
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
||||
const std::string &InFile = InputFilenames[i];
|
||||
llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromASTFile(InFile, Diags,
|
||||
FileSystemOptions(),
|
||||
false, 0, 0, true));
|
||||
llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, *Diags));
|
||||
if (!AST)
|
||||
return 1;
|
||||
|
||||
ASTUnits.push_back(AST.take());
|
||||
}
|
||||
|
||||
if (ViewCallGraph) {
|
||||
llvm::OwningPtr<CallGraph> CG;
|
||||
CG.reset(new CallGraph(Prog));
|
||||
llvm::OwningPtr<CallGraph> CG;
|
||||
CG.reset(new CallGraph());
|
||||
|
||||
for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
|
||||
CG->addTU(ASTUnits[i]->getASTContext());
|
||||
for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
|
||||
CG->addTU(ASTUnits[i]->getASTContext());
|
||||
|
||||
CG->ViewCallGraph();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (AnalyzeFunction.empty())
|
||||
return 0;
|
||||
|
||||
// Feed all ASTUnits to the Indexer.
|
||||
for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i) {
|
||||
ASTUnitTU *TU = new ASTUnitTU(ASTUnits[i]);
|
||||
Idxer.IndexAST(TU);
|
||||
}
|
||||
|
||||
Entity Ent = Entity::get(AnalyzeFunction, Prog);
|
||||
FunctionDecl *FD;
|
||||
TranslationUnit *TU;
|
||||
llvm::tie(FD, TU) = Idxer.getDefinitionFor(Ent);
|
||||
|
||||
if (!FD)
|
||||
return 0;
|
||||
|
||||
// Create an analysis engine.
|
||||
Preprocessor &PP = TU->getPreprocessor();
|
||||
|
||||
AnalyzerOptions Opts;
|
||||
|
||||
// Hard code options and checkers for now.
|
||||
|
||||
Opts.MaxNodes = 300000;
|
||||
Opts.MaxLoop = 3;
|
||||
Opts.InlineCall = true;
|
||||
Opts.CFGAddImplicitDtors = true;
|
||||
Opts.EagerlyTrimEGraph = true;
|
||||
|
||||
Opts.CheckersControlList.push_back(std::make_pair("core", true));
|
||||
if (PP.getTargetInfo().getTriple().getOS() != llvm::Triple::Win32)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("unix", true));
|
||||
if (PP.getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("macosx", true));
|
||||
|
||||
// Checks to perform for Objective-C/Objective-C++.
|
||||
if (PP.getLangOptions().ObjC1)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("cocoa", true));
|
||||
|
||||
llvm::OwningPtr<ento::CheckerManager> checkerMgr;
|
||||
checkerMgr.reset(ento::registerCheckers(Opts, PP.getLangOptions(),
|
||||
PP.getDiagnostics()));
|
||||
|
||||
using namespace clang::ento;
|
||||
AnalysisManager AMgr(TU->getASTContext(), PP.getDiagnostics(),
|
||||
PP.getLangOptions(), /* PathDiagnostic */ 0,
|
||||
CreateRegionStoreManager,
|
||||
CreateRangeConstraintManager, checkerMgr.get(), &Idxer,
|
||||
Opts.MaxNodes, Opts.MaxLoop,
|
||||
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
|
||||
Opts.PurgeDead, Opts.EagerlyAssume,
|
||||
Opts.TrimGraph, Opts.InlineCall,
|
||||
Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
|
||||
Opts.CFGAddInitializers,
|
||||
Opts.EagerlyTrimEGraph);
|
||||
|
||||
TransferFuncs* TF = MakeCFRefCountTF(AMgr.getASTContext(), /*GC*/false,
|
||||
AMgr.getLangOptions());
|
||||
ExprEngine Eng(AMgr, TF);
|
||||
|
||||
Eng.ExecuteWorkList(AMgr.getStackFrame(FD, TU), AMgr.getMaxNodes());
|
||||
|
||||
return 0;
|
||||
CG->ViewCallGraph();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CLANG_LEVEL := ..
|
||||
DIRS := clang clang-c
|
||||
LEVEL = ../../..
|
||||
DIRS := clang
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
||||
CLANG_LEVEL := ../..
|
||||
DIRS :=
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
install-local::
|
||||
$(Echo) Installing Clang C API include files
|
||||
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
|
||||
$(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang-c" ; then \
|
||||
cd $(PROJ_SRC_ROOT)/tools/clang/include && \
|
||||
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=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
|
||||
if test \! -d "$$instdir" ; then \
|
||||
$(EchoCmd) Making install directory $$instdir ; \
|
||||
$(MKDIR) $$instdir ;\
|
||||
fi ; \
|
||||
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$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 \
|
||||
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
endif
|
||||
@@ -1,112 +0,0 @@
|
||||
//===-- 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,
|
||||
StringRef Filename, InputKind Kind,
|
||||
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,
|
||||
StringRef Filename, InputKind Kind,
|
||||
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,
|
||||
StringRef Filename, InputKind Kind,
|
||||
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);
|
||||
|
||||
typedef void (*TransformFn)(MigrationPass &pass);
|
||||
|
||||
std::vector<TransformFn> getAllTransformations();
|
||||
|
||||
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
|
||||
@@ -1,51 +0,0 @@
|
||||
//===--- 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 "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 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);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,77 +0,0 @@
|
||||
//===-- 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 CompilerInvocation;
|
||||
|
||||
namespace arcmt {
|
||||
|
||||
class FileRemapper {
|
||||
// FIXME: Reuse the same FileManager for multiple ASTContexts.
|
||||
llvm::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 flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag);
|
||||
|
||||
bool overwriteOriginal(DiagnosticsEngine &Diag,
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
|
||||
void remap(StringRef filePath, StringRef newPath);
|
||||
|
||||
void applyMappings(CompilerInvocation &CI) const;
|
||||
|
||||
void transferMappingsAndClear(CompilerInvocation &CI);
|
||||
|
||||
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
|
||||
@@ -14,13 +14,11 @@
|
||||
#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"
|
||||
|
||||
namespace clang {
|
||||
class CharUnits;
|
||||
class DiagnosticBuilder;
|
||||
class Expr;
|
||||
|
||||
/// APValue - This class implements a discriminated union of [uninitialized]
|
||||
@@ -87,10 +85,10 @@ public:
|
||||
APValue(const APValue &RHS) : Kind(Uninitialized) {
|
||||
*this = RHS;
|
||||
}
|
||||
APValue(const Expr* B, const CharUnits &O) : Kind(Uninitialized) {
|
||||
APValue(Expr* B, const CharUnits &O) : Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O);
|
||||
}
|
||||
APValue(const Expr* B);
|
||||
APValue(Expr* B);
|
||||
|
||||
~APValue() {
|
||||
MakeUninit();
|
||||
@@ -105,7 +103,7 @@ public:
|
||||
bool isLValue() const { return Kind == LValue; }
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void print(llvm::raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
APSInt &getInt() {
|
||||
@@ -124,17 +122,13 @@ public:
|
||||
return const_cast<APValue*>(this)->getFloat();
|
||||
}
|
||||
|
||||
APValue &getVectorElt(unsigned i) {
|
||||
APValue &getVectorElt(unsigned i) const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(char*)Data)->Elts[i];
|
||||
}
|
||||
const APValue &getVectorElt(unsigned i) const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((const Vec*)(const char*)Data)->Elts[i];
|
||||
}
|
||||
unsigned getVectorLength() const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((const Vec*)(const void *)Data)->NumElts;
|
||||
return ((Vec*)(void *)Data)->NumElts;
|
||||
}
|
||||
|
||||
APSInt &getComplexIntReal() {
|
||||
@@ -169,7 +163,7 @@ public:
|
||||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
}
|
||||
|
||||
const Expr* getLValueBase() const;
|
||||
Expr* getLValueBase() const;
|
||||
CharUnits getLValueOffset() const;
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
@@ -201,7 +195,7 @@ public:
|
||||
((ComplexAPFloat*)(char*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(char*)Data)->Imag = I;
|
||||
}
|
||||
void setLValue(const Expr *B, const CharUnits &O);
|
||||
void setLValue(Expr *B, const CharUnits &O);
|
||||
|
||||
const APValue &operator=(const APValue &RHS);
|
||||
|
||||
@@ -235,15 +229,11 @@ private:
|
||||
void MakeLValue();
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) {
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
|
||||
V.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
// Writes a concise representation of V to DB, in a single << operation.
|
||||
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const APValue &V);
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,13 +16,10 @@
|
||||
|
||||
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 HandleTagDeclDefinition;
|
||||
class SemaConsumer; // layering violation required for safe SemaConsumer
|
||||
class VarDecl;
|
||||
|
||||
/// ASTConsumer - This is an abstract interface that should be implemented by
|
||||
@@ -50,11 +47,6 @@ public:
|
||||
/// elements). Use Decl::getNextDeclarator() to walk the chain.
|
||||
virtual void 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) {}
|
||||
@@ -76,26 +68,6 @@ public:
|
||||
/// modified by the introduction of an implicit zero initializer.
|
||||
virtual void CompleteTentativeDefinition(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() {}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,7 @@
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||
#undef DIAG
|
||||
@@ -24,27 +23,25 @@ namespace clang {
|
||||
};
|
||||
} // end namespace diag
|
||||
|
||||
/// \brief DiagnosticsEngine argument formatting function for diagnostics that
|
||||
/// \brief Diagnostic 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,
|
||||
SmallVectorImpl<intptr_t> &QualTypeVals);
|
||||
/// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext
|
||||
/// pointer.
|
||||
void FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
|
||||
intptr_t Val,
|
||||
const char *Modifier,
|
||||
unsigned ModLen,
|
||||
const char *Argument,
|
||||
unsigned ArgLen,
|
||||
const Diagnostic::ArgumentValue *PrevArgs,
|
||||
unsigned NumPrevArgs,
|
||||
llvm::SmallVectorImpl<char> &Output,
|
||||
void *Cookie);
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#ifndef LLVM_CLANG_AST_ASTIMPORTER_H
|
||||
#define LLVM_CLANG_AST_ASTIMPORTER_H
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
@@ -25,7 +25,7 @@ namespace clang {
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class DiagnosticsEngine;
|
||||
class Diagnostic;
|
||||
class Expr;
|
||||
class FileManager;
|
||||
class IdentifierInfo;
|
||||
@@ -45,13 +45,13 @@ namespace clang {
|
||||
|
||||
/// \brief The file managers we're importing to and from.
|
||||
FileManager &ToFileManager, &FromFileManager;
|
||||
|
||||
/// \brief Whether to perform a minimal import.
|
||||
bool Minimal;
|
||||
|
||||
/// \brief The diagnostics object that we should use to emit diagnostics.
|
||||
Diagnostic &Diags;
|
||||
|
||||
/// \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;
|
||||
llvm::DenseMap<Type *, Type *> ImportedTypes;
|
||||
|
||||
/// \brief Mapping from the already-imported declarations in the "from"
|
||||
/// context to the corresponding declarations in the "to" context.
|
||||
@@ -63,40 +63,23 @@ namespace clang {
|
||||
|
||||
/// \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;
|
||||
llvm::DenseMap<unsigned, FileID> ImportedFileIDs;
|
||||
|
||||
/// \brief Imported, anonymous tag declarations that are missing their
|
||||
/// corresponding typedefs.
|
||||
SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
|
||||
llvm::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);
|
||||
ASTImporter(Diagnostic &Diags,
|
||||
ASTContext &ToContext, FileManager &ToFileManager,
|
||||
ASTContext &FromContext, FileManager &FromFileManager);
|
||||
|
||||
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.
|
||||
///
|
||||
@@ -145,17 +128,6 @@ namespace clang {
|
||||
/// \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.
|
||||
@@ -182,7 +154,7 @@ namespace clang {
|
||||
/// into the "to" context.
|
||||
///
|
||||
/// \returns the equivalent identifier in the "to" context.
|
||||
IdentifierInfo *Import(const IdentifierInfo *FromId);
|
||||
IdentifierInfo *Import(IdentifierInfo *FromId);
|
||||
|
||||
/// \brief Import the given Objective-C selector from the "from"
|
||||
/// context into the "to" context.
|
||||
@@ -197,12 +169,6 @@ namespace clang {
|
||||
/// 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.
|
||||
///
|
||||
@@ -246,6 +212,9 @@ namespace clang {
|
||||
|
||||
/// \brief Retrieve the file manager that AST nodes are being imported from.
|
||||
FileManager &getFromFileManager() const { return FromFileManager; }
|
||||
|
||||
/// \brief Retrieve the diagnostic formatter.
|
||||
Diagnostic &getDiags() const { return Diags; }
|
||||
|
||||
/// \brief Report a diagnostic in the "to" context.
|
||||
DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID);
|
||||
@@ -259,13 +228,12 @@ namespace clang {
|
||||
/// \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);
|
||||
/// \returns \p To
|
||||
Decl *Imported(Decl *From, Decl *To);
|
||||
|
||||
/// \brief Determine whether the given types are structurally
|
||||
/// equivalent.
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To);
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
//===--- 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;
|
||||
|
||||
/// \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) {}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,397 +0,0 @@
|
||||
//===- 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
|
||||
@@ -14,91 +14,144 @@
|
||||
#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/Support/Casting.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
using llvm::dyn_cast;
|
||||
|
||||
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,
|
||||
void *operator new(size_t Bytes, clang::ASTContext &C,
|
||||
size_t Alignment = 16) throw ();
|
||||
// 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) throw ();
|
||||
|
||||
// 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)
|
||||
throw ();
|
||||
void operator delete[](void *Ptr, const clang::ASTContext &C, size_t)
|
||||
void operator delete(void *Ptr, clang::ASTContext &C, size_t)
|
||||
throw ();
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Attr - This represents one attribute.
|
||||
class Attr {
|
||||
private:
|
||||
SourceRange Range;
|
||||
unsigned AttrKind : 16;
|
||||
public:
|
||||
enum Kind {
|
||||
Alias,
|
||||
Aligned,
|
||||
AlwaysInline,
|
||||
AnalyzerNoReturn, // Clang-specific.
|
||||
Annotate,
|
||||
AsmLabel, // Represent GCC asm label extension.
|
||||
BaseCheck,
|
||||
Blocks,
|
||||
CDecl,
|
||||
Cleanup,
|
||||
Const,
|
||||
Constructor,
|
||||
Deprecated,
|
||||
Destructor,
|
||||
FastCall,
|
||||
Final,
|
||||
Format,
|
||||
FormatArg,
|
||||
GNUInline,
|
||||
Hiding,
|
||||
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro.
|
||||
IBActionKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro.
|
||||
Malloc,
|
||||
NoDebug,
|
||||
NoInline,
|
||||
NonNull,
|
||||
NoReturn,
|
||||
NoThrow,
|
||||
ObjCException,
|
||||
ObjCNSObject,
|
||||
Override,
|
||||
CFReturnsRetained, // Clang/Checker-specific.
|
||||
CFReturnsNotRetained, // Clang/Checker-specific.
|
||||
NSReturnsRetained, // Clang/Checker-specific.
|
||||
NSReturnsNotRetained, // Clang/Checker-specific.
|
||||
Overloadable, // Clang-specific
|
||||
Packed,
|
||||
PragmaPack,
|
||||
Pure,
|
||||
Regparm,
|
||||
ReqdWorkGroupSize, // OpenCL-specific
|
||||
Section,
|
||||
Sentinel,
|
||||
StdCall,
|
||||
TransparentUnion,
|
||||
Unavailable,
|
||||
Unused,
|
||||
Used,
|
||||
Visibility,
|
||||
WarnUnusedResult,
|
||||
Weak,
|
||||
WeakImport,
|
||||
WeakRef,
|
||||
|
||||
protected:
|
||||
FIRST_TARGET_ATTRIBUTE,
|
||||
DLLExport,
|
||||
DLLImport,
|
||||
MSP430Interrupt,
|
||||
X86ForceAlignArgPointer
|
||||
};
|
||||
|
||||
private:
|
||||
Attr *Next;
|
||||
Kind AttrKind;
|
||||
bool Inherited : 1;
|
||||
|
||||
virtual ~Attr();
|
||||
|
||||
protected:
|
||||
void* operator new(size_t bytes) throw() {
|
||||
llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
|
||||
assert(0 && "Attrs cannot be allocated with regular 'new'.");
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
assert(0 && "Attrs cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
protected:
|
||||
Attr(attr::Kind AK, SourceRange R)
|
||||
: Range(R), AttrKind(AK), Inherited(false) {}
|
||||
|
||||
Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {}
|
||||
virtual ~Attr() {
|
||||
assert(Next == 0 && "Destroy didn't work");
|
||||
}
|
||||
public:
|
||||
virtual void Destroy(ASTContext &C);
|
||||
|
||||
attr::Kind getKind() const {
|
||||
return static_cast<attr::Kind>(AttrKind);
|
||||
/// \brief Whether this attribute should be merged to new
|
||||
/// declarations.
|
||||
virtual bool isMerged() const { return true; }
|
||||
|
||||
Kind getKind() const { return AttrKind; }
|
||||
|
||||
Attr *getNext() { return Next; }
|
||||
const Attr *getNext() const { return Next; }
|
||||
void setNext(Attr *next) { Next = next; }
|
||||
|
||||
template<typename T> const T *getNext() const {
|
||||
for (const Attr *attr = getNext(); attr; attr = attr->getNext())
|
||||
if (const T *V = dyn_cast<T>(attr))
|
||||
return V;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SourceLocation getLocation() const { return Range.getBegin(); }
|
||||
SourceRange getRange() const { return Range; }
|
||||
void setRange(SourceRange R) { Range = R; }
|
||||
|
||||
bool isInherited() const { return Inherited; }
|
||||
void setInherited(bool value) { Inherited = value; }
|
||||
|
||||
void addAttr(Attr *attr) {
|
||||
assert((attr != 0) && "addAttr(): attr is null");
|
||||
|
||||
// FIXME: This doesn't preserve the order in any way.
|
||||
attr->Next = Next;
|
||||
Next = attr;
|
||||
}
|
||||
|
||||
// Clone this attribute.
|
||||
virtual Attr* clone(ASTContext &C) const = 0;
|
||||
@@ -106,142 +159,428 @@ public:
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *) { return true; }
|
||||
};
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
|
||||
class AttrWithString : public Attr {
|
||||
private:
|
||||
const char *Str;
|
||||
unsigned StrLen;
|
||||
protected:
|
||||
InheritableAttr(attr::Kind AK, SourceRange R)
|
||||
: Attr(AK, R) {}
|
||||
|
||||
AttrWithString(Attr::Kind AK, ASTContext &C, llvm::StringRef s);
|
||||
llvm::StringRef getString() const { return llvm::StringRef(Str, StrLen); }
|
||||
void ReplaceString(ASTContext &C, llvm::StringRef newS);
|
||||
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; }
|
||||
virtual void Destroy(ASTContext &C);
|
||||
};
|
||||
|
||||
class InheritableParamAttr : public InheritableAttr {
|
||||
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) {
|
||||
#define DEF_SIMPLE_ATTR(ATTR) \
|
||||
class ATTR##Attr : public Attr { \
|
||||
public: \
|
||||
ATTR##Attr() : Attr(ATTR) {} \
|
||||
virtual Attr *clone(ASTContext &C) const; \
|
||||
static bool classof(const Attr *A) { return A->getKind() == ATTR; } \
|
||||
static bool classof(const ATTR##Attr *A) { return true; } \
|
||||
}
|
||||
|
||||
/// 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;
|
||||
DEF_SIMPLE_ATTR(Packed);
|
||||
|
||||
void AdvanceToNext() const {
|
||||
while (!isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
void AdvanceToNext(AttrVec::const_iterator I) const {
|
||||
while (Current != I && !isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
class PragmaPackAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
|
||||
public:
|
||||
typedef SpecificAttr* value_type;
|
||||
typedef SpecificAttr* reference;
|
||||
typedef SpecificAttr* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
PragmaPackAttr(unsigned alignment) : Attr(PragmaPack), Alignment(alignment) {}
|
||||
|
||||
specific_attr_iterator() : Current() { }
|
||||
explicit specific_attr_iterator(AttrVec::const_iterator i) : Current(i) { }
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
reference operator*() const {
|
||||
AdvanceToNext();
|
||||
return cast<SpecificAttr>(*Current);
|
||||
}
|
||||
pointer operator->() const {
|
||||
AdvanceToNext();
|
||||
return cast<SpecificAttr>(*Current);
|
||||
}
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
specific_attr_iterator& operator++() {
|
||||
++Current;
|
||||
return *this;
|
||||
}
|
||||
specific_attr_iterator operator++(int) {
|
||||
specific_attr_iterator Tmp(*this);
|
||||
++(*this);
|
||||
return Tmp;
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == PragmaPack;
|
||||
}
|
||||
static bool classof(const PragmaPackAttr *A) { return true; }
|
||||
};
|
||||
|
||||
friend bool operator==(specific_attr_iterator Left,
|
||||
specific_attr_iterator Right) {
|
||||
if (Left.Current < Right.Current)
|
||||
Left.AdvanceToNext(Right.Current);
|
||||
class AlignedAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
public:
|
||||
AlignedAttr(unsigned alignment)
|
||||
: Attr(Aligned), Alignment(alignment) {}
|
||||
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
/// getMaxAlignment - Get the maximum alignment of attributes on this list.
|
||||
unsigned getMaxAlignment() const {
|
||||
const AlignedAttr *Next = getNext<AlignedAttr>();
|
||||
if (Next)
|
||||
return std::max(Next->getMaxAlignment(), Alignment);
|
||||
else
|
||||
Right.AdvanceToNext(Left.Current);
|
||||
return Left.Current == Right.Current;
|
||||
return Alignment;
|
||||
}
|
||||
friend bool operator!=(specific_attr_iterator Left,
|
||||
specific_attr_iterator Right) {
|
||||
return !(Left == Right);
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Aligned;
|
||||
}
|
||||
static bool classof(const AlignedAttr *A) { return true; }
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
class AnnotateAttr : public AttrWithString {
|
||||
public:
|
||||
AnnotateAttr(ASTContext &C, llvm::StringRef ann)
|
||||
: AttrWithString(Annotate, C, ann) {}
|
||||
|
||||
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;
|
||||
}
|
||||
llvm::StringRef getAnnotation() const { return getString(); }
|
||||
|
||||
/// 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;
|
||||
}
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Annotate;
|
||||
}
|
||||
static bool classof(const AnnotateAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AsmLabelAttr : public AttrWithString {
|
||||
public:
|
||||
AsmLabelAttr(ASTContext &C, llvm::StringRef L)
|
||||
: AttrWithString(AsmLabel, C, L) {}
|
||||
|
||||
llvm::StringRef getLabel() const { return getString(); }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == AsmLabel;
|
||||
}
|
||||
static bool classof(const AsmLabelAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(AlwaysInline);
|
||||
|
||||
class AliasAttr : public AttrWithString {
|
||||
public:
|
||||
AliasAttr(ASTContext &C, llvm::StringRef aliasee)
|
||||
: AttrWithString(Alias, C, aliasee) {}
|
||||
|
||||
llvm::StringRef getAliasee() const { return getString(); }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Alias; }
|
||||
static bool classof(const AliasAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ConstructorAttr : public Attr {
|
||||
int priority;
|
||||
public:
|
||||
ConstructorAttr(int p) : Attr(Constructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Constructor; }
|
||||
static bool classof(const ConstructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class DestructorAttr : public Attr {
|
||||
int priority;
|
||||
public:
|
||||
DestructorAttr(int p) : Attr(Destructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Destructor; }
|
||||
static bool classof(const DestructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class IBOutletAttr : public Attr {
|
||||
public:
|
||||
IBOutletAttr() : Attr(IBOutletKind) {}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == IBOutletKind;
|
||||
}
|
||||
static bool classof(const IBOutletAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class IBActionAttr : public Attr {
|
||||
public:
|
||||
IBActionAttr() : Attr(IBActionKind) {}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == IBActionKind;
|
||||
}
|
||||
static bool classof(const IBActionAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(AnalyzerNoReturn);
|
||||
DEF_SIMPLE_ATTR(Deprecated);
|
||||
DEF_SIMPLE_ATTR(Final);
|
||||
DEF_SIMPLE_ATTR(GNUInline);
|
||||
DEF_SIMPLE_ATTR(Malloc);
|
||||
DEF_SIMPLE_ATTR(NoReturn);
|
||||
|
||||
class SectionAttr : public AttrWithString {
|
||||
public:
|
||||
SectionAttr(ASTContext &C, llvm::StringRef N)
|
||||
: AttrWithString(Section, C, N) {}
|
||||
|
||||
llvm::StringRef getName() const { return getString(); }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Section;
|
||||
}
|
||||
static bool classof(const SectionAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(Unavailable);
|
||||
DEF_SIMPLE_ATTR(Unused);
|
||||
DEF_SIMPLE_ATTR(Used);
|
||||
DEF_SIMPLE_ATTR(Weak);
|
||||
DEF_SIMPLE_ATTR(WeakImport);
|
||||
DEF_SIMPLE_ATTR(WeakRef);
|
||||
DEF_SIMPLE_ATTR(NoThrow);
|
||||
DEF_SIMPLE_ATTR(Const);
|
||||
DEF_SIMPLE_ATTR(Pure);
|
||||
|
||||
class NonNullAttr : public Attr {
|
||||
unsigned* ArgNums;
|
||||
unsigned Size;
|
||||
public:
|
||||
NonNullAttr(ASTContext &C, unsigned* arg_nums = 0, unsigned size = 0);
|
||||
|
||||
virtual void Destroy(ASTContext &C);
|
||||
|
||||
typedef const unsigned *iterator;
|
||||
iterator begin() const { return ArgNums; }
|
||||
iterator end() const { return ArgNums + Size; }
|
||||
unsigned size() const { return Size; }
|
||||
|
||||
bool isNonNull(unsigned arg) const {
|
||||
return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
|
||||
}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == NonNull; }
|
||||
static bool classof(const NonNullAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FormatAttr : public AttrWithString {
|
||||
int formatIdx, firstArg;
|
||||
public:
|
||||
FormatAttr(ASTContext &C, llvm::StringRef type, int idx, int first)
|
||||
: AttrWithString(Format, C, type), formatIdx(idx), firstArg(first) {}
|
||||
|
||||
llvm::StringRef getType() const { return getString(); }
|
||||
void setType(ASTContext &C, llvm::StringRef type);
|
||||
int getFormatIdx() const { return formatIdx; }
|
||||
int getFirstArg() const { return firstArg; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Format; }
|
||||
static bool classof(const FormatAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FormatArgAttr : public Attr {
|
||||
int formatIdx;
|
||||
public:
|
||||
FormatArgAttr(int idx) : Attr(FormatArg), formatIdx(idx) {}
|
||||
int getFormatIdx() const { return formatIdx; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == FormatArg; }
|
||||
static bool classof(const FormatArgAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class SentinelAttr : public Attr {
|
||||
int sentinel, NullPos;
|
||||
public:
|
||||
SentinelAttr(int sentinel_val, int nullPos) : Attr(Sentinel),
|
||||
sentinel(sentinel_val), NullPos(nullPos) {}
|
||||
int getSentinel() const { return sentinel; }
|
||||
int getNullPos() const { return NullPos; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Sentinel; }
|
||||
static bool classof(const SentinelAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class VisibilityAttr : public Attr {
|
||||
public:
|
||||
/// @brief An enumeration for the kinds of visibility of symbols.
|
||||
enum VisibilityTypes {
|
||||
DefaultVisibility = 0,
|
||||
HiddenVisibility,
|
||||
ProtectedVisibility
|
||||
};
|
||||
private:
|
||||
VisibilityTypes VisibilityType;
|
||||
public:
|
||||
VisibilityAttr(VisibilityTypes v) : Attr(Visibility),
|
||||
VisibilityType(v) {}
|
||||
|
||||
VisibilityTypes getVisibility() const { return VisibilityType; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Visibility; }
|
||||
static bool classof(const VisibilityAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(FastCall);
|
||||
DEF_SIMPLE_ATTR(StdCall);
|
||||
DEF_SIMPLE_ATTR(CDecl);
|
||||
DEF_SIMPLE_ATTR(TransparentUnion);
|
||||
DEF_SIMPLE_ATTR(ObjCNSObject);
|
||||
DEF_SIMPLE_ATTR(ObjCException);
|
||||
|
||||
class OverloadableAttr : public Attr {
|
||||
public:
|
||||
OverloadableAttr() : Attr(Overloadable) { }
|
||||
|
||||
virtual bool isMerged() const { return false; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
|
||||
static bool classof(const OverloadableAttr *) { return true; }
|
||||
};
|
||||
|
||||
class BlocksAttr : public Attr {
|
||||
public:
|
||||
enum BlocksAttrTypes {
|
||||
ByRef = 0
|
||||
};
|
||||
private:
|
||||
BlocksAttrTypes BlocksAttrType;
|
||||
public:
|
||||
BlocksAttr(BlocksAttrTypes t) : Attr(Blocks), BlocksAttrType(t) {}
|
||||
|
||||
BlocksAttrTypes getType() const { return BlocksAttrType; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Blocks; }
|
||||
static bool classof(const BlocksAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FunctionDecl;
|
||||
|
||||
class CleanupAttr : public Attr {
|
||||
FunctionDecl *FD;
|
||||
|
||||
public:
|
||||
CleanupAttr(FunctionDecl *fd) : Attr(Cleanup), FD(fd) {}
|
||||
|
||||
const FunctionDecl *getFunctionDecl() const { return FD; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Cleanup; }
|
||||
static bool classof(const CleanupAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(NoDebug);
|
||||
DEF_SIMPLE_ATTR(WarnUnusedResult);
|
||||
DEF_SIMPLE_ATTR(NoInline);
|
||||
|
||||
class RegparmAttr : public Attr {
|
||||
unsigned NumParams;
|
||||
|
||||
public:
|
||||
RegparmAttr(unsigned np) : Attr(Regparm), NumParams(np) {}
|
||||
|
||||
unsigned getNumParams() const { return NumParams; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Regparm; }
|
||||
static bool classof(const RegparmAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ReqdWorkGroupSizeAttr : public Attr {
|
||||
unsigned X, Y, Z;
|
||||
public:
|
||||
ReqdWorkGroupSizeAttr(unsigned X, unsigned Y, unsigned Z)
|
||||
: Attr(ReqdWorkGroupSize), X(X), Y(Y), Z(Z) {}
|
||||
|
||||
unsigned getXDim() const { return X; }
|
||||
unsigned getYDim() const { return Y; }
|
||||
unsigned getZDim() const { return Z; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == ReqdWorkGroupSize;
|
||||
}
|
||||
static bool classof(const ReqdWorkGroupSizeAttr *A) { return true; }
|
||||
};
|
||||
|
||||
// Checker-specific attributes.
|
||||
DEF_SIMPLE_ATTR(CFReturnsNotRetained);
|
||||
DEF_SIMPLE_ATTR(CFReturnsRetained);
|
||||
DEF_SIMPLE_ATTR(NSReturnsNotRetained);
|
||||
DEF_SIMPLE_ATTR(NSReturnsRetained);
|
||||
|
||||
// C++0x member checking attributes.
|
||||
DEF_SIMPLE_ATTR(BaseCheck);
|
||||
DEF_SIMPLE_ATTR(Hiding);
|
||||
DEF_SIMPLE_ATTR(Override);
|
||||
|
||||
// Target-specific attributes
|
||||
DEF_SIMPLE_ATTR(DLLImport);
|
||||
DEF_SIMPLE_ATTR(DLLExport);
|
||||
|
||||
class MSP430InterruptAttr : public Attr {
|
||||
unsigned Number;
|
||||
|
||||
public:
|
||||
MSP430InterruptAttr(unsigned n) : Attr(MSP430Interrupt), Number(n) {}
|
||||
|
||||
unsigned getNumber() const { return Number; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == MSP430Interrupt; }
|
||||
static bool classof(const MSP430InterruptAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(X86ForceAlignArgPointer);
|
||||
|
||||
#undef DEF_SIMPLE_ATTR
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
//===--- 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
|
||||
@@ -1,17 +0,0 @@
|
||||
clang_tablegen(Attrs.inc -gen-clang-attr-classes
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||
SOURCE ../Basic/Attr.td
|
||||
TARGET ClangAttrClasses)
|
||||
|
||||
clang_tablegen(AttrImpl.inc -gen-clang-attr-impl
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||
SOURCE ../Basic/Attr.td
|
||||
TARGET ClangAttrImpl)
|
||||
|
||||
clang_tablegen(StmtNodes.inc -gen-clang-stmt-nodes
|
||||
SOURCE ../Basic/StmtNodes.td
|
||||
TARGET ClangStmtNodes)
|
||||
|
||||
clang_tablegen(DeclNodes.inc -gen-clang-decl-nodes
|
||||
SOURCE ../Basic/DeclNodes.td
|
||||
TARGET ClangDeclNodes)
|
||||
@@ -19,8 +19,6 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
@@ -66,7 +64,7 @@ struct CXXBasePathElement {
|
||||
/// structure, which captures both the link from a derived class to one of its
|
||||
/// direct bases and identification describing which base class
|
||||
/// subobject is being used.
|
||||
class CXXBasePath : public SmallVector<CXXBasePathElement, 4> {
|
||||
class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
|
||||
public:
|
||||
CXXBasePath() : Access(AS_public) {}
|
||||
|
||||
@@ -80,14 +78,14 @@ public:
|
||||
DeclContext::lookup_result Decls;
|
||||
|
||||
void clear() {
|
||||
SmallVectorImpl<CXXBasePathElement>::clear();
|
||||
llvm::SmallVectorImpl<CXXBasePathElement>::clear();
|
||||
Access = AS_public;
|
||||
}
|
||||
};
|
||||
|
||||
/// BasePaths - Represents the set of paths from a derived class to
|
||||
/// one of its (direct or indirect) bases. For example, given the
|
||||
/// following class hierarchy:
|
||||
/// following class hierachy:
|
||||
///
|
||||
/// @code
|
||||
/// class A { };
|
||||
@@ -197,7 +195,7 @@ public:
|
||||
/// \brief Determine whether the path from the most-derived type to the
|
||||
/// given base type is ambiguous (i.e., it refers to multiple subobjects of
|
||||
/// the same base type).
|
||||
bool isAmbiguous(CanQualType BaseType);
|
||||
bool isAmbiguous(QualType BaseType);
|
||||
|
||||
/// \brief Whether we are finding multiple paths to detect ambiguities.
|
||||
bool isFindingAmbiguities() const { return FindAmbiguities; }
|
||||
@@ -229,142 +227,7 @@ public:
|
||||
/// object.
|
||||
void swap(CXXBasePaths &Other);
|
||||
};
|
||||
|
||||
/// \brief Uniquely identifies a virtual method within a class
|
||||
/// hierarchy by the method itself and a class subobject number.
|
||||
struct UniqueVirtualMethod {
|
||||
UniqueVirtualMethod() : Method(0), Subobject(0), InVirtualSubobject(0) { }
|
||||
|
||||
UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
|
||||
const CXXRecordDecl *InVirtualSubobject)
|
||||
: Method(Method), Subobject(Subobject),
|
||||
InVirtualSubobject(InVirtualSubobject) { }
|
||||
|
||||
/// \brief The overriding virtual method.
|
||||
CXXMethodDecl *Method;
|
||||
|
||||
/// \brief The subobject in which the overriding virtual method
|
||||
/// resides.
|
||||
unsigned Subobject;
|
||||
|
||||
/// \brief The virtual base class subobject of which this overridden
|
||||
/// virtual method is a part. Note that this records the closest
|
||||
/// derived virtual base class subobject.
|
||||
const CXXRecordDecl *InVirtualSubobject;
|
||||
|
||||
friend bool operator==(const UniqueVirtualMethod &X,
|
||||
const UniqueVirtualMethod &Y) {
|
||||
return X.Method == Y.Method && X.Subobject == Y.Subobject &&
|
||||
X.InVirtualSubobject == Y.InVirtualSubobject;
|
||||
}
|
||||
|
||||
friend bool operator!=(const UniqueVirtualMethod &X,
|
||||
const UniqueVirtualMethod &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief The set of methods that override a given virtual method in
|
||||
/// each subobject where it occurs.
|
||||
///
|
||||
/// The first part of the pair is the subobject in which the
|
||||
/// overridden virtual function occurs, while the second part of the
|
||||
/// pair is the virtual method that overrides it (including the
|
||||
/// subobject in which that virtual function occurs).
|
||||
class OverridingMethods {
|
||||
llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
Overrides;
|
||||
|
||||
public:
|
||||
// Iterate over the set of subobjects that have overriding methods.
|
||||
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
::iterator iterator;
|
||||
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
::const_iterator const_iterator;
|
||||
iterator begin() { return Overrides.begin(); }
|
||||
const_iterator begin() const { return Overrides.begin(); }
|
||||
iterator end() { return Overrides.end(); }
|
||||
const_iterator end() const { return Overrides.end(); }
|
||||
unsigned size() const { return Overrides.size(); }
|
||||
|
||||
// Iterate over the set of overriding virtual methods in a given
|
||||
// subobject.
|
||||
typedef SmallVector<UniqueVirtualMethod, 4>::iterator
|
||||
overriding_iterator;
|
||||
typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator
|
||||
overriding_const_iterator;
|
||||
|
||||
// Add a new overriding method for a particular subobject.
|
||||
void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding);
|
||||
|
||||
// Add all of the overriding methods from "other" into overrides for
|
||||
// this method. Used when merging the overrides from multiple base
|
||||
// class subobjects.
|
||||
void add(const OverridingMethods &Other);
|
||||
|
||||
// Replace all overriding virtual methods in all subobjects with the
|
||||
// given virtual method.
|
||||
void replaceAll(UniqueVirtualMethod Overriding);
|
||||
};
|
||||
|
||||
/// \brief A mapping from each virtual member function to its set of
|
||||
/// final overriders.
|
||||
///
|
||||
/// Within a class hierarchy for a given derived class, each virtual
|
||||
/// member function in that hierarchy has one or more "final
|
||||
/// overriders" (C++ [class.virtual]p2). A final overrider for a
|
||||
/// virtual function "f" is the virtual function that will actually be
|
||||
/// invoked when dispatching a call to "f" through the
|
||||
/// vtable. Well-formed classes have a single final overrider for each
|
||||
/// virtual function; in abstract classes, the final overrider for at
|
||||
/// least one virtual function is a pure virtual function. Due to
|
||||
/// multiple, virtual inheritance, it is possible for a class to have
|
||||
/// more than one final overrider. Athough this is an error (per C++
|
||||
/// [class.virtual]p2), it is not considered an error here: the final
|
||||
/// overrider map can represent multiple final overriders for a
|
||||
/// method, and it is up to the client to determine whether they are
|
||||
/// problem. For example, the following class \c D has two final
|
||||
/// overriders for the virtual function \c A::f(), one in \c C and one
|
||||
/// in \c D:
|
||||
///
|
||||
/// \code
|
||||
/// struct A { virtual void f(); };
|
||||
/// struct B : virtual A { virtual void f(); };
|
||||
/// struct C : virtual A { virtual void f(); };
|
||||
/// struct D : B, C { };
|
||||
/// \endcode
|
||||
///
|
||||
/// This data structure contaings a mapping from every virtual
|
||||
/// function *that does not override an existing virtual function* and
|
||||
/// in every subobject where that virtual function occurs to the set
|
||||
/// of virtual functions that override it. Thus, the same virtual
|
||||
/// function \c A::f can actually occur in multiple subobjects of type
|
||||
/// \c A due to multiple inheritance, and may be overriden by
|
||||
/// different virtual functions in each, as in the following example:
|
||||
///
|
||||
/// \code
|
||||
/// struct A { virtual void f(); };
|
||||
/// struct B : A { virtual void f(); };
|
||||
/// struct C : A { virtual void f(); };
|
||||
/// struct D : B, C { };
|
||||
/// \endcode
|
||||
///
|
||||
/// Unlike in the previous example, where the virtual functions \c
|
||||
/// B::f and \c C::f both overrode \c A::f in the same subobject of
|
||||
/// type \c A, in this example the two virtual functions both override
|
||||
/// \c A::f but in *different* subobjects of type A. This is
|
||||
/// represented by numbering the subobjects in which the overridden
|
||||
/// and the overriding virtual member functions are located. Subobject
|
||||
/// 0 represents the virtua base class subobject of that type, while
|
||||
/// subobject numbers greater than 0 refer to non-virtual base class
|
||||
/// subobjects of that type.
|
||||
class CXXFinalOverriderMap
|
||||
: public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
|
||||
|
||||
/// \brief A set of all the primary bases for a class.
|
||||
class CXXIndirectPrimaryBaseSet
|
||||
: public llvm::SmallSet<const CXXRecordDecl*, 32> { };
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
@@ -66,16 +66,7 @@ public:
|
||||
|
||||
/// \brief Retrieve the underlying type pointer, which refers to a
|
||||
/// canonical type.
|
||||
///
|
||||
/// The underlying pointer must not be NULL.
|
||||
const T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); }
|
||||
|
||||
/// \brief Retrieve the underlying type pointer, which refers to a
|
||||
/// canonical type, or NULL.
|
||||
///
|
||||
const T *getTypePtrOrNull() const {
|
||||
return cast_or_null<T>(Stored.getTypePtrOrNull());
|
||||
}
|
||||
T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); }
|
||||
|
||||
/// \brief Implicit conversion to a qualified type.
|
||||
operator QualType() const { return Stored; }
|
||||
@@ -87,8 +78,6 @@ public:
|
||||
return Stored.isNull();
|
||||
}
|
||||
|
||||
SplitQualType split() const { return Stored.split(); }
|
||||
|
||||
/// \brief Retrieve a canonical type pointer with a different static type,
|
||||
/// upcasting or downcasting as needed.
|
||||
///
|
||||
@@ -176,8 +165,6 @@ public:
|
||||
// (dynamic) type.
|
||||
static CanQual<T> CreateUnsafe(QualType Other);
|
||||
|
||||
void dump() const { Stored.dump(); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddPointer(getAsOpaquePtr());
|
||||
}
|
||||
@@ -227,7 +214,7 @@ protected:
|
||||
|
||||
public:
|
||||
/// \brief Retrieve the pointer to the underlying Type
|
||||
const T *getTypePtr() const { return Stored.getTypePtr(); }
|
||||
T* getTypePtr() const { return Stored.getTypePtr(); }
|
||||
|
||||
/// \brief Implicit conversion to the underlying pointer.
|
||||
///
|
||||
@@ -236,7 +223,7 @@ public:
|
||||
/// @code
|
||||
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
|
||||
/// @endcode
|
||||
operator const T*() const { return this->Stored.getTypePtrOrNull(); }
|
||||
operator const T*() const { return this->Stored.getTypePtr(); }
|
||||
|
||||
/// \brief Try to convert the given canonical type to a specific structural
|
||||
/// type.
|
||||
@@ -250,6 +237,7 @@ public:
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPODType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType)
|
||||
@@ -257,7 +245,6 @@ public:
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isCharType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isWideCharType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralOrEnumerationType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealFloatingType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyComplexType)
|
||||
@@ -274,27 +261,18 @@ public:
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArrayType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasIntegerRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasSignedIntegerRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasUnsignedIntegerRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasFloatingRepresentation)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerOrEnumerationType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerOrEnumerationType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CXXRecordDecl*, getAsCXXRecordDecl)
|
||||
|
||||
/// \brief Retrieve the proxy-adaptor type.
|
||||
///
|
||||
@@ -349,7 +327,7 @@ namespace llvm {
|
||||
/// to return smart pointer (proxies?).
|
||||
template<typename T>
|
||||
struct simplify_type<const ::clang::CanQual<T> > {
|
||||
typedef const T *SimpleType;
|
||||
typedef T* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) {
|
||||
return Val.getTypePtr();
|
||||
}
|
||||
@@ -584,21 +562,24 @@ struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionNoProtoType>
|
||||
: public CanProxyBase<FunctionNoProtoType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionProtoType>
|
||||
: public CanProxyBase<FunctionProtoType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs)
|
||||
CanQualType getArgType(unsigned i) const {
|
||||
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
|
||||
@@ -632,14 +613,6 @@ struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
|
||||
};
|
||||
|
||||
template <>
|
||||
struct CanProxyAdaptor<UnaryTransformType>
|
||||
: public CanProxyBase<UnaryTransformType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType)
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(UnaryTransformType::UTTKind, getUTTKind)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl)
|
||||
@@ -651,6 +624,7 @@ struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace)
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -665,26 +639,7 @@ struct CanProxyAdaptor<TemplateTypeParmType>
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TemplateTypeParmDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getIdentifier)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<ObjCObjectType>
|
||||
: public CanProxyBase<ObjCObjectType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceDecl *,
|
||||
getInterface)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedId)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedClass)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedId)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClass)
|
||||
|
||||
typedef ObjCObjectPointerType::qual_iterator qual_iterator;
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getName)
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -724,9 +679,9 @@ inline CanQual<Type> CanQual<T>::getNonReferenceType() const {
|
||||
template<typename T>
|
||||
CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) {
|
||||
CanQual<T> Result;
|
||||
Result.Stored = QualType::getFromOpaquePtr(Ptr);
|
||||
assert((!Result || Result.Stored.getAsOpaquePtr() == (void*)-1 ||
|
||||
Result.Stored.isCanonical()) && "Type is not canonical!");
|
||||
Result.Stored.setFromOpaqueValue(Ptr);
|
||||
assert((!Result || Result.Stored.isCanonical())
|
||||
&& "Type is not canonical!");
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,7 @@
|
||||
#ifndef LLVM_CLANG_AST_CHARUNITS_H
|
||||
#define LLVM_CLANG_AST_CHARUNITS_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/System/DataTypes.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@@ -34,7 +32,7 @@ namespace clang {
|
||||
/// architectures where the two are the same size.
|
||||
///
|
||||
/// For portability, never assume that a target character is 8 bits wide. Use
|
||||
/// CharUnit values wherever you calculate sizes, offsets, or alignments
|
||||
/// CharUnit values whereever you calculate sizes, offsets, or alignments
|
||||
/// in character units.
|
||||
class CharUnits {
|
||||
public:
|
||||
@@ -70,24 +68,10 @@ namespace clang {
|
||||
Quantity += Other.Quantity;
|
||||
return *this;
|
||||
}
|
||||
CharUnits& operator++ () {
|
||||
++Quantity;
|
||||
return *this;
|
||||
}
|
||||
CharUnits operator++ (int) {
|
||||
return CharUnits(Quantity++);
|
||||
}
|
||||
CharUnits& operator-= (const CharUnits &Other) {
|
||||
Quantity -= Other.Quantity;
|
||||
return *this;
|
||||
}
|
||||
CharUnits& operator-- () {
|
||||
--Quantity;
|
||||
return *this;
|
||||
}
|
||||
CharUnits operator-- (int) {
|
||||
return CharUnits(Quantity--);
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
bool operator== (const CharUnits &Other) const {
|
||||
@@ -125,12 +109,6 @@ namespace clang {
|
||||
/// isNegative - Test whether the quantity is less than zero.
|
||||
bool isNegative() const { return Quantity < 0; }
|
||||
|
||||
/// isPowerOfTwo - Test whether the quantity is a power of two.
|
||||
/// Zero is not a power of two.
|
||||
bool isPowerOfTwo() const {
|
||||
return (Quantity & -Quantity) == Quantity;
|
||||
}
|
||||
|
||||
// Arithmetic operators.
|
||||
CharUnits operator* (QuantityType N) const {
|
||||
return CharUnits(Quantity * N);
|
||||
@@ -153,24 +131,12 @@ namespace clang {
|
||||
CharUnits operator- (const CharUnits &Other) const {
|
||||
return CharUnits(Quantity - Other.Quantity);
|
||||
}
|
||||
CharUnits operator- () const {
|
||||
return CharUnits(-Quantity);
|
||||
}
|
||||
|
||||
|
||||
// Conversions.
|
||||
|
||||
/// getQuantity - Get the raw integer representation of this quantity.
|
||||
QuantityType getQuantity() const { return Quantity; }
|
||||
|
||||
/// RoundUpToAlignment - Returns the next integer (mod 2**64) that is
|
||||
/// greater than or equal to this quantity and is a multiple of \arg
|
||||
/// Align. Align must be non-zero.
|
||||
CharUnits RoundUpToAlignment(const CharUnits &Align) {
|
||||
return CharUnits(llvm::RoundUpToAlignment(Quantity,
|
||||
Align.Quantity));
|
||||
}
|
||||
|
||||
|
||||
}; // class CharUnit
|
||||
} // namespace clang
|
||||
@@ -180,38 +146,4 @@ inline clang::CharUnits operator* (clang::CharUnits::QuantityType Scale,
|
||||
return CU * Scale;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<> struct DenseMapInfo<clang::CharUnits> {
|
||||
static clang::CharUnits getEmptyKey() {
|
||||
clang::CharUnits::QuantityType Quantity =
|
||||
DenseMapInfo<clang::CharUnits::QuantityType>::getEmptyKey();
|
||||
|
||||
return clang::CharUnits::fromQuantity(Quantity);
|
||||
}
|
||||
|
||||
static clang::CharUnits getTombstoneKey() {
|
||||
clang::CharUnits::QuantityType Quantity =
|
||||
DenseMapInfo<clang::CharUnits::QuantityType>::getTombstoneKey();
|
||||
|
||||
return clang::CharUnits::fromQuantity(Quantity);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::CharUnits &CU) {
|
||||
clang::CharUnits::QuantityType Quantity = CU.getQuantity();
|
||||
return DenseMapInfo<clang::CharUnits::QuantityType>::getHashValue(Quantity);
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::CharUnits &LHS,
|
||||
const clang::CharUnits &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct isPodLike<clang::CharUnits> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CLANG_AST_CHARUNITS_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +0,0 @@
|
||||
//===--- DeclAccessPair.h - A decl bundled with its path access -*- 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 DeclAccessPair class, which provides an
|
||||
// efficient representation of a pair of a NamedDecl* and an
|
||||
// AccessSpecifier. Generally the access specifier gives the
|
||||
// natural access of a declaration when named in a class, as
|
||||
// defined in C++ [class.access.base]p1.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLACCESSPAIR_H
|
||||
#define LLVM_CLANG_AST_DECLACCESSPAIR_H
|
||||
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class NamedDecl;
|
||||
|
||||
/// A POD class for pairing a NamedDecl* with an access specifier.
|
||||
/// Can be put into unions.
|
||||
class DeclAccessPair {
|
||||
NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
|
||||
|
||||
enum { Mask = 0x3 };
|
||||
|
||||
public:
|
||||
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
|
||||
DeclAccessPair p;
|
||||
p.set(D, AS);
|
||||
return p;
|
||||
}
|
||||
|
||||
NamedDecl *getDecl() const {
|
||||
return (NamedDecl*) (~Mask & (uintptr_t) Ptr);
|
||||
}
|
||||
AccessSpecifier getAccess() const {
|
||||
return AccessSpecifier(Mask & (uintptr_t) Ptr);
|
||||
}
|
||||
|
||||
void setDecl(NamedDecl *D) {
|
||||
set(D, getAccess());
|
||||
}
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
set(getDecl(), AS);
|
||||
}
|
||||
void set(NamedDecl *D, AccessSpecifier AS) {
|
||||
Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) |
|
||||
reinterpret_cast<uintptr_t>(D));
|
||||
}
|
||||
|
||||
operator NamedDecl*() const { return getDecl(); }
|
||||
NamedDecl *operator->() const { return getDecl(); }
|
||||
};
|
||||
}
|
||||
|
||||
// Take a moment to tell SmallVector that DeclAccessPair is POD.
|
||||
namespace llvm {
|
||||
template<typename> struct isPodLike;
|
||||
template<> struct isPodLike<clang::DeclAccessPair> {
|
||||
static const bool value = true;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -41,9 +41,6 @@ class LinkageSpecDecl;
|
||||
class BlockDecl;
|
||||
class DeclarationName;
|
||||
class CompoundStmt;
|
||||
class StoredDeclsMap;
|
||||
class DependentDiagnostic;
|
||||
class ASTMutationListener;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
@@ -62,15 +59,6 @@ public:
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Captures the result of checking the availability of a
|
||||
/// declaration.
|
||||
enum AvailabilityResult {
|
||||
AR_Available = 0,
|
||||
AR_NotYetIntroduced,
|
||||
AR_Deprecated,
|
||||
AR_Unavailable
|
||||
};
|
||||
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
///
|
||||
@@ -78,98 +66,39 @@ class Decl {
|
||||
public:
|
||||
/// \brief Lists the kind of concrete classes of Decl.
|
||||
enum Kind {
|
||||
#define DECL(DERIVED, BASE) DERIVED,
|
||||
#define ABSTRACT_DECL(DECL)
|
||||
#define DECL_RANGE(BASE, START, END) \
|
||||
first##BASE = START, last##BASE = END,
|
||||
#define LAST_DECL_RANGE(BASE, START, END) \
|
||||
first##BASE = START, last##BASE = END
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
#define DECL(Derived, Base) Derived,
|
||||
#define DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End,
|
||||
#define LAST_DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
};
|
||||
|
||||
/// \brief A placeholder type used to construct an empty shell of a
|
||||
/// decl-derived type that will be filled in later (e.g., by some
|
||||
/// deserialization method).
|
||||
struct EmptyShell { };
|
||||
|
||||
/// IdentifierNamespace - The different namespaces in which
|
||||
/// declarations may appear. According to C99 6.2.3, there are
|
||||
/// four namespaces, labels, tags, members and ordinary
|
||||
/// identifiers. C++ describes lookup completely differently:
|
||||
/// certain lookups merely "ignore" certain kinds of declarations,
|
||||
/// usually based on whether the declaration is of a type, etc.
|
||||
///
|
||||
/// These are meant as bitmasks, so that searches in
|
||||
/// C++ can look into the "tag" namespace during ordinary lookup.
|
||||
///
|
||||
/// Decl currently provides 15 bits of IDNS bits.
|
||||
/// IdentifierNamespace - According to C99 6.2.3, there are four
|
||||
/// namespaces, labels, tags, members and ordinary
|
||||
/// identifiers. These are meant as bitmasks, so that searches in
|
||||
/// C++ can look into the "tag" namespace during ordinary lookup. We
|
||||
/// use additional namespaces for Objective-C entities. We also put
|
||||
/// C++ friend declarations (of previously-undeclared entities) in
|
||||
/// shadow namespaces, and 'using' declarations (as opposed to their
|
||||
/// implicit shadow declarations) can be found in their own
|
||||
/// namespace.
|
||||
enum IdentifierNamespace {
|
||||
/// Labels, declared with 'x:' and referenced with 'goto x'.
|
||||
IDNS_Label = 0x0001,
|
||||
|
||||
/// Tags, declared with 'struct foo;' and referenced with
|
||||
/// 'struct foo'. All tags are also types. This is what
|
||||
/// elaborated-type-specifiers look for in C.
|
||||
IDNS_Tag = 0x0002,
|
||||
|
||||
/// Types, declared with 'struct foo', typedefs, etc.
|
||||
/// This is what elaborated-type-specifiers look for in C++,
|
||||
/// but note that it's ill-formed to find a non-tag.
|
||||
IDNS_Type = 0x0004,
|
||||
|
||||
/// Members, declared with object declarations within tag
|
||||
/// definitions. In C, these can only be found by "qualified"
|
||||
/// lookup in member expressions. In C++, they're found by
|
||||
/// normal lookup.
|
||||
IDNS_Member = 0x0008,
|
||||
|
||||
/// Namespaces, declared with 'namespace foo {}'.
|
||||
/// Lookup for nested-name-specifiers find these.
|
||||
IDNS_Namespace = 0x0010,
|
||||
|
||||
/// Ordinary names. In C, everything that's not a label, tag,
|
||||
/// or member ends up here.
|
||||
IDNS_Ordinary = 0x0020,
|
||||
|
||||
/// Objective C @protocol.
|
||||
IDNS_ObjCProtocol = 0x0040,
|
||||
|
||||
/// This declaration is a friend function. A friend function
|
||||
/// declaration is always in this namespace but may also be in
|
||||
/// IDNS_Ordinary if it was previously declared.
|
||||
IDNS_OrdinaryFriend = 0x0080,
|
||||
|
||||
/// This declaration is a friend class. A friend class
|
||||
/// declaration is always in this namespace but may also be in
|
||||
/// IDNS_Tag|IDNS_Type if it was previously declared.
|
||||
IDNS_TagFriend = 0x0100,
|
||||
|
||||
/// This declaration is a using declaration. A using declaration
|
||||
/// *introduces* a number of other declarations into the current
|
||||
/// scope, and those declarations use the IDNS of their targets,
|
||||
/// but the actual using declarations go in this namespace.
|
||||
IDNS_Using = 0x0200,
|
||||
|
||||
/// This declaration is a C++ operator declared in a non-class
|
||||
/// context. All such operators are also in IDNS_Ordinary.
|
||||
/// C++ lexical operator lookup looks for these.
|
||||
IDNS_NonMemberOperator = 0x0400
|
||||
IDNS_Label = 0x1,
|
||||
IDNS_Tag = 0x2,
|
||||
IDNS_Member = 0x4,
|
||||
IDNS_Ordinary = 0x8,
|
||||
IDNS_ObjCProtocol = 0x10,
|
||||
IDNS_ObjCImplementation = 0x20,
|
||||
IDNS_ObjCCategoryName = 0x40,
|
||||
IDNS_OrdinaryFriend = 0x80,
|
||||
IDNS_TagFriend = 0x100,
|
||||
IDNS_Using = 0x200
|
||||
};
|
||||
|
||||
/// ObjCDeclQualifier - 'Qualifiers' written next to the return and
|
||||
/// parameter types in method declarations. Other than remembering
|
||||
/// them and mangling them into the method's signature string, these
|
||||
/// are ignored by the compiler; they are consumed by certain
|
||||
/// remote-messaging frameworks.
|
||||
///
|
||||
/// in, inout, and out are mutually exclusive and apply only to
|
||||
/// method parameters. bycopy and byref are mutually exclusive and
|
||||
/// apply only to method parameters (?). oneway applies only to
|
||||
/// results. All of these expect their corresponding parameter to
|
||||
/// have a particular type. None of this is currently enforced by
|
||||
/// clang.
|
||||
///
|
||||
/// This should be kept in sync with ObjCDeclSpec::ObjCDeclQualifier.
|
||||
/// ObjCDeclQualifier - Qualifier used on types in method declarations
|
||||
/// for remote messaging. They are meant for the arguments though and
|
||||
/// applied to the Decls (ObjCMethodDecl and ParmVarDecl).
|
||||
enum ObjCDeclQualifier {
|
||||
OBJC_TQ_None = 0x0,
|
||||
OBJC_TQ_In = 0x1,
|
||||
@@ -218,90 +147,55 @@ private:
|
||||
return DeclCtx.get<DeclContext*>();
|
||||
}
|
||||
|
||||
/// Loc - The location of this decl.
|
||||
/// Loc - The location that this decl.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// DeclKind - This indicates which class this is.
|
||||
unsigned DeclKind : 8;
|
||||
Kind DeclKind : 8;
|
||||
|
||||
/// InvalidDecl - This indicates a semantic error occurred.
|
||||
unsigned InvalidDecl : 1;
|
||||
unsigned int InvalidDecl : 1;
|
||||
|
||||
/// HasAttrs - This indicates whether the decl has attributes or not.
|
||||
unsigned HasAttrs : 1;
|
||||
unsigned int HasAttrs : 1;
|
||||
|
||||
/// Implicit - Whether this declaration was implicitly generated by
|
||||
/// the implementation rather than explicitly written by the user.
|
||||
unsigned Implicit : 1;
|
||||
bool Implicit : 1;
|
||||
|
||||
/// \brief Whether this declaration was "used", meaning that a definition is
|
||||
/// required.
|
||||
unsigned Used : 1;
|
||||
bool Used : 1;
|
||||
|
||||
/// \brief Whether this declaration was "referenced".
|
||||
/// The difference with 'Used' is whether the reference appears in a
|
||||
/// evaluated context or not, e.g. functions used in uninstantiated templates
|
||||
/// are regarded as "referenced" but not "used".
|
||||
unsigned Referenced : 1;
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
unsigned Access : 2;
|
||||
friend class CXXClassMemberWrapper;
|
||||
|
||||
/// \brief Whether this declaration was loaded from an AST file.
|
||||
unsigned FromASTFile : 1;
|
||||
|
||||
/// ChangedAfterLoad - if this declaration has changed since being loaded
|
||||
unsigned ChangedAfterLoad : 1;
|
||||
|
||||
/// \brief Whether this declaration is private to the module in which it was
|
||||
/// defined.
|
||||
unsigned ModulePrivate : 1;
|
||||
|
||||
// PCHLevel - the "level" of precompiled header/AST file from which this
|
||||
// declaration was built.
|
||||
unsigned PCHLevel : 2;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 12;
|
||||
|
||||
/// \brief Whether the \c CachedLinkage field is active.
|
||||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned HasCachedLinkage : 1;
|
||||
|
||||
/// \brief If \c HasCachedLinkage, the linkage of this declaration.
|
||||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned CachedLinkage : 2;
|
||||
|
||||
friend class ASTDeclWriter;
|
||||
friend class ASTDeclReader;
|
||||
unsigned IdentifierNamespace : 16;
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
void CheckAccessDeclContext() const;
|
||||
#else
|
||||
void CheckAccessDeclContext() const { }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
|
||||
ModulePrivate(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
if (Decl::CollectingStats()) add(DK);
|
||||
}
|
||||
|
||||
Decl(Kind DK, EmptyShell Empty)
|
||||
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
|
||||
ModulePrivate(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
if (Decl::CollectingStats()) add(DK);
|
||||
HasAttrs(false), Implicit(false), Used(false),
|
||||
Access(AS_none), PCHLevel(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
|
||||
virtual ~Decl();
|
||||
@@ -318,7 +212,7 @@ public:
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
Kind getKind() const { return static_cast<Kind>(DeclKind); }
|
||||
Kind getKind() const { return DeclKind; }
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
Decl *getNextDeclInContext() { return NextDeclInContext; }
|
||||
@@ -333,13 +227,6 @@ public:
|
||||
return const_cast<Decl*>(this)->getDeclContext();
|
||||
}
|
||||
|
||||
/// Finds the innermost non-closure context of this declaration.
|
||||
/// That is, walk out the DeclContext chain, skipping any blocks.
|
||||
DeclContext *getNonClosureContext();
|
||||
const DeclContext *getNonClosureContext() const {
|
||||
return const_cast<Decl*>(this)->getNonClosureContext();
|
||||
}
|
||||
|
||||
TranslationUnitDecl *getTranslationUnitDecl();
|
||||
const TranslationUnitDecl *getTranslationUnitDecl() const {
|
||||
return const_cast<Decl*>(this)->getTranslationUnitDecl();
|
||||
@@ -351,82 +238,32 @@ public:
|
||||
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
Access = AS;
|
||||
#ifndef NDEBUG
|
||||
CheckAccessDeclContext();
|
||||
#endif
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
#ifndef NDEBUG
|
||||
CheckAccessDeclContext();
|
||||
#endif
|
||||
return AccessSpecifier(Access);
|
||||
}
|
||||
|
||||
bool hasAttrs() const { return HasAttrs; }
|
||||
void setAttrs(const AttrVec& Attrs);
|
||||
AttrVec &getAttrs() {
|
||||
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
|
||||
void addAttr(Attr *attr);
|
||||
const Attr *getAttrs() const {
|
||||
if (!HasAttrs) return 0; // common case, no attributes.
|
||||
return getAttrsImpl(); // Uncommon case, out of line hash lookup.
|
||||
}
|
||||
const AttrVec &getAttrs() const;
|
||||
void swapAttrs(Decl *D);
|
||||
void dropAttrs();
|
||||
void invalidateAttrs();
|
||||
|
||||
void addAttr(Attr *A) {
|
||||
if (hasAttrs())
|
||||
getAttrs().push_back(A);
|
||||
else
|
||||
setAttrs(AttrVec(1, A));
|
||||
template<typename T> const T *getAttr() const {
|
||||
for (const Attr *attr = getAttrs(); attr; attr = attr->getNext())
|
||||
if (const T *V = dyn_cast<T>(attr))
|
||||
return V;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef AttrVec::const_iterator attr_iterator;
|
||||
|
||||
// FIXME: Do not rely on iterators having comparable singular values.
|
||||
// Note that this should error out if they do not.
|
||||
attr_iterator attr_begin() const {
|
||||
return hasAttrs() ? getAttrs().begin() : 0;
|
||||
}
|
||||
attr_iterator attr_end() const {
|
||||
return hasAttrs() ? getAttrs().end() : 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void dropAttr() {
|
||||
if (!HasAttrs) return;
|
||||
|
||||
AttrVec &Attrs = getAttrs();
|
||||
for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) {
|
||||
if (isa<T>(Attrs[i])) {
|
||||
Attrs.erase(Attrs.begin() + i);
|
||||
--e;
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
if (Attrs.empty())
|
||||
HasAttrs = false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
specific_attr_iterator<T> specific_attr_begin() const {
|
||||
return specific_attr_iterator<T>(attr_begin());
|
||||
}
|
||||
template <typename T>
|
||||
specific_attr_iterator<T> specific_attr_end() const {
|
||||
return specific_attr_iterator<T>(attr_end());
|
||||
}
|
||||
|
||||
template<typename T> T *getAttr() const {
|
||||
return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : 0;
|
||||
}
|
||||
template<typename T> bool hasAttr() const {
|
||||
return hasAttrs() && hasSpecificAttr<T>(getAttrs());
|
||||
}
|
||||
|
||||
/// getMaxAlignment - return the maximum alignment specified by attributes
|
||||
/// on this decl, 0 if there are none.
|
||||
unsigned getMaxAlignment() const {
|
||||
return hasAttrs() ? getMaxAttrAlignment(getAttrs(), getASTContext()) : 0;
|
||||
return getAttr<T>() != 0;
|
||||
}
|
||||
|
||||
/// setInvalidDecl - Indicates the Decl had a semantic error. This
|
||||
@@ -442,82 +279,30 @@ public:
|
||||
|
||||
/// \brief Whether this declaration was used, meaning that a definition
|
||||
/// is required.
|
||||
///
|
||||
/// \param CheckUsedAttr When true, also consider the "used" attribute
|
||||
/// (in addition to the "used" bit set by \c setUsed()) when determining
|
||||
/// whether the function is used.
|
||||
bool isUsed(bool CheckUsedAttr = true) const;
|
||||
|
||||
bool isUsed() const;
|
||||
|
||||
void setUsed(bool U = true) { Used = U; }
|
||||
|
||||
/// \brief Whether this declaration was referenced.
|
||||
bool isReferenced() const;
|
||||
|
||||
void setReferenced(bool R = true) { Referenced = R; }
|
||||
|
||||
/// \brief Determine the availability of the given declaration.
|
||||
/// \brief Retrieve the level of precompiled header from which this
|
||||
/// declaration was generated.
|
||||
///
|
||||
/// This routine will determine the most restrictive availability of
|
||||
/// the given declaration (e.g., preferring 'unavailable' to
|
||||
/// 'deprecated').
|
||||
///
|
||||
/// \param Message If non-NULL and the result is not \c
|
||||
/// AR_Available, will be set to a (possibly empty) message
|
||||
/// describing why the declaration has not been introduced, is
|
||||
/// deprecated, or is unavailable.
|
||||
AvailabilityResult getAvailability(std::string *Message = 0) const;
|
||||
/// The PCH level of a declaration describes where the declaration originated
|
||||
/// from. A PCH level of 0 indicates that the declaration was not from a
|
||||
/// precompiled header. A PCH level of 1 indicates that the declaration was
|
||||
/// from a top-level precompiled header; 2 indicates that the declaration
|
||||
/// comes from a precompiled header on which the top-level precompiled header
|
||||
/// depends, and so on.
|
||||
unsigned getPCHLevel() const { return PCHLevel; }
|
||||
|
||||
/// \brief Determine whether this declaration is marked 'deprecated'.
|
||||
///
|
||||
/// \param Message If non-NULL and the declaration is deprecated,
|
||||
/// this will be set to the message describing why the declaration
|
||||
/// was deprecated (which may be empty).
|
||||
bool isDeprecated(std::string *Message = 0) const {
|
||||
return getAvailability(Message) == AR_Deprecated;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration is marked 'unavailable'.
|
||||
///
|
||||
/// \param Message If non-NULL and the declaration is unavailable,
|
||||
/// this will be set to the message describing why the declaration
|
||||
/// was made unavailable (which may be empty).
|
||||
bool isUnavailable(std::string *Message = 0) const {
|
||||
return getAvailability(Message) == AR_Unavailable;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this is a weak-imported symbol.
|
||||
///
|
||||
/// Weak-imported symbols are typically marked with the
|
||||
/// 'weak_import' attribute, but may also be marked with an
|
||||
/// 'availability' attribute where we're targing a platform prior to
|
||||
/// the introduction of this feature.
|
||||
bool isWeakImported() const;
|
||||
|
||||
/// \brief Determines whether this symbol can be weak-imported,
|
||||
/// e.g., whether it would be well-formed to add the weak_import
|
||||
/// attribute.
|
||||
///
|
||||
/// \param IsDefinition Set to \c true to indicate that this
|
||||
/// declaration cannot be weak-imported because it has a definition.
|
||||
bool canBeWeakImported(bool &IsDefinition) const;
|
||||
|
||||
/// \brief Determine whether this declaration came from an AST file (such as
|
||||
/// a precompiled header or module) rather than having been parsed.
|
||||
bool isFromASTFile() const { return FromASTFile; }
|
||||
/// \brief The maximum PCH level that any declaration may have.
|
||||
static const unsigned MaxPCHLevel = 3;
|
||||
|
||||
/// \brief Query whether this declaration was changed in a significant way
|
||||
/// since being loaded from an AST file.
|
||||
///
|
||||
/// In an epic violation of layering, what is "significant" is entirely
|
||||
/// up to the serialization system, but implemented in AST and Sema.
|
||||
bool isChangedSinceDeserialization() const { return ChangedAfterLoad; }
|
||||
|
||||
/// \brief Mark this declaration as having changed since deserialization, or
|
||||
/// reset the flag.
|
||||
void setChangedSinceDeserialization(bool Changed) {
|
||||
ChangedAfterLoad = Changed;
|
||||
/// \brief Set the PCH level of this declaration.
|
||||
void setPCHLevel(unsigned Level) {
|
||||
assert(Level < MaxPCHLevel && "PCH level exceeds the maximum");
|
||||
PCHLevel = Level;
|
||||
}
|
||||
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
@@ -526,13 +311,6 @@ public:
|
||||
}
|
||||
static unsigned getIdentifierNamespaceForKind(Kind DK);
|
||||
|
||||
bool hasTagIdentifierNamespace() const {
|
||||
return isTagIdentifierNamespace(getIdentifierNamespace());
|
||||
}
|
||||
static bool isTagIdentifierNamespace(unsigned NS) {
|
||||
// TagDecls have Tag and Type set and may also have TagFriend.
|
||||
return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type);
|
||||
}
|
||||
|
||||
/// getLexicalDeclContext - The declaration context where this Decl was
|
||||
/// lexically declared (LexicalDC). May be different from
|
||||
@@ -563,21 +341,11 @@ public:
|
||||
|
||||
void setLexicalDeclContext(DeclContext *DC);
|
||||
|
||||
/// isDefinedOutsideFunctionOrMethod - This predicate returns true if this
|
||||
/// scoped decl is defined outside the current function or method. This is
|
||||
/// roughly global variables and functions, but also handles enums (which
|
||||
/// could be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const {
|
||||
return getParentFunctionOrMethod() == 0;
|
||||
}
|
||||
|
||||
/// \brief If this decl is defined inside a function/method/block it returns
|
||||
/// the corresponding DeclContext, otherwise it returns null.
|
||||
const DeclContext *getParentFunctionOrMethod() const;
|
||||
DeclContext *getParentFunctionOrMethod() {
|
||||
return const_cast<DeclContext*>(
|
||||
const_cast<const Decl*>(this)->getParentFunctionOrMethod());
|
||||
}
|
||||
// isDefinedOutsideFunctionOrMethod - This predicate returns true if this
|
||||
// scoped decl is defined outside the current function or method. This is
|
||||
// roughly global variables and functions, but also handles enums (which could
|
||||
// be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const;
|
||||
|
||||
/// \brief Retrieves the "canonical" declaration of the given declaration.
|
||||
virtual Decl *getCanonicalDecl() { return this; }
|
||||
@@ -650,16 +418,15 @@ public:
|
||||
/// top-level Stmt* of that body. Otherwise this method returns null.
|
||||
virtual Stmt* getBody() const { return 0; }
|
||||
|
||||
/// \brief Returns true if this Decl represents a declaration for a body of
|
||||
/// code, such as a function or method definition.
|
||||
virtual bool hasBody() const { return getBody() != 0; }
|
||||
/// getCompoundBody - Returns getBody(), dyn_casted to a CompoundStmt.
|
||||
CompoundStmt* getCompoundBody() const;
|
||||
|
||||
/// getBodyRBrace - Gets the right brace of the body, if a body exists.
|
||||
/// This works whether the body is a CompoundStmt or a CXXTryStmt.
|
||||
SourceLocation getBodyRBrace() const;
|
||||
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void add(Kind k);
|
||||
static void addDeclKind(Kind k);
|
||||
static bool CollectingStats(bool Enable = false);
|
||||
static void PrintStats();
|
||||
|
||||
@@ -671,12 +438,6 @@ public:
|
||||
/// template parameter pack.
|
||||
bool isTemplateParameterPack() const;
|
||||
|
||||
/// \brief Whether this declaration is a parameter pack.
|
||||
bool isParameterPack() const;
|
||||
|
||||
/// \brief returns true if this declaration is a template
|
||||
bool isTemplateDecl() const;
|
||||
|
||||
/// \brief Whether this declaration is a function or function template.
|
||||
bool isFunctionOrFunctionTemplate() const;
|
||||
|
||||
@@ -689,23 +450,15 @@ public:
|
||||
/// same entity may not (and probably don't) share this property.
|
||||
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
|
||||
unsigned OldNS = IdentifierNamespace;
|
||||
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
|
||||
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
|
||||
"namespace includes neither ordinary nor tag");
|
||||
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
|
||||
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
|
||||
"namespace includes other than ordinary or tag");
|
||||
assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
|
||||
OldNS == (IDNS_Tag | IDNS_Ordinary))
|
||||
&& "unsupported namespace for undeclared friend");
|
||||
if (!PreviouslyDeclared) IdentifierNamespace = 0;
|
||||
|
||||
IdentifierNamespace = 0;
|
||||
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
|
||||
if (OldNS == IDNS_Tag)
|
||||
IdentifierNamespace |= IDNS_TagFriend;
|
||||
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type;
|
||||
}
|
||||
|
||||
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
|
||||
else
|
||||
IdentifierNamespace |= IDNS_OrdinaryFriend;
|
||||
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
|
||||
}
|
||||
}
|
||||
|
||||
enum FriendObjectKind {
|
||||
@@ -726,36 +479,26 @@ public:
|
||||
FOK_Declared : FOK_Undeclared);
|
||||
}
|
||||
|
||||
/// Specifies that this declaration is a C++ overloaded non-member.
|
||||
void setNonMemberOperator() {
|
||||
assert(getKind() == Function || getKind() == FunctionTemplate);
|
||||
assert((IdentifierNamespace & IDNS_Ordinary) &&
|
||||
"visible non-member operators should be in ordinary namespace");
|
||||
IdentifierNamespace |= IDNS_NonMemberOperator;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
static bool classofKind(Kind K) { return true; }
|
||||
static DeclContext *castToDeclContext(const Decl *);
|
||||
static Decl *castFromDeclContext(const DeclContext *);
|
||||
|
||||
void print(raw_ostream &Out, unsigned Indentation = 0,
|
||||
bool PrintInstantiation = false) const;
|
||||
void print(raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0, bool PrintInstantiation = false) const;
|
||||
/// Destroy - Call destructors and release memory.
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
void print(llvm::raw_ostream &Out, unsigned Indentation = 0) const;
|
||||
void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0) const;
|
||||
static void printGroup(Decl** Begin, unsigned NumDecls,
|
||||
raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
llvm::raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
void dump() const;
|
||||
void dumpXML() const;
|
||||
void dumpXML(raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
const Attr *getAttrsImpl() const;
|
||||
|
||||
protected:
|
||||
ASTMutationListener *getASTMutationListener() const;
|
||||
};
|
||||
|
||||
/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when
|
||||
@@ -770,32 +513,9 @@ public:
|
||||
SourceManager &sm, const char *Msg)
|
||||
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
|
||||
|
||||
virtual void print(raw_ostream &OS) const;
|
||||
virtual void print(llvm::raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
class DeclContextLookupResult
|
||||
: public std::pair<NamedDecl**,NamedDecl**> {
|
||||
public:
|
||||
DeclContextLookupResult(NamedDecl **I, NamedDecl **E)
|
||||
: std::pair<NamedDecl**,NamedDecl**>(I, E) {}
|
||||
DeclContextLookupResult()
|
||||
: std::pair<NamedDecl**,NamedDecl**>() {}
|
||||
|
||||
using std::pair<NamedDecl**,NamedDecl**>::operator=;
|
||||
};
|
||||
|
||||
class DeclContextLookupConstResult
|
||||
: public std::pair<NamedDecl*const*, NamedDecl*const*> {
|
||||
public:
|
||||
DeclContextLookupConstResult(std::pair<NamedDecl**,NamedDecl**> R)
|
||||
: std::pair<NamedDecl*const*, NamedDecl*const*>(R) {}
|
||||
DeclContextLookupConstResult(NamedDecl * const *I, NamedDecl * const *E)
|
||||
: std::pair<NamedDecl*const*, NamedDecl*const*>(I, E) {}
|
||||
DeclContextLookupConstResult()
|
||||
: std::pair<NamedDecl*const*, NamedDecl*const*>() {}
|
||||
|
||||
using std::pair<NamedDecl*const*,NamedDecl*const*>::operator=;
|
||||
};
|
||||
|
||||
/// DeclContext - This is used only as base class of specific decl types that
|
||||
/// can act as declaration contexts. These decls are (only the top classes
|
||||
@@ -812,24 +532,23 @@ public:
|
||||
///
|
||||
class DeclContext {
|
||||
/// DeclKind - This indicates which class this is.
|
||||
unsigned DeclKind : 8;
|
||||
Decl::Kind DeclKind : 8;
|
||||
|
||||
/// \brief Whether this declaration context also has some external
|
||||
/// storage that contains additional declarations that are lexically
|
||||
/// part of this context.
|
||||
mutable unsigned ExternalLexicalStorage : 1;
|
||||
mutable bool ExternalLexicalStorage : 1;
|
||||
|
||||
/// \brief Whether this declaration context also has some external
|
||||
/// storage that contains additional declarations that are visible
|
||||
/// in this context.
|
||||
mutable unsigned ExternalVisibleStorage : 1;
|
||||
mutable bool ExternalVisibleStorage : 1;
|
||||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context (or a DependentStoredDeclsMap if this is a
|
||||
/// dependent context).
|
||||
mutable StoredDeclsMap *LookupPtr;
|
||||
/// within this context, which is a DenseMap<DeclarationName,
|
||||
/// StoredDeclsList>.
|
||||
mutable void* LookupPtr;
|
||||
|
||||
protected:
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
/// context.
|
||||
mutable Decl *FirstDecl;
|
||||
@@ -840,24 +559,19 @@ protected:
|
||||
/// another pointer.
|
||||
mutable Decl *LastDecl;
|
||||
|
||||
friend class ExternalASTSource;
|
||||
|
||||
/// \brief Build up a chain of declarations.
|
||||
///
|
||||
/// \returns the first/last pair of declarations.
|
||||
static std::pair<Decl *, Decl *>
|
||||
BuildDeclChain(const SmallVectorImpl<Decl*> &Decls, bool FieldsAlreadyLoaded);
|
||||
|
||||
protected:
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
|
||||
LastDecl(0) { }
|
||||
|
||||
void DestroyDecls(ASTContext &C);
|
||||
|
||||
public:
|
||||
~DeclContext();
|
||||
|
||||
Decl::Kind getDeclKind() const {
|
||||
return static_cast<Decl::Kind>(DeclKind);
|
||||
return DeclKind;
|
||||
}
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
@@ -895,29 +609,13 @@ public:
|
||||
return cast<Decl>(this)->getASTContext();
|
||||
}
|
||||
|
||||
bool isClosure() const {
|
||||
return DeclKind == Decl::Block;
|
||||
}
|
||||
|
||||
bool isObjCContainer() const {
|
||||
switch (DeclKind) {
|
||||
case Decl::ObjCCategory:
|
||||
case Decl::ObjCCategoryImpl:
|
||||
case Decl::ObjCImplementation:
|
||||
case Decl::ObjCInterface:
|
||||
case Decl::ObjCProtocol:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isFunctionOrMethod() const {
|
||||
switch (DeclKind) {
|
||||
case Decl::Block:
|
||||
case Decl::ObjCMethod:
|
||||
return true;
|
||||
default:
|
||||
return DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction;
|
||||
return DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,15 +628,13 @@ public:
|
||||
}
|
||||
|
||||
bool isRecord() const {
|
||||
return DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord;
|
||||
return DeclKind >= Decl::RecordFirst && DeclKind <= Decl::RecordLast;
|
||||
}
|
||||
|
||||
bool isNamespace() const {
|
||||
return DeclKind == Decl::Namespace;
|
||||
}
|
||||
|
||||
bool isInlineNamespace() const;
|
||||
|
||||
/// \brief Determines whether this context is dependent on a
|
||||
/// template parameter.
|
||||
bool isDependentContext() const;
|
||||
@@ -957,22 +653,19 @@ public:
|
||||
/// Here, E is a transparent context, so its enumerator (Val1) will
|
||||
/// appear (semantically) that it is in the same context of E.
|
||||
/// Examples of transparent contexts include: enumerations (except for
|
||||
/// C++0x scoped enums), and C++ linkage specifications.
|
||||
/// C++0x scoped enums), C++ linkage specifications, and C++0x
|
||||
/// inline namespaces.
|
||||
bool isTransparentContext() const;
|
||||
|
||||
/// \brief Determines whether this context is, or is nested within,
|
||||
/// a C++ extern "C" linkage spec.
|
||||
bool isExternCContext() const;
|
||||
|
||||
/// \brief Determine whether this declaration context is equivalent
|
||||
/// to the declaration context DC.
|
||||
bool Equals(const DeclContext *DC) const {
|
||||
return DC && this->getPrimaryContext() == DC->getPrimaryContext();
|
||||
bool Equals(DeclContext *DC) {
|
||||
return this->getPrimaryContext() == DC->getPrimaryContext();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration context encloses the
|
||||
/// declaration context DC.
|
||||
bool Encloses(const DeclContext *DC) const;
|
||||
bool Encloses(DeclContext *DC);
|
||||
|
||||
/// getPrimaryContext - There may be many different
|
||||
/// declarations of the same entity (including forward declarations
|
||||
@@ -981,16 +674,14 @@ public:
|
||||
/// "primary" DeclContext structure, which will contain the
|
||||
/// information needed to perform name lookup into this context.
|
||||
DeclContext *getPrimaryContext();
|
||||
const DeclContext *getPrimaryContext() const {
|
||||
return const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
}
|
||||
|
||||
/// getRedeclContext - Retrieve the context in which an entity conflicts with
|
||||
/// other entities of the same name, or where it is a redeclaration if the
|
||||
/// two entities are compatible. This skips through transparent contexts.
|
||||
DeclContext *getRedeclContext();
|
||||
const DeclContext *getRedeclContext() const {
|
||||
return const_cast<DeclContext *>(this)->getRedeclContext();
|
||||
/// getLookupContext - Retrieve the innermost non-transparent
|
||||
/// context of this context, which corresponds to the innermost
|
||||
/// location from which name lookup can find the entities in this
|
||||
/// context.
|
||||
DeclContext *getLookupContext();
|
||||
const DeclContext *getLookupContext() const {
|
||||
return const_cast<DeclContext *>(this)->getLookupContext();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the nearest enclosing namespace context.
|
||||
@@ -999,14 +690,6 @@ public:
|
||||
return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext();
|
||||
}
|
||||
|
||||
/// \brief Test if this context is part of the enclosing namespace set of
|
||||
/// the context NS, as defined in C++0x [namespace.def]p9. If either context
|
||||
/// isn't a namespace, this is equivalent to Equals().
|
||||
///
|
||||
/// The enclosing namespace set of a namespace is the namespace and, if it is
|
||||
/// inline, its enclosing namespace, recursively.
|
||||
bool InEnclosingNamespaceSetOf(const DeclContext *NS) const;
|
||||
|
||||
/// getNextContext - If this is a DeclContext that may have other
|
||||
/// DeclContexts that are semantically connected but syntactically
|
||||
/// different, such as C++ namespaces, this routine retrieves the
|
||||
@@ -1070,12 +753,6 @@ public:
|
||||
decl_iterator decls_end() const;
|
||||
bool decls_empty() const;
|
||||
|
||||
/// noload_decls_begin/end - Iterate over the declarations stored in this
|
||||
/// context that are currently loaded; don't attempt to retrieve anything
|
||||
/// from an external source.
|
||||
decl_iterator noload_decls_begin() const;
|
||||
decl_iterator noload_decls_end() const;
|
||||
|
||||
/// specific_decl_iterator - Iterates over a subrange of
|
||||
/// declarations stored in a DeclContext, providing only those that
|
||||
/// are of type SpecificDecl (or a class derived from it). This
|
||||
@@ -1251,8 +928,9 @@ public:
|
||||
/// access to the results of lookup up a name within this context.
|
||||
typedef NamedDecl * const * lookup_const_iterator;
|
||||
|
||||
typedef DeclContextLookupResult lookup_result;
|
||||
typedef DeclContextLookupConstResult lookup_const_result;
|
||||
typedef std::pair<lookup_iterator, lookup_iterator> lookup_result;
|
||||
typedef std::pair<lookup_const_iterator, lookup_const_iterator>
|
||||
lookup_const_result;
|
||||
|
||||
/// lookup - Find the declarations (if any) with the given Name in
|
||||
/// this context. Returns a range of iterators that contains all of
|
||||
@@ -1262,15 +940,6 @@ public:
|
||||
lookup_result lookup(DeclarationName Name);
|
||||
lookup_const_result lookup(DeclarationName Name) const;
|
||||
|
||||
/// \brief A simplistic name lookup mechanism that performs name lookup
|
||||
/// into this declaration context without consulting the external source.
|
||||
///
|
||||
/// This function should almost never be used, because it subverts the
|
||||
/// usual relationship between a DeclContext and the external source.
|
||||
/// See the ASTImporter for the (few, but important) use cases.
|
||||
void localUncachedLookup(DeclarationName Name,
|
||||
llvm::SmallVectorImpl<NamedDecl *> &Results);
|
||||
|
||||
/// @brief Makes a declaration visible within this context.
|
||||
///
|
||||
/// This routine makes the declaration D visible to name lookup
|
||||
@@ -1307,15 +976,10 @@ public:
|
||||
return getUsingDirectives().second;
|
||||
}
|
||||
|
||||
// These are all defined in DependentDiagnostic.h.
|
||||
class ddiag_iterator;
|
||||
inline ddiag_iterator ddiag_begin() const;
|
||||
inline ddiag_iterator ddiag_end() const;
|
||||
|
||||
// Low-level accessors
|
||||
|
||||
/// \brief Retrieve the internal representation of the lookup structure.
|
||||
StoredDeclsMap* getLookupPtr() const { return LookupPtr; }
|
||||
void* getLookupPtr() const { return LookupPtr; }
|
||||
|
||||
/// \brief Whether this DeclContext has external storage containing
|
||||
/// additional declarations that are lexically in this context.
|
||||
@@ -1337,26 +1001,17 @@ public:
|
||||
ExternalVisibleStorage = ES;
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given declaration is stored in the list of
|
||||
/// declarations lexically within this context.
|
||||
bool isDeclInLexicalTraversal(const Decl *D) const {
|
||||
return D && (D->NextDeclInContext || D == FirstDecl || D == LastDecl);
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D);
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
#define DECL(NAME, BASE)
|
||||
#define DECL_CONTEXT(NAME) \
|
||||
static bool classof(const NAME##Decl *D) { return true; }
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
#define DECL_CONTEXT(Name) \
|
||||
static bool classof(const Name##Decl *D) { return true; }
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
|
||||
void dumpDeclContext() const;
|
||||
|
||||
private:
|
||||
void LoadLexicalDeclsFromExternalStorage() const;
|
||||
|
||||
friend class DependentDiagnostic;
|
||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||
void LoadVisibleDeclsFromExternalStorage() const;
|
||||
|
||||
void buildLookup(DeclContext *DCtx);
|
||||
void makeDeclVisibleInContextImpl(NamedDecl *D);
|
||||
@@ -1367,6 +1022,7 @@ inline bool Decl::isTemplateParameter() const {
|
||||
getKind() == TemplateTemplateParm;
|
||||
}
|
||||
|
||||
|
||||
// Specialization selected when ToTy is not a known subclass of DeclContext.
|
||||
template <class ToTy,
|
||||
bool IsKnownSubtype = ::llvm::is_base_of< DeclContext, ToTy>::value>
|
||||
@@ -1398,12 +1054,17 @@ struct cast_convert_decl_context<ToTy, true> {
|
||||
namespace llvm {
|
||||
|
||||
/// isa<T>(DeclContext*)
|
||||
template <typename To>
|
||||
struct isa_impl<To, ::clang::DeclContext> {
|
||||
template<class ToTy>
|
||||
struct isa_impl_wrap<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {
|
||||
static bool doit(const ::clang::DeclContext &Val) {
|
||||
return To::classofKind(Val.getDeclKind());
|
||||
return ToTy::classofKind(Val.getDeclKind());
|
||||
}
|
||||
};
|
||||
template<class ToTy>
|
||||
struct isa_impl_wrap<ToTy, ::clang::DeclContext, ::clang::DeclContext>
|
||||
: public isa_impl_wrap<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {};
|
||||
|
||||
/// cast<T>(DeclContext*)
|
||||
template<class ToTy>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,59 +24,111 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
class DependentDiagnostic;
|
||||
|
||||
/// StoredDeclsList - This is an array of decls optimized a common case of only
|
||||
/// containing one entry.
|
||||
struct StoredDeclsList {
|
||||
/// The kind of data encoded in this list.
|
||||
enum DataKind {
|
||||
/// \brief The data is a NamedDecl*.
|
||||
DK_Decl = 0,
|
||||
/// \brief The data is a declaration ID (an unsigned value),
|
||||
/// shifted left by 2 bits.
|
||||
DK_DeclID = 1,
|
||||
/// \brief The data is a pointer to a vector (of type VectorTy)
|
||||
/// that contains declarations.
|
||||
DK_Decl_Vector = 2,
|
||||
/// \brief The data is a pointer to a vector (of type VectorTy)
|
||||
/// that contains declaration ID.
|
||||
DK_ID_Vector = 3
|
||||
};
|
||||
|
||||
/// DeclsTy - When in vector form, this is what the Data pointer points to.
|
||||
typedef SmallVector<NamedDecl *, 4> DeclsTy;
|
||||
/// VectorTy - When in vector form, this is what the Data pointer points to.
|
||||
typedef llvm::SmallVector<uintptr_t, 4> VectorTy;
|
||||
|
||||
/// \brief The stored data, which will be either a pointer to a NamedDecl,
|
||||
/// or a pointer to a vector.
|
||||
llvm::PointerUnion<NamedDecl *, DeclsTy *> Data;
|
||||
/// \brief The stored data, which will be either a declaration ID, a
|
||||
/// pointer to a NamedDecl, or a pointer to a vector.
|
||||
uintptr_t Data;
|
||||
|
||||
public:
|
||||
StoredDeclsList() {}
|
||||
StoredDeclsList() : Data(0) {}
|
||||
|
||||
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
|
||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||
Data = new DeclsTy(*RHSVec);
|
||||
if (VectorTy *RHSVec = RHS.getAsVector()) {
|
||||
VectorTy *New = new VectorTy(*RHSVec);
|
||||
Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
|
||||
}
|
||||
}
|
||||
|
||||
~StoredDeclsList() {
|
||||
// If this is a vector-form, free the vector.
|
||||
if (DeclsTy *Vector = getAsVector())
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
}
|
||||
|
||||
StoredDeclsList &operator=(const StoredDeclsList &RHS) {
|
||||
if (DeclsTy *Vector = getAsVector())
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
Data = RHS.Data;
|
||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||
Data = new DeclsTy(*RHSVec);
|
||||
if (VectorTy *RHSVec = RHS.getAsVector()) {
|
||||
VectorTy *New = new VectorTy(*RHSVec);
|
||||
Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isNull() const { return Data.isNull(); }
|
||||
bool isNull() const { return (Data & ~0x03) == 0; }
|
||||
|
||||
NamedDecl *getAsDecl() const {
|
||||
return Data.dyn_cast<NamedDecl *>();
|
||||
if ((Data & 0x03) != DK_Decl)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<NamedDecl *>(Data & ~0x03);
|
||||
}
|
||||
|
||||
DeclsTy *getAsVector() const {
|
||||
return Data.dyn_cast<DeclsTy *>();
|
||||
VectorTy *getAsVector() const {
|
||||
if ((Data & 0x03) != DK_ID_Vector && (Data & 0x03) != DK_Decl_Vector)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<VectorTy *>(Data & ~0x03);
|
||||
}
|
||||
|
||||
void setOnlyValue(NamedDecl *ND) {
|
||||
assert(!getAsVector() && "Not inline");
|
||||
Data = ND;
|
||||
// Make sure that Data is a plain NamedDecl* so we can use its address
|
||||
// at getLookupResult.
|
||||
assert(*(NamedDecl **)&Data == ND &&
|
||||
"PointerUnion mangles the NamedDecl pointer!");
|
||||
Data = reinterpret_cast<uintptr_t>(ND);
|
||||
}
|
||||
|
||||
void setFromDeclIDs(const llvm::SmallVectorImpl<unsigned> &Vec) {
|
||||
if (Vec.size() > 1) {
|
||||
VectorTy *Vector = getAsVector();
|
||||
if (!Vector) {
|
||||
Vector = new VectorTy;
|
||||
Data = reinterpret_cast<uintptr_t>(Vector) | DK_ID_Vector;
|
||||
}
|
||||
|
||||
Vector->resize(Vec.size());
|
||||
std::copy(Vec.begin(), Vec.end(), Vector->begin());
|
||||
return;
|
||||
}
|
||||
|
||||
if (VectorTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
|
||||
if (Vec.empty())
|
||||
Data = 0;
|
||||
else
|
||||
Data = (Vec[0] << 2) | DK_DeclID;
|
||||
}
|
||||
|
||||
/// \brief Force the stored declarations list to contain actual
|
||||
/// declarations.
|
||||
///
|
||||
/// This routine will resolve any declaration IDs for declarations
|
||||
/// that may not yet have been loaded from external storage.
|
||||
void materializeDecls(ASTContext &Context);
|
||||
|
||||
bool hasDeclarationIDs() const {
|
||||
DataKind DK = (DataKind)(Data & 0x03);
|
||||
return DK == DK_DeclID || DK == DK_ID_Vector;
|
||||
}
|
||||
|
||||
void remove(NamedDecl *D) {
|
||||
@@ -84,25 +136,28 @@ public:
|
||||
if (NamedDecl *Singleton = getAsDecl()) {
|
||||
assert(Singleton == D && "list is different singleton");
|
||||
(void)Singleton;
|
||||
Data = (NamedDecl *)0;
|
||||
Data = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
DeclsTy::iterator I = std::find(Vec.begin(), Vec.end(), D);
|
||||
VectorTy &Vec = *getAsVector();
|
||||
VectorTy::iterator I = std::find(Vec.begin(), Vec.end(),
|
||||
reinterpret_cast<uintptr_t>(D));
|
||||
assert(I != Vec.end() && "list does not contain decl");
|
||||
Vec.erase(I);
|
||||
|
||||
assert(std::find(Vec.begin(), Vec.end(), D)
|
||||
assert(std::find(Vec.begin(), Vec.end(), reinterpret_cast<uintptr_t>(D))
|
||||
== Vec.end() && "list still contains decl");
|
||||
}
|
||||
|
||||
/// getLookupResult - Return an array of all the decls that this list
|
||||
/// represents.
|
||||
DeclContext::lookup_result getLookupResult() {
|
||||
DeclContext::lookup_result getLookupResult(ASTContext &Context) {
|
||||
if (isNull())
|
||||
return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
|
||||
DeclContext::lookup_iterator(0));
|
||||
return DeclContext::lookup_result(0, 0);
|
||||
|
||||
if (hasDeclarationIDs())
|
||||
materializeDecls(Context);
|
||||
|
||||
// If we have a single NamedDecl, return it.
|
||||
if (getAsDecl()) {
|
||||
@@ -114,15 +169,19 @@ public:
|
||||
}
|
||||
|
||||
assert(getAsVector() && "Must have a vector at this point");
|
||||
DeclsTy &Vector = *getAsVector();
|
||||
VectorTy &Vector = *getAsVector();
|
||||
|
||||
// Otherwise, we have a range result.
|
||||
return DeclContext::lookup_result(&Vector[0], &Vector[0]+Vector.size());
|
||||
return DeclContext::lookup_result((NamedDecl **)&Vector[0],
|
||||
(NamedDecl **)&Vector[0]+Vector.size());
|
||||
}
|
||||
|
||||
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
|
||||
/// replace the old one with D and return true. Otherwise return false.
|
||||
bool HandleRedeclaration(NamedDecl *D) {
|
||||
bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) {
|
||||
if (hasDeclarationIDs())
|
||||
materializeDecls(Context);
|
||||
|
||||
// Most decls only have one entry in their list, special case it.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
if (!D->declarationReplaces(OldD))
|
||||
@@ -132,12 +191,12 @@ public:
|
||||
}
|
||||
|
||||
// Determine if this declaration is actually a redeclaration.
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
for (DeclsTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
|
||||
VectorTy &Vec = *getAsVector();
|
||||
for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
|
||||
OD != ODEnd; ++OD) {
|
||||
NamedDecl *OldD = *OD;
|
||||
NamedDecl *OldD = reinterpret_cast<NamedDecl *>(*OD);
|
||||
if (D->declarationReplaces(OldD)) {
|
||||
*OD = D;
|
||||
*OD = reinterpret_cast<uintptr_t>(D);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -149,15 +208,17 @@ public:
|
||||
/// not a redeclaration to merge it into the appropriate place in our list.
|
||||
///
|
||||
void AddSubsequentDecl(NamedDecl *D) {
|
||||
assert(!hasDeclarationIDs() && "Must materialize before adding decls");
|
||||
|
||||
// If this is the second decl added to the list, convert this to vector
|
||||
// form.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
DeclsTy *VT = new DeclsTy();
|
||||
VT->push_back(OldD);
|
||||
Data = VT;
|
||||
VectorTy *VT = new VectorTy();
|
||||
VT->push_back(reinterpret_cast<uintptr_t>(OldD));
|
||||
Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector;
|
||||
}
|
||||
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
VectorTy &Vec = *getAsVector();
|
||||
|
||||
// Using directives end up in a special entry which contains only
|
||||
// other using directives, so all this logic is wasted for them.
|
||||
@@ -167,56 +228,38 @@ public:
|
||||
// Tag declarations always go at the end of the list so that an
|
||||
// iterator which points at the first tag will start a span of
|
||||
// decls that only contains tags.
|
||||
if (D->hasTagIdentifierNamespace())
|
||||
Vec.push_back(D);
|
||||
if (D->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
Vec.push_back(reinterpret_cast<uintptr_t>(D));
|
||||
|
||||
// Resolved using declarations go at the front of the list so that
|
||||
// they won't show up in other lookup results. Unresolved using
|
||||
// declarations (which are always in IDNS_Using | IDNS_Ordinary)
|
||||
// follow that so that the using declarations will be contiguous.
|
||||
else if (D->getIdentifierNamespace() & Decl::IDNS_Using) {
|
||||
DeclsTy::iterator I = Vec.begin();
|
||||
VectorTy::iterator I = Vec.begin();
|
||||
if (D->getIdentifierNamespace() != Decl::IDNS_Using) {
|
||||
while (I != Vec.end() &&
|
||||
(*I)->getIdentifierNamespace() == Decl::IDNS_Using)
|
||||
reinterpret_cast<NamedDecl *>(*I)
|
||||
->getIdentifierNamespace() == Decl::IDNS_Using)
|
||||
++I;
|
||||
}
|
||||
Vec.insert(I, D);
|
||||
Vec.insert(I, reinterpret_cast<uintptr_t>(D));
|
||||
|
||||
// All other declarations go at the end of the list, but before any
|
||||
// tag declarations. But we can be clever about tag declarations
|
||||
// because there can only ever be one in a scope.
|
||||
} else if (Vec.back()->hasTagIdentifierNamespace()) {
|
||||
NamedDecl *TagD = Vec.back();
|
||||
Vec.back() = D;
|
||||
} else if (reinterpret_cast<NamedDecl *>(Vec.back())
|
||||
->getIdentifierNamespace() == Decl::IDNS_Tag) {
|
||||
uintptr_t TagD = Vec.back();
|
||||
Vec.back() = reinterpret_cast<uintptr_t>(D);
|
||||
Vec.push_back(TagD);
|
||||
} else
|
||||
Vec.push_back(D);
|
||||
Vec.push_back(reinterpret_cast<uintptr_t>(D));
|
||||
}
|
||||
};
|
||||
|
||||
class StoredDeclsMap
|
||||
: public llvm::DenseMap<DeclarationName, StoredDeclsList> {
|
||||
typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
|
||||
|
||||
public:
|
||||
static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
|
||||
|
||||
private:
|
||||
friend class ASTContext; // walks the chain deleting these
|
||||
friend class DeclContext;
|
||||
llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
|
||||
};
|
||||
|
||||
class DependentStoredDeclsMap : public StoredDeclsMap {
|
||||
public:
|
||||
DependentStoredDeclsMap() : FirstDiagnostic(0) {}
|
||||
|
||||
private:
|
||||
friend class DependentDiagnostic;
|
||||
friend class DeclContext; // iterates over diagnostics
|
||||
|
||||
DependentDiagnostic *FirstDiagnostic;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
//===-- DeclFriend.h - Classes for C++ friend declarations -*- 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 section of the AST representing C++ friend
|
||||
// declarations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLFRIEND_H
|
||||
#define LLVM_CLANG_AST_DECLFRIEND_H
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// FriendDecl - Represents the declaration of a friend entity,
|
||||
/// which can be a function, a type, or a templated function or type.
|
||||
// For example:
|
||||
///
|
||||
/// @code
|
||||
/// template <typename T> class A {
|
||||
/// friend int foo(T);
|
||||
/// friend class B;
|
||||
/// friend T; // only in C++0x
|
||||
/// template <typename U> friend class C;
|
||||
/// template <typename U> friend A& operator+=(A&, const U&) { ... }
|
||||
/// };
|
||||
/// @endcode
|
||||
///
|
||||
/// The semantic context of a friend decl is its declaring class.
|
||||
class FriendDecl : public Decl {
|
||||
public:
|
||||
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
|
||||
|
||||
private:
|
||||
// The declaration that's a friend of this class.
|
||||
FriendUnion Friend;
|
||||
|
||||
// A pointer to the next friend in the sequence.
|
||||
LazyDeclPtr NextFriend;
|
||||
|
||||
// Location of the 'friend' specifier.
|
||||
SourceLocation FriendLoc;
|
||||
|
||||
/// True if this 'friend' declaration is unsupported. Eventually we
|
||||
/// will support every possible friend declaration, but for now we
|
||||
/// silently ignore some and set this flag to authorize all access.
|
||||
bool UnsupportedFriend;
|
||||
|
||||
friend class CXXRecordDecl::friend_iterator;
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
|
||||
SourceLocation FriendL)
|
||||
: Decl(Decl::Friend, DC, L),
|
||||
Friend(Friend),
|
||||
NextFriend(),
|
||||
FriendLoc(FriendL),
|
||||
UnsupportedFriend(false) {
|
||||
}
|
||||
|
||||
explicit FriendDecl(EmptyShell Empty)
|
||||
: Decl(Decl::Friend, Empty), NextFriend() { }
|
||||
|
||||
FriendDecl *getNextFriend() {
|
||||
return cast_or_null<FriendDecl>(
|
||||
NextFriend.get(getASTContext().getExternalSource()));
|
||||
}
|
||||
|
||||
public:
|
||||
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, FriendUnion Friend_,
|
||||
SourceLocation FriendL);
|
||||
static FriendDecl *Create(ASTContext &C, EmptyShell Empty);
|
||||
|
||||
/// If this friend declaration names an (untemplated but possibly
|
||||
/// dependent) type, return the type; otherwise return null. This
|
||||
/// is used for elaborated-type-specifiers and, in C++0x, for
|
||||
/// arbitrary friend type declarations.
|
||||
TypeSourceInfo *getFriendType() const {
|
||||
return Friend.dyn_cast<TypeSourceInfo*>();
|
||||
}
|
||||
|
||||
/// If this friend declaration doesn't name a type, return the inner
|
||||
/// declaration.
|
||||
NamedDecl *getFriendDecl() const {
|
||||
return Friend.dyn_cast<NamedDecl*>();
|
||||
}
|
||||
|
||||
/// Retrieves the location of the 'friend' keyword.
|
||||
SourceLocation getFriendLoc() const {
|
||||
return FriendLoc;
|
||||
}
|
||||
|
||||
/// Retrieves the source range for the friend declaration.
|
||||
SourceRange getSourceRange() const {
|
||||
/* FIXME: consider the case of templates wrt start of range. */
|
||||
if (NamedDecl *ND = getFriendDecl())
|
||||
return SourceRange(getFriendLoc(), ND->getLocEnd());
|
||||
else if (TypeSourceInfo *TInfo = getFriendType())
|
||||
return SourceRange(getFriendLoc(), TInfo->getTypeLoc().getEndLoc());
|
||||
else
|
||||
return SourceRange(getFriendLoc(), getLocation());
|
||||
}
|
||||
|
||||
/// Determines if this friend kind is unsupported.
|
||||
bool isUnsupportedFriend() const {
|
||||
return UnsupportedFriend;
|
||||
}
|
||||
void setUnsupportedFriend(bool Unsupported) {
|
||||
UnsupportedFriend = Unsupported;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const FriendDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Decl::Friend; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// An iterator over the friend declarations of a class.
|
||||
class CXXRecordDecl::friend_iterator {
|
||||
FriendDecl *Ptr;
|
||||
|
||||
friend class CXXRecordDecl;
|
||||
explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {}
|
||||
public:
|
||||
friend_iterator() {}
|
||||
|
||||
typedef FriendDecl *value_type;
|
||||
typedef FriendDecl *reference;
|
||||
typedef FriendDecl *pointer;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
reference operator*() const { return Ptr; }
|
||||
|
||||
friend_iterator &operator++() {
|
||||
assert(Ptr && "attempt to increment past end of friend list");
|
||||
Ptr = Ptr->getNextFriend();
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend_iterator operator++(int) {
|
||||
friend_iterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const friend_iterator &Other) const {
|
||||
return Ptr == Other.Ptr;
|
||||
}
|
||||
|
||||
bool operator!=(const friend_iterator &Other) const {
|
||||
return Ptr != Other.Ptr;
|
||||
}
|
||||
|
||||
friend_iterator &operator+=(difference_type N) {
|
||||
assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator");
|
||||
while (N--)
|
||||
++*this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend_iterator operator+(difference_type N) const {
|
||||
friend_iterator tmp = *this;
|
||||
tmp += N;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
|
||||
return friend_iterator(data().FirstFriend);
|
||||
}
|
||||
|
||||
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
|
||||
return friend_iterator(0);
|
||||
}
|
||||
|
||||
inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
|
||||
assert(FD->NextFriend == 0 && "friend already has next friend?");
|
||||
FD->NextFriend = data().FirstFriend;
|
||||
data().FirstFriend = FD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,7 +14,7 @@
|
||||
#ifndef LLVM_CLANG_AST_DECLGROUP_H
|
||||
#define LLVM_CLANG_AST_DECLGROUP_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
@@ -34,17 +34,18 @@ private:
|
||||
|
||||
public:
|
||||
static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls);
|
||||
void Destroy(ASTContext& C);
|
||||
|
||||
unsigned size() const { return NumDecls; }
|
||||
|
||||
Decl*& operator[](unsigned i) {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return ((Decl**) (this+1))[i];
|
||||
return *((Decl**) (this+1));
|
||||
}
|
||||
|
||||
Decl* const& operator[](unsigned i) const {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return ((Decl* const*) (this+1))[i];
|
||||
return *((Decl* const*) (this+1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
165
clang/include/clang/AST/DeclNodes.def
Normal file
165
clang/include/clang/AST/DeclNodes.def
Normal file
@@ -0,0 +1,165 @@
|
||||
//===-- DeclNodes.def - Metadata about Decl AST nodes -----------*- 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 declaration nodes within the AST. The
|
||||
// description of the declaration nodes uses six macros:
|
||||
//
|
||||
// DECL(Derived, Base) describes a normal declaration type Derived
|
||||
// and specifies its base class. Note that Derived should not have
|
||||
// the Decl suffix on it, while Base should.
|
||||
//
|
||||
// LAST_DECL(Derived, Base) is like DECL, but is used for the last
|
||||
// declaration in the list.
|
||||
//
|
||||
// ABSTRACT_DECL(Derived, Base) describes an abstract class that is
|
||||
// used to specify a classification of declarations. For example,
|
||||
// TagDecl is an abstract class used to describe the various kinds of
|
||||
// "tag" declarations (unions, structs, classes, enums).
|
||||
//
|
||||
// DECL_CONTEXT(Decl) specifies that Decl is a kind of declaration
|
||||
// that is also a DeclContext.
|
||||
//
|
||||
// LAST_DECL_CONTEXT(Decl) is like DECL_CONTEXT, but is used for the
|
||||
// last declaration context.
|
||||
//
|
||||
// DECL_RANGE(CommonBase, Start, End) specifies a range of
|
||||
// declaration values that have a common (potentially indirect) base
|
||||
// class.
|
||||
//
|
||||
// LAST_DECL_RANGE(CommonBase, Start, End) is like DECL_RANGE, but is
|
||||
// used for the last declaration range.
|
||||
//
|
||||
// Note that, due to the use of ranges, the order of the these
|
||||
// declarations is significant. A declaration should be listed under
|
||||
// its base class.
|
||||
// ===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DECL
|
||||
# define DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL
|
||||
# define LAST_DECL(Derived, Base) DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef ABSTRACT_DECL
|
||||
# define ABSTRACT_DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_CONTEXT
|
||||
# define DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_CONTEXT_BASE
|
||||
# define DECL_CONTEXT_BASE(Decl) DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL_CONTEXT
|
||||
# define LAST_DECL_CONTEXT(Decl) DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_RANGE
|
||||
# define DECL_RANGE(CommonBase, Start, End)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL_RANGE
|
||||
# define LAST_DECL_RANGE(CommonBase, Start, End) \
|
||||
DECL_RANGE(CommonBase, Start, End)
|
||||
#endif
|
||||
|
||||
DECL(TranslationUnit, Decl)
|
||||
ABSTRACT_DECL(Named, Decl)
|
||||
DECL(Namespace, NamedDecl)
|
||||
DECL(UsingDirective, NamedDecl)
|
||||
DECL(NamespaceAlias, NamedDecl)
|
||||
ABSTRACT_DECL(Type, NamedDecl)
|
||||
DECL(Typedef, TypeDecl)
|
||||
DECL(UnresolvedUsingTypename, TypeDecl)
|
||||
ABSTRACT_DECL(Tag, TypeDecl)
|
||||
DECL(Enum, TagDecl)
|
||||
DECL(Record, TagDecl)
|
||||
DECL(CXXRecord, RecordDecl)
|
||||
DECL(ClassTemplateSpecialization, CXXRecordDecl)
|
||||
DECL(ClassTemplatePartialSpecialization,
|
||||
ClassTemplateSpecializationDecl)
|
||||
DECL(TemplateTypeParm, TypeDecl)
|
||||
ABSTRACT_DECL(Value, NamedDecl)
|
||||
DECL(EnumConstant, ValueDecl)
|
||||
DECL(UnresolvedUsingValue, ValueDecl)
|
||||
ABSTRACT_DECL(Declarator, ValueDecl)
|
||||
DECL(Function, DeclaratorDecl)
|
||||
DECL(CXXMethod, FunctionDecl)
|
||||
DECL(CXXConstructor, CXXMethodDecl)
|
||||
DECL(CXXDestructor, CXXMethodDecl)
|
||||
DECL(CXXConversion, CXXMethodDecl)
|
||||
DECL(Field, DeclaratorDecl)
|
||||
DECL(ObjCIvar, FieldDecl)
|
||||
DECL(ObjCAtDefsField, FieldDecl)
|
||||
DECL(Var, DeclaratorDecl)
|
||||
DECL(ImplicitParam, VarDecl)
|
||||
DECL(ParmVar, VarDecl)
|
||||
DECL(NonTypeTemplateParm, VarDecl)
|
||||
DECL(Template, NamedDecl)
|
||||
DECL(FunctionTemplate, TemplateDecl)
|
||||
DECL(ClassTemplate, TemplateDecl)
|
||||
DECL(TemplateTemplateParm, TemplateDecl)
|
||||
DECL(Using, NamedDecl)
|
||||
DECL(UsingShadow, NamedDecl)
|
||||
DECL(ObjCMethod, NamedDecl)
|
||||
DECL(ObjCContainer, NamedDecl)
|
||||
DECL(ObjCCategory, ObjCContainerDecl)
|
||||
DECL(ObjCProtocol, ObjCContainerDecl)
|
||||
DECL(ObjCInterface, ObjCContainerDecl)
|
||||
ABSTRACT_DECL(ObjCImpl, ObjCContainerDecl)
|
||||
DECL(ObjCCategoryImpl, ObjCImplDecl)
|
||||
DECL(ObjCImplementation, ObjCImplDecl)
|
||||
DECL(ObjCProperty, NamedDecl)
|
||||
DECL(ObjCCompatibleAlias, NamedDecl)
|
||||
DECL(LinkageSpec, Decl)
|
||||
DECL(ObjCPropertyImpl, Decl)
|
||||
DECL(ObjCForwardProtocol, Decl)
|
||||
DECL(ObjCClass, Decl)
|
||||
DECL(FileScopeAsm, Decl)
|
||||
DECL(Friend, Decl)
|
||||
DECL(FriendTemplate, Decl)
|
||||
DECL(StaticAssert, Decl)
|
||||
LAST_DECL(Block, Decl)
|
||||
|
||||
// Declaration contexts. DECL_CONTEXT_BASE indicates that it has subclasses.
|
||||
DECL_CONTEXT(TranslationUnit)
|
||||
DECL_CONTEXT(Namespace)
|
||||
DECL_CONTEXT(LinkageSpec)
|
||||
DECL_CONTEXT(ObjCMethod)
|
||||
DECL_CONTEXT_BASE(Tag)
|
||||
DECL_CONTEXT_BASE(Function)
|
||||
DECL_CONTEXT_BASE(ObjCContainer)
|
||||
LAST_DECL_CONTEXT(Block)
|
||||
|
||||
// Declaration ranges
|
||||
DECL_RANGE(Named, Namespace, ObjCCompatibleAlias)
|
||||
DECL_RANGE(ObjCContainer, ObjCContainer, ObjCImplementation)
|
||||
DECL_RANGE(Field, Field, ObjCAtDefsField)
|
||||
DECL_RANGE(Type, Typedef, TemplateTypeParm)
|
||||
DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization)
|
||||
DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization)
|
||||
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
|
||||
DECL_RANGE(Declarator, Function, NonTypeTemplateParm)
|
||||
DECL_RANGE(Function, Function, CXXConversion)
|
||||
DECL_RANGE(Template, Template, TemplateTemplateParm)
|
||||
DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation)
|
||||
LAST_DECL_RANGE(Var, Var, NonTypeTemplateParm)
|
||||
|
||||
#undef LAST_DECL_RANGE
|
||||
#undef DECL_RANGE
|
||||
#undef LAST_DECL_CONTEXT
|
||||
#undef DECL_CONTEXT_BASE
|
||||
#undef DECL_CONTEXT
|
||||
#undef ABSTRACT_DECL
|
||||
#undef LAST_DECL
|
||||
#undef DECL
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,6 @@
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclFriend.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
|
||||
namespace clang {
|
||||
@@ -30,19 +29,20 @@ class DeclVisitor {
|
||||
public:
|
||||
RetTy Visit(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
|
||||
#define DECL(DERIVED, BASE) \
|
||||
case Decl::DERIVED: DISPATCH(DERIVED##Decl, DERIVED##Decl);
|
||||
#define ABSTRACT_DECL(DECL)
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
default: assert(false && "Decl that isn't part of DeclNodes.def!");
|
||||
#define DECL(Derived, Base) \
|
||||
case Decl::Derived: DISPATCH(Derived##Decl, Derived##Decl);
|
||||
#define ABSTRACT_DECL(Derived, Base)
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
}
|
||||
}
|
||||
|
||||
// If the implementation chooses not to implement a certain visit
|
||||
// method, fall back to the parent.
|
||||
#define DECL(DERIVED, BASE) \
|
||||
RetTy Visit##DERIVED##Decl(DERIVED##Decl *D) { DISPATCH(BASE, BASE); }
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
#define DECL(Derived, Base) \
|
||||
RetTy Visit##Derived##Decl(Derived##Decl *D) { DISPATCH(Base, Base); }
|
||||
#define ABSTRACT_DECL(Derived, Base) DECL(Derived, Base)
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
|
||||
RetTy VisitDecl(Decl *D) { return RetTy(); }
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace clang {
|
||||
class IdentifierInfo;
|
||||
class MultiKeywordSelector;
|
||||
class UsingDirectiveDecl;
|
||||
class TypeSourceInfo;
|
||||
|
||||
/// DeclarationName - The name of a declaration. In the common case,
|
||||
/// this just stores an IdentifierInfo pointer to a normal
|
||||
@@ -199,12 +198,9 @@ public:
|
||||
/// callee in a call expression with dependent arguments.
|
||||
bool isDependentName() const;
|
||||
|
||||
/// getNameAsString - Retrieve the human-readable string for this name.
|
||||
/// getName - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
||||
/// printName - Print the human-readable name to a stream.
|
||||
void printName(raw_ostream &OS) const;
|
||||
|
||||
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
||||
/// this declaration name, or NULL if this declaration name isn't a
|
||||
/// simple identifier.
|
||||
@@ -315,16 +311,15 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
|
||||
/// retrieved using its member functions (e.g.,
|
||||
/// getCXXConstructorName).
|
||||
class DeclarationNameTable {
|
||||
const ASTContext &Ctx;
|
||||
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
|
||||
void *CXXLiteralOperatorNames; // Actually a FoldingSet<...> *
|
||||
|
||||
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
|
||||
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
|
||||
|
||||
public:
|
||||
DeclarationNameTable(const ASTContext &C);
|
||||
DeclarationNameTable();
|
||||
~DeclarationNameTable();
|
||||
|
||||
/// getIdentifier - Create a declaration name that is a simple
|
||||
@@ -336,15 +331,13 @@ public:
|
||||
/// getCXXConstructorName - Returns the name of a C++ constructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXConstructorName(CanQualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXConstructorName,
|
||||
Ty.getUnqualifiedType());
|
||||
return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXDestructorName - Returns the name of a C++ destructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXDestructorName(CanQualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXDestructorName,
|
||||
Ty.getUnqualifiedType());
|
||||
return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXConversionFunctionName - Returns the name of a C++
|
||||
@@ -368,159 +361,12 @@ public:
|
||||
DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II);
|
||||
};
|
||||
|
||||
/// DeclarationNameLoc - Additional source/type location info
|
||||
/// for a declaration name. Needs a DeclarationName in order
|
||||
/// to be interpreted correctly.
|
||||
struct DeclarationNameLoc {
|
||||
union {
|
||||
// The source location for identifier stored elsewhere.
|
||||
// struct {} Identifier;
|
||||
|
||||
// Type info for constructors, destructors and conversion functions.
|
||||
// Locations (if any) for the tilde (destructor) or operator keyword
|
||||
// (conversion) are stored elsewhere.
|
||||
struct {
|
||||
TypeSourceInfo* TInfo;
|
||||
} NamedType;
|
||||
|
||||
// The location (if any) of the operator keyword is stored elsewhere.
|
||||
struct {
|
||||
unsigned BeginOpNameLoc;
|
||||
unsigned EndOpNameLoc;
|
||||
} CXXOperatorName;
|
||||
|
||||
// The location (if any) of the operator keyword is stored elsewhere.
|
||||
struct {
|
||||
unsigned OpNameLoc;
|
||||
} CXXLiteralOperatorName;
|
||||
|
||||
// struct {} CXXUsingDirective;
|
||||
// struct {} ObjCZeroArgSelector;
|
||||
// struct {} ObjCOneArgSelector;
|
||||
// struct {} ObjCMultiArgSelector;
|
||||
};
|
||||
|
||||
DeclarationNameLoc(DeclarationName Name);
|
||||
// FIXME: this should go away once all DNLocs are properly initialized.
|
||||
DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); }
|
||||
}; // struct DeclarationNameLoc
|
||||
|
||||
|
||||
/// DeclarationNameInfo - A collector data type for bundling together
|
||||
/// a DeclarationName and the correspnding source/type location info.
|
||||
struct DeclarationNameInfo {
|
||||
private:
|
||||
/// Name - The declaration name, also encoding name kind.
|
||||
DeclarationName Name;
|
||||
/// Loc - The main source location for the declaration name.
|
||||
SourceLocation NameLoc;
|
||||
/// Info - Further source/type location info for special kinds of names.
|
||||
DeclarationNameLoc LocInfo;
|
||||
|
||||
public:
|
||||
// FIXME: remove it.
|
||||
DeclarationNameInfo() {}
|
||||
|
||||
DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc)
|
||||
: Name(Name), NameLoc(NameLoc), LocInfo(Name) {}
|
||||
|
||||
DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc,
|
||||
DeclarationNameLoc LocInfo)
|
||||
: Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {}
|
||||
|
||||
/// getName - Returns the embedded declaration name.
|
||||
DeclarationName getName() const { return Name; }
|
||||
/// setName - Sets the embedded declaration name.
|
||||
void setName(DeclarationName N) { Name = N; }
|
||||
|
||||
/// getLoc - Returns the main location of the declaration name.
|
||||
SourceLocation getLoc() const { return NameLoc; }
|
||||
/// setLoc - Sets the main location of the declaration name.
|
||||
void setLoc(SourceLocation L) { NameLoc = L; }
|
||||
|
||||
const DeclarationNameLoc &getInfo() const { return LocInfo; }
|
||||
DeclarationNameLoc &getInfo() { return LocInfo; }
|
||||
void setInfo(const DeclarationNameLoc &Info) { LocInfo = Info; }
|
||||
|
||||
/// getNamedTypeInfo - Returns the source type info associated to
|
||||
/// the name. Assumes it is a constructor, destructor or conversion.
|
||||
TypeSourceInfo *getNamedTypeInfo() const {
|
||||
assert(Name.getNameKind() == DeclarationName::CXXConstructorName ||
|
||||
Name.getNameKind() == DeclarationName::CXXDestructorName ||
|
||||
Name.getNameKind() == DeclarationName::CXXConversionFunctionName);
|
||||
return LocInfo.NamedType.TInfo;
|
||||
}
|
||||
/// setNamedTypeInfo - Sets the source type info associated to
|
||||
/// the name. Assumes it is a constructor, destructor or conversion.
|
||||
void setNamedTypeInfo(TypeSourceInfo *TInfo) {
|
||||
assert(Name.getNameKind() == DeclarationName::CXXConstructorName ||
|
||||
Name.getNameKind() == DeclarationName::CXXDestructorName ||
|
||||
Name.getNameKind() == DeclarationName::CXXConversionFunctionName);
|
||||
LocInfo.NamedType.TInfo = TInfo;
|
||||
}
|
||||
|
||||
/// getCXXOperatorNameRange - Gets the range of the operator name
|
||||
/// (without the operator keyword). Assumes it is a (non-literal) operator.
|
||||
SourceRange getCXXOperatorNameRange() const {
|
||||
assert(Name.getNameKind() == DeclarationName::CXXOperatorName);
|
||||
return SourceRange(
|
||||
SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.BeginOpNameLoc),
|
||||
SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.EndOpNameLoc)
|
||||
);
|
||||
}
|
||||
/// setCXXOperatorNameRange - Sets the range of the operator name
|
||||
/// (without the operator keyword). Assumes it is a C++ operator.
|
||||
void setCXXOperatorNameRange(SourceRange R) {
|
||||
assert(Name.getNameKind() == DeclarationName::CXXOperatorName);
|
||||
LocInfo.CXXOperatorName.BeginOpNameLoc = R.getBegin().getRawEncoding();
|
||||
LocInfo.CXXOperatorName.EndOpNameLoc = R.getEnd().getRawEncoding();
|
||||
}
|
||||
|
||||
/// getCXXLiteralOperatorNameLoc - Returns the location of the literal
|
||||
/// operator name (not the operator keyword).
|
||||
/// Assumes it is a literal operator.
|
||||
SourceLocation getCXXLiteralOperatorNameLoc() const {
|
||||
assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName);
|
||||
return SourceLocation::
|
||||
getFromRawEncoding(LocInfo.CXXLiteralOperatorName.OpNameLoc);
|
||||
}
|
||||
/// setCXXLiteralOperatorNameLoc - Sets the location of the literal
|
||||
/// operator name (not the operator keyword).
|
||||
/// Assumes it is a literal operator.
|
||||
void setCXXLiteralOperatorNameLoc(SourceLocation Loc) {
|
||||
assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName);
|
||||
LocInfo.CXXLiteralOperatorName.OpNameLoc = Loc.getRawEncoding();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this name involves a template parameter.
|
||||
bool isInstantiationDependent() const;
|
||||
|
||||
/// \brief Determine whether this name contains an unexpanded
|
||||
/// parameter pack.
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
|
||||
/// getAsString - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
||||
/// printName - Print the human-readable name to a stream.
|
||||
void printName(raw_ostream &OS) const;
|
||||
|
||||
/// getBeginLoc - Retrieve the location of the first token.
|
||||
SourceLocation getBeginLoc() const { return NameLoc; }
|
||||
/// getEndLoc - Retrieve the location of the last token.
|
||||
SourceLocation getEndLoc() const;
|
||||
/// getSourceRange - The range of the declaration name.
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getBeginLoc(), getEndLoc());
|
||||
}
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending DeclarationName's
|
||||
/// into a diagnostic with <<.
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
DeclarationName N) {
|
||||
DB.AddTaggedVal(N.getAsOpaqueInteger(),
|
||||
DiagnosticsEngine::ak_declarationname);
|
||||
Diagnostic::ak_declarationname);
|
||||
return DB;
|
||||
}
|
||||
|
||||
@@ -529,16 +375,10 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
DeclarationName N) {
|
||||
PD.AddTaggedVal(N.getAsOpaqueInteger(),
|
||||
DiagnosticsEngine::ak_declarationname);
|
||||
Diagnostic::ak_declarationname);
|
||||
return PD;
|
||||
}
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS,
|
||||
DeclarationNameInfo DNInfo) {
|
||||
DNInfo.printName(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- 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 interfaces for diagnostics which may or may
|
||||
// fire based on how a template is instantiated.
|
||||
//
|
||||
// At the moment, the only consumer of this interface is access
|
||||
// control.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclContextInternals.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class NamedDecl;
|
||||
|
||||
/// A dependently-generated diagnostic.
|
||||
class DependentDiagnostic {
|
||||
public:
|
||||
enum AccessNonce { Access = 0 };
|
||||
|
||||
static DependentDiagnostic *Create(ASTContext &Context,
|
||||
DeclContext *Parent,
|
||||
AccessNonce _,
|
||||
SourceLocation Loc,
|
||||
bool IsMemberAccess,
|
||||
AccessSpecifier AS,
|
||||
NamedDecl *TargetDecl,
|
||||
CXXRecordDecl *NamingClass,
|
||||
QualType BaseObjectType,
|
||||
const PartialDiagnostic &PDiag) {
|
||||
DependentDiagnostic *DD = Create(Context, Parent, PDiag);
|
||||
DD->AccessData.Loc = Loc.getRawEncoding();
|
||||
DD->AccessData.IsMember = IsMemberAccess;
|
||||
DD->AccessData.Access = AS;
|
||||
DD->AccessData.TargetDecl = TargetDecl;
|
||||
DD->AccessData.NamingClass = NamingClass;
|
||||
DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr();
|
||||
return DD;
|
||||
}
|
||||
|
||||
unsigned getKind() const {
|
||||
return Access;
|
||||
}
|
||||
|
||||
bool isAccessToMember() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessData.IsMember;
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessSpecifier(AccessData.Access);
|
||||
}
|
||||
|
||||
SourceLocation getAccessLoc() const {
|
||||
assert(getKind() == Access);
|
||||
return SourceLocation::getFromRawEncoding(AccessData.Loc);
|
||||
}
|
||||
|
||||
NamedDecl *getAccessTarget() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessData.TargetDecl;
|
||||
}
|
||||
|
||||
NamedDecl *getAccessNamingClass() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessData.NamingClass;
|
||||
}
|
||||
|
||||
QualType getAccessBaseObjectType() const {
|
||||
assert(getKind() == Access);
|
||||
return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
|
||||
}
|
||||
|
||||
const PartialDiagnostic &getDiagnostic() const {
|
||||
return Diag;
|
||||
}
|
||||
|
||||
private:
|
||||
DependentDiagnostic(const PartialDiagnostic &PDiag,
|
||||
PartialDiagnostic::Storage *Storage)
|
||||
: Diag(PDiag, Storage) {}
|
||||
|
||||
static DependentDiagnostic *Create(ASTContext &Context,
|
||||
DeclContext *Parent,
|
||||
const PartialDiagnostic &PDiag);
|
||||
|
||||
friend class DependentStoredDeclsMap;
|
||||
friend class DeclContext::ddiag_iterator;
|
||||
DependentDiagnostic *NextDiagnostic;
|
||||
|
||||
PartialDiagnostic Diag;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned Loc;
|
||||
unsigned Access : 2;
|
||||
unsigned IsMember : 1;
|
||||
NamedDecl *TargetDecl;
|
||||
CXXRecordDecl *NamingClass;
|
||||
void *BaseObjectType;
|
||||
} AccessData;
|
||||
};
|
||||
};
|
||||
|
||||
///
|
||||
|
||||
/// An iterator over the dependent diagnostics in a dependent context.
|
||||
class DeclContext::ddiag_iterator {
|
||||
public:
|
||||
ddiag_iterator() : Ptr(0) {}
|
||||
explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
|
||||
|
||||
typedef DependentDiagnostic *value_type;
|
||||
typedef DependentDiagnostic *reference;
|
||||
typedef DependentDiagnostic *pointer;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
reference operator*() const { return Ptr; }
|
||||
|
||||
ddiag_iterator &operator++() {
|
||||
assert(Ptr && "attempt to increment past end of diag list");
|
||||
Ptr = Ptr->NextDiagnostic;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ddiag_iterator operator++(int) {
|
||||
ddiag_iterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(ddiag_iterator Other) const {
|
||||
return Ptr == Other.Ptr;
|
||||
}
|
||||
|
||||
bool operator!=(ddiag_iterator Other) const {
|
||||
return Ptr != Other.Ptr;
|
||||
}
|
||||
|
||||
ddiag_iterator &operator+=(difference_type N) {
|
||||
assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
|
||||
while (N--)
|
||||
++*this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ddiag_iterator operator+(difference_type N) const {
|
||||
ddiag_iterator tmp = *this;
|
||||
tmp += N;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
DependentDiagnostic *Ptr;
|
||||
};
|
||||
|
||||
inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const {
|
||||
assert(isDependentContext()
|
||||
&& "cannot iterate dependent diagnostics of non-dependent context");
|
||||
const DependentStoredDeclsMap *Map
|
||||
= static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->LookupPtr);
|
||||
|
||||
if (!Map) return ddiag_iterator();
|
||||
return ddiag_iterator(Map->FirstDiagnostic);
|
||||
}
|
||||
|
||||
inline DeclContext::ddiag_iterator DeclContext::ddiag_end() const {
|
||||
return ddiag_iterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,83 +0,0 @@
|
||||
//===--- EvaluatedExprVisitor.h - Evaluated expression visitor --*- 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 EvaluatedExprVisitor class template, which visits
|
||||
// the potentially-evaluated subexpressions of a potentially-evaluated
|
||||
// expression.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
|
||||
#define LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
|
||||
/// \begin Given a potentially-evaluated expression, this visitor visits all
|
||||
/// of its potentially-evaluated subexpressions, recursively.
|
||||
template<typename ImplClass>
|
||||
class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
ASTContext &Context;
|
||||
|
||||
public:
|
||||
explicit EvaluatedExprVisitor(ASTContext &Context) : Context(Context) { }
|
||||
|
||||
// Expressions that have no potentially-evaluated subexpressions (but may have
|
||||
// other sub-expressions).
|
||||
void VisitDeclRefExpr(DeclRefExpr *E) { }
|
||||
void VisitOffsetOfExpr(OffsetOfExpr *E) { }
|
||||
void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { }
|
||||
void VisitExpressionTraitExpr(ExpressionTraitExpr *E) { }
|
||||
void VisitBlockExpr(BlockExpr *E) { }
|
||||
void VisitCXXUuidofExpr(CXXUuidofExpr *E) { }
|
||||
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { }
|
||||
|
||||
void VisitMemberExpr(MemberExpr *E) {
|
||||
// Only the base matters.
|
||||
return this->Visit(E->getBase());
|
||||
}
|
||||
|
||||
void VisitChooseExpr(ChooseExpr *E) {
|
||||
// Only the selected subexpression matters; the other one is not evaluated.
|
||||
return this->Visit(E->getChosenSubExpr(Context));
|
||||
}
|
||||
|
||||
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
|
||||
// Only the actual initializer matters; the designators are all constant
|
||||
// expressions.
|
||||
return this->Visit(E->getInit());
|
||||
}
|
||||
|
||||
void VisitCXXTypeidExpr(CXXTypeidExpr *E) {
|
||||
// typeid(expression) is potentially evaluated when the argument is
|
||||
// a glvalue of polymorphic type. (C++ 5.2.8p2-3)
|
||||
if (!E->isTypeOperand() && E->Classify(Context).isGLValue())
|
||||
if (const RecordType *Record
|
||||
= E->getExprOperand()->getType()->template getAs<RecordType>())
|
||||
if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic())
|
||||
return this->Visit(E->getExprOperand());
|
||||
}
|
||||
|
||||
/// \brief The basis case walks all of the children of the statement or
|
||||
/// expression, assuming they are all potentially evaluated.
|
||||
void VisitStmt(Stmt *S) {
|
||||
for (Stmt::child_range C = S->children(); C; ++C)
|
||||
if (*C)
|
||||
this->Visit(*C);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,39 +8,37 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ExternalASTSource interface, which enables
|
||||
// construction of AST nodes from some external source.
|
||||
// construction of AST nodes from some external source.x
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
namespace clang {
|
||||
|
||||
class ASTConsumer;
|
||||
class CXXBaseSpecifier;
|
||||
class DeclarationName;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class ExternalSemaSource; // layering violation required for downcasting
|
||||
class NamedDecl;
|
||||
class Selector;
|
||||
class Stmt;
|
||||
class TagDecl;
|
||||
|
||||
/// \brief Enumeration describing the result of loading information from
|
||||
/// an external source.
|
||||
enum ExternalLoadResult {
|
||||
/// \brief Loading the external information has succeeded.
|
||||
ELR_Success,
|
||||
|
||||
/// \brief Loading the external information has failed.
|
||||
ELR_Failure,
|
||||
|
||||
/// \brief The external information has already been loaded, and therefore
|
||||
/// no additional processing is required.
|
||||
ELR_AlreadyLoaded
|
||||
/// \brief The deserialized representation of a set of declarations
|
||||
/// with the same name that are visible in a given context.
|
||||
struct VisibleDeclaration {
|
||||
/// \brief The name of the declarations.
|
||||
DeclarationName Name;
|
||||
|
||||
/// \brief The ID numbers of all of the declarations with this name.
|
||||
///
|
||||
/// These declarations have not necessarily been de-serialized.
|
||||
llvm::SmallVector<unsigned, 4> Declarations;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Abstract interface for external sources of AST nodes.
|
||||
///
|
||||
/// External AST sources provide AST nodes constructed from some
|
||||
@@ -60,167 +58,68 @@ public:
|
||||
|
||||
virtual ~ExternalASTSource();
|
||||
|
||||
/// \brief RAII class for safely pairing a StartedDeserializing call
|
||||
/// with FinishedDeserializing.
|
||||
class Deserializing {
|
||||
ExternalASTSource *Source;
|
||||
public:
|
||||
explicit Deserializing(ExternalASTSource *source) : Source(source) {
|
||||
assert(Source);
|
||||
Source->StartedDeserializing();
|
||||
}
|
||||
~Deserializing() {
|
||||
Source->FinishedDeserializing();
|
||||
}
|
||||
};
|
||||
/// \brief Reads the source ranges that correspond to comments from
|
||||
/// an external AST source.
|
||||
///
|
||||
/// \param Comments the contents of this vector will be
|
||||
/// replaced with the sorted set of source ranges corresponding to
|
||||
/// comments in the source code.
|
||||
virtual void ReadComments(std::vector<SourceRange> &Comments) = 0;
|
||||
|
||||
/// \brief Resolve a type ID into a type, potentially building a new
|
||||
/// type.
|
||||
virtual QualType GetType(uint32_t ID) = 0;
|
||||
|
||||
/// \brief Resolve a declaration ID into a declaration, potentially
|
||||
/// building a new declaration.
|
||||
///
|
||||
/// This method only needs to be implemented if the AST source ever
|
||||
/// passes back decl sets as VisibleDeclaration objects.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual Decl *GetExternalDecl(uint32_t ID);
|
||||
virtual Decl *GetDecl(uint32_t ID) = 0;
|
||||
|
||||
/// \brief Resolve a selector ID into a selector.
|
||||
/// \brief Resolve the offset of a statement in the decl stream into a
|
||||
/// statement.
|
||||
///
|
||||
/// This operation only needs to be implemented if the AST source
|
||||
/// returns non-zero for GetNumKnownSelectors().
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual Selector GetExternalSelector(uint32_t ID);
|
||||
/// This operation will read a new statement from the external
|
||||
/// source each time it is called, and is meant to be used via a
|
||||
/// LazyOffsetPtr.
|
||||
virtual Stmt *GetDeclStmt(uint64_t Offset) = 0;
|
||||
|
||||
/// \brief Returns the number of selectors known to the external AST
|
||||
/// source.
|
||||
/// \brief Read all of the declarations lexically stored in a
|
||||
/// declaration context.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual uint32_t GetNumExternalSelectors();
|
||||
/// \param DC The declaration context whose declarations will be
|
||||
/// read.
|
||||
///
|
||||
/// \param Decls Vector that will contain the declarations loaded
|
||||
/// from the external source. The caller is responsible for merging
|
||||
/// these declarations with any declarations already stored in the
|
||||
/// declaration context.
|
||||
///
|
||||
/// \returns true if there was an error while reading the
|
||||
/// declarations for this declaration context.
|
||||
virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
|
||||
llvm::SmallVectorImpl<uint32_t> &Decls) = 0;
|
||||
|
||||
/// \brief Resolve the offset of a statement in the decl stream into
|
||||
/// a statement.
|
||||
/// \brief Read all of the declarations visible from a declaration
|
||||
/// context.
|
||||
///
|
||||
/// This operation is meant to be used via a LazyOffsetPtr. It only
|
||||
/// needs to be implemented if the AST source uses methods like
|
||||
/// FunctionDecl::setLazyBody when building decls.
|
||||
/// \param DC The declaration context whose visible declarations
|
||||
/// will be read.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
|
||||
|
||||
/// \brief Resolve the offset of a set of C++ base specifiers in the decl
|
||||
/// stream into an array of specifiers.
|
||||
/// \param Decls A vector of visible declaration structures,
|
||||
/// providing the mapping from each name visible in the declaration
|
||||
/// context to the declaration IDs of declarations with that name.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
|
||||
|
||||
/// \brief Finds all declarations with the given name in the
|
||||
/// given context.
|
||||
///
|
||||
/// Generally the final step of this method is either to call
|
||||
/// SetExternalVisibleDeclsForName or to recursively call lookup on
|
||||
/// the DeclContext after calling SetExternalVisibleDecls.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual DeclContextLookupResult
|
||||
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext, after applying an optional filter predicate.
|
||||
///
|
||||
/// \param isKindWeWant a predicate function that returns true if the passed
|
||||
/// declaration kind is one we are looking for. If NULL, all declarations
|
||||
/// are returned.
|
||||
///
|
||||
/// \return an indication of whether the load succeeded or failed.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
|
||||
bool (*isKindWeWant)(Decl::Kind),
|
||||
SmallVectorImpl<Decl*> &Result);
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext.
|
||||
///
|
||||
/// \return true if an error occurred
|
||||
ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
|
||||
SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, 0, Result);
|
||||
}
|
||||
|
||||
template <typename DeclTy>
|
||||
ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC,
|
||||
SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
|
||||
}
|
||||
|
||||
/// \brief Gives the external AST source an opportunity to complete
|
||||
/// an incomplete type.
|
||||
virtual void CompleteType(TagDecl *Tag) {}
|
||||
|
||||
/// \brief Gives the external AST source an opportunity to complete an
|
||||
/// incomplete Objective-C class.
|
||||
///
|
||||
/// This routine will only be invoked if the "externally completed" bit is
|
||||
/// set on the ObjCInterfaceDecl via the function
|
||||
/// \c ObjCInterfaceDecl::setExternallyCompleted().
|
||||
virtual void CompleteType(ObjCInterfaceDecl *Class) { }
|
||||
|
||||
/// \brief Notify ExternalASTSource that we started deserialization of
|
||||
/// a decl or type so until FinishedDeserializing is called there may be
|
||||
/// decls that are initializing. Must be paired with FinishedDeserializing.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual void StartedDeserializing() { }
|
||||
|
||||
/// \brief Notify ExternalASTSource that we finished the deserialization of
|
||||
/// a decl or type. Must be paired with StartedDeserializing.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual void FinishedDeserializing() { }
|
||||
/// \returns true if there was an error while reading the
|
||||
/// declarations for this declaration context.
|
||||
virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
|
||||
llvm::SmallVectorImpl<VisibleDeclaration> & Decls) = 0;
|
||||
|
||||
/// \brief Function that will be invoked when we begin parsing a new
|
||||
/// translation unit involving this external AST source.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual void StartTranslationUnit(ASTConsumer *Consumer) { }
|
||||
|
||||
/// \brief Print any statistics that have been gathered regarding
|
||||
/// the external AST source.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual void PrintStats();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Queries for performance analysis.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct MemoryBufferSizes {
|
||||
size_t malloc_bytes;
|
||||
size_t mmap_bytes;
|
||||
|
||||
MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
|
||||
: malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
|
||||
};
|
||||
|
||||
/// Return the amount of memory used by memory buffers, breaking down
|
||||
/// by heap-backed versus mmap'ed memory.
|
||||
MemoryBufferSizes getMemoryBufferSizes() const {
|
||||
MemoryBufferSizes sizes(0, 0);
|
||||
getMemoryBufferSizes(sizes);
|
||||
return sizes;
|
||||
}
|
||||
|
||||
virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
|
||||
|
||||
protected:
|
||||
static DeclContextLookupResult
|
||||
SetExternalVisibleDeclsForName(const DeclContext *DC,
|
||||
DeclarationName Name,
|
||||
ArrayRef<NamedDecl*> Decls);
|
||||
|
||||
static DeclContextLookupResult
|
||||
SetNoExternalVisibleDeclsForName(const DeclContext *DC,
|
||||
DeclarationName Name);
|
||||
};
|
||||
|
||||
/// \brief A lazy pointer to an AST node (of base type T) that resides
|
||||
@@ -229,7 +128,7 @@ protected:
|
||||
/// The AST node is identified within the external AST source by a
|
||||
/// 63-bit offset, and can be retrieved via an operation on the
|
||||
/// external AST source itself.
|
||||
template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)>
|
||||
template<typename T, T* (ExternalASTSource::*Get)(uint64_t Offset)>
|
||||
struct LazyOffsetPtr {
|
||||
/// \brief Either a pointer to an AST node or the offset within the
|
||||
/// external AST source where the AST node can be found.
|
||||
@@ -286,190 +185,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a lazily-loaded vector of data.
|
||||
///
|
||||
/// The lazily-loaded vector of data contains data that is partially loaded
|
||||
/// from an external source and partially added by local translation. The
|
||||
/// items loaded from the external source are loaded lazily, when needed for
|
||||
/// iteration over the complete vector.
|
||||
template<typename T, typename Source,
|
||||
void (Source::*Loader)(SmallVectorImpl<T>&),
|
||||
unsigned LoadedStorage = 2, unsigned LocalStorage = 4>
|
||||
class LazyVector {
|
||||
SmallVector<T, LoadedStorage> Loaded;
|
||||
SmallVector<T, LocalStorage> Local;
|
||||
|
||||
public:
|
||||
// Iteration over the elements in the vector.
|
||||
class iterator {
|
||||
LazyVector *Self;
|
||||
|
||||
/// \brief Position within the vector..
|
||||
///
|
||||
/// In a complete iteration, the Position field walks the range [-M, N),
|
||||
/// where negative values are used to indicate elements
|
||||
/// loaded from the external source while non-negative values are used to
|
||||
/// indicate elements added via \c push_back().
|
||||
/// However, to provide iteration in source order (for, e.g., chained
|
||||
/// precompiled headers), dereferencing the iterator flips the negative
|
||||
/// values (corresponding to loaded entities), so that position -M
|
||||
/// corresponds to element 0 in the loaded entities vector, position -M+1
|
||||
/// corresponds to element 1 in the loaded entities vector, etc. This
|
||||
/// gives us a reasonably efficient, source-order walk.
|
||||
int Position;
|
||||
|
||||
friend class LazyVector;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef int difference_type;
|
||||
|
||||
iterator() : Self(0), Position(0) { }
|
||||
|
||||
iterator(LazyVector *Self, int Position)
|
||||
: Self(Self), Position(Position) { }
|
||||
|
||||
reference operator*() const {
|
||||
if (Position < 0)
|
||||
return Self->Loaded.end()[Position];
|
||||
return Self->Local[Position];
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
if (Position < 0)
|
||||
return &Self->Loaded.end()[Position];
|
||||
|
||||
return &Self->Local[Position];
|
||||
}
|
||||
|
||||
reference operator[](difference_type D) {
|
||||
return *(*this + D);
|
||||
}
|
||||
|
||||
iterator &operator++() {
|
||||
++Position;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) {
|
||||
iterator Prev(*this);
|
||||
++Position;
|
||||
return Prev;
|
||||
}
|
||||
|
||||
iterator &operator--() {
|
||||
--Position;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator--(int) {
|
||||
iterator Prev(*this);
|
||||
--Position;
|
||||
return Prev;
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator &X, const iterator &Y) {
|
||||
return X.Position == Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator!=(const iterator &X, const iterator &Y) {
|
||||
return X.Position != Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator<(const iterator &X, const iterator &Y) {
|
||||
return X.Position < Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator>(const iterator &X, const iterator &Y) {
|
||||
return X.Position > Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator<=(const iterator &X, const iterator &Y) {
|
||||
return X.Position < Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator>=(const iterator &X, const iterator &Y) {
|
||||
return X.Position > Y.Position;
|
||||
}
|
||||
|
||||
friend iterator& operator+=(iterator &X, difference_type D) {
|
||||
X.Position += D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend iterator& operator-=(iterator &X, difference_type D) {
|
||||
X.Position -= D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend iterator operator+(iterator X, difference_type D) {
|
||||
X.Position += D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend iterator operator+(difference_type D, iterator X) {
|
||||
X.Position += D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend difference_type operator-(const iterator &X, const iterator &Y) {
|
||||
return X.Position - Y.Position;
|
||||
}
|
||||
|
||||
friend iterator operator-(iterator X, difference_type D) {
|
||||
X.Position -= D;
|
||||
return X;
|
||||
}
|
||||
};
|
||||
friend class iterator;
|
||||
|
||||
iterator begin(Source *source, bool LocalOnly = false) {
|
||||
if (LocalOnly)
|
||||
return iterator(this, 0);
|
||||
|
||||
if (source)
|
||||
(source->*Loader)(Loaded);
|
||||
return iterator(this, -(int)Loaded.size());
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return iterator(this, Local.size());
|
||||
}
|
||||
|
||||
void push_back(const T& LocalValue) {
|
||||
Local.push_back(LocalValue);
|
||||
}
|
||||
|
||||
void erase(iterator From, iterator To) {
|
||||
if (From.Position < 0 && To.Position < 0) {
|
||||
Loaded.erase(Loaded.end() + From.Position, Loaded.end() + To.Position);
|
||||
return;
|
||||
}
|
||||
|
||||
if (From.Position < 0) {
|
||||
Loaded.erase(Loaded.end() + From.Position, Loaded.end());
|
||||
From = begin(0, true);
|
||||
}
|
||||
|
||||
Local.erase(Local.begin() + From.Position, Local.begin() + To.Position);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A lazy pointer to a statement.
|
||||
typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
|
||||
LazyDeclStmtPtr;
|
||||
|
||||
/// \brief A lazy pointer to a declaration.
|
||||
typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>
|
||||
LazyDeclPtr;
|
||||
|
||||
/// \brief A lazy pointer to a set of CXXBaseSpecifiers.
|
||||
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
|
||||
&ExternalASTSource::GetExternalCXXBaseSpecifiers>
|
||||
LazyCXXBaseSpecifiersPtr;
|
||||
typedef LazyOffsetPtr<Stmt, &ExternalASTSource::GetDeclStmt> LazyDeclStmtPtr;
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
89
clang/include/clang/AST/FullExpr.h
Normal file
89
clang/include/clang/AST/FullExpr.h
Normal file
@@ -0,0 +1,89 @@
|
||||
//===--- FullExpr.h - C++ full expression class -----------------*- 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 FullExpr interface, to be used for type safe handling
|
||||
// of full expressions.
|
||||
//
|
||||
// Full expressions are described in C++ [intro.execution]p12.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_FULLEXPR_H
|
||||
#define LLVM_CLANG_AST_FULLEXPR_H
|
||||
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class CXXTemporary;
|
||||
class Expr;
|
||||
|
||||
class FullExpr {
|
||||
struct ExprAndTemporaries {
|
||||
Expr *SubExpr;
|
||||
|
||||
unsigned NumTemps;
|
||||
|
||||
typedef CXXTemporary** temps_iterator;
|
||||
|
||||
temps_iterator temps_begin() {
|
||||
return reinterpret_cast<CXXTemporary **>(this + 1);
|
||||
}
|
||||
temps_iterator temps_end() {
|
||||
return temps_begin() + NumTemps;
|
||||
}
|
||||
};
|
||||
|
||||
typedef llvm::PointerUnion<Expr *, ExprAndTemporaries *> SubExprTy;
|
||||
SubExprTy SubExpr;
|
||||
|
||||
FullExpr() { }
|
||||
|
||||
public:
|
||||
static FullExpr Create(ASTContext &Context, Expr *SubExpr,
|
||||
CXXTemporary **Temps, unsigned NumTemps);
|
||||
void Destroy(ASTContext &Context);
|
||||
|
||||
Expr *getExpr() {
|
||||
if (Expr *E = SubExpr.dyn_cast<Expr *>())
|
||||
return E;
|
||||
|
||||
return SubExpr.get<ExprAndTemporaries *>()->SubExpr;
|
||||
}
|
||||
|
||||
const Expr *getExpr() const {
|
||||
return const_cast<FullExpr*>(this)->getExpr();
|
||||
}
|
||||
|
||||
typedef CXXTemporary** temps_iterator;
|
||||
|
||||
temps_iterator temps_begin() {
|
||||
if (ExprAndTemporaries *ET = SubExpr.dyn_cast<ExprAndTemporaries *>())
|
||||
return ET->temps_begin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
temps_iterator temps_end() {
|
||||
if (ExprAndTemporaries *ET = SubExpr.dyn_cast<ExprAndTemporaries *>())
|
||||
return ET->temps_end();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *getAsOpaquePtr() const { return SubExpr.getOpaqueValue(); }
|
||||
|
||||
static FullExpr getFromOpaquePtr(void *Ptr) {
|
||||
FullExpr E;
|
||||
E.SubExpr = SubExprTy::getFromOpaqueValue(Ptr);
|
||||
return E;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
CLANG_LEVEL := ../../..
|
||||
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
|
||||
BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc
|
||||
|
||||
TABLEGEN_INC_FILES_COMMON = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
$(ObjDir)/Attrs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang attribute classes with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-attr-classes -o $(call SYSPATH, $@) \
|
||||
-I $(PROJ_SRC_DIR)/../../ $<
|
||||
|
||||
$(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang attribute implementations with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \
|
||||
-I $(PROJ_SRC_DIR)/../../ $<
|
||||
|
||||
$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang statement node tables with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(ObjDir)/DeclNodes.inc.tmp : $(TD_SRC_DIR)/DeclNodes.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang declaration node tables with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-decl-nodes -o $(call SYSPATH, $@) $<
|
||||
@@ -1,150 +0,0 @@
|
||||
//===--- Mangle.h - Mangle C++ Names ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the C++ name mangling interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MANGLE_H
|
||||
#define LLVM_CLANG_AST_MANGLE_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/ABI.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class BlockDecl;
|
||||
class CXXConstructorDecl;
|
||||
class CXXDestructorDecl;
|
||||
class CXXMethodDecl;
|
||||
class FunctionDecl;
|
||||
class NamedDecl;
|
||||
class ObjCMethodDecl;
|
||||
class VarDecl;
|
||||
struct ThisAdjustment;
|
||||
struct ThunkInfo;
|
||||
|
||||
/// MangleBuffer - a convenient class for storing a name which is
|
||||
/// either the result of a mangling or is a constant string with
|
||||
/// external memory ownership.
|
||||
class MangleBuffer {
|
||||
public:
|
||||
void setString(StringRef Ref) {
|
||||
String = Ref;
|
||||
}
|
||||
|
||||
SmallVectorImpl<char> &getBuffer() {
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
StringRef getString() const {
|
||||
if (!String.empty()) return String;
|
||||
return Buffer.str();
|
||||
}
|
||||
|
||||
operator StringRef() const {
|
||||
return getString();
|
||||
}
|
||||
|
||||
private:
|
||||
StringRef String;
|
||||
llvm::SmallString<256> Buffer;
|
||||
};
|
||||
|
||||
/// MangleContext - Context for tracking state which persists across multiple
|
||||
/// calls to the C++ name mangler.
|
||||
class MangleContext {
|
||||
ASTContext &Context;
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
|
||||
|
||||
public:
|
||||
explicit MangleContext(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags)
|
||||
: Context(Context), Diags(Diags) { }
|
||||
|
||||
virtual ~MangleContext() { }
|
||||
|
||||
ASTContext &getASTContext() const { return Context; }
|
||||
|
||||
DiagnosticsEngine &getDiags() const { return Diags; }
|
||||
|
||||
virtual void startNewFunction() { LocalBlockIds.clear(); }
|
||||
|
||||
unsigned getBlockId(const BlockDecl *BD, bool Local) {
|
||||
llvm::DenseMap<const BlockDecl *, unsigned> &BlockIds
|
||||
= Local? LocalBlockIds : GlobalBlockIds;
|
||||
std::pair<llvm::DenseMap<const BlockDecl *, unsigned>::iterator, bool>
|
||||
Result = BlockIds.insert(std::make_pair(BD, BlockIds.size()));
|
||||
return Result.first->second;
|
||||
}
|
||||
|
||||
/// @name Mangler Entry Points
|
||||
/// @{
|
||||
|
||||
virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
|
||||
virtual void mangleName(const NamedDecl *D, raw_ostream &)=0;
|
||||
virtual void mangleThunk(const CXXMethodDecl *MD,
|
||||
const ThunkInfo &Thunk,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
|
||||
const ThisAdjustment &ThisAdjustment,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleReferenceTemporary(const VarDecl *D,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
|
||||
const CXXRecordDecl *Type,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
|
||||
raw_ostream &) = 0;
|
||||
|
||||
void mangleGlobalBlock(const BlockDecl *BD,
|
||||
raw_ostream &Out);
|
||||
void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT,
|
||||
const BlockDecl *BD, raw_ostream &Out);
|
||||
void mangleDtorBlock(const CXXDestructorDecl *CD, CXXDtorType DT,
|
||||
const BlockDecl *BD, raw_ostream &Out);
|
||||
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
||||
raw_ostream &Out);
|
||||
// Do the right thing.
|
||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out);
|
||||
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD,
|
||||
raw_ostream &);
|
||||
|
||||
// This is pretty lame.
|
||||
virtual void mangleItaniumGuardVariable(const VarDecl *D,
|
||||
raw_ostream &) {
|
||||
llvm_unreachable("Target does not support mangling guard variables");
|
||||
}
|
||||
/// @}
|
||||
};
|
||||
|
||||
MangleContext *createItaniumMangleContext(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags);
|
||||
MangleContext *createMicrosoftMangleContext(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -18,15 +18,17 @@
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class NamespaceAliasDecl;
|
||||
class NamespaceDecl;
|
||||
class IdentifierInfo;
|
||||
struct PrintingPolicy;
|
||||
class Type;
|
||||
class TypeLoc;
|
||||
class LangOptions;
|
||||
|
||||
/// \brief Represents a C++ nested name specifier, such as
|
||||
@@ -39,22 +41,13 @@ class LangOptions;
|
||||
/// (for dependent names), or the global specifier ('::', must be the
|
||||
/// first specifier).
|
||||
class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
|
||||
/// \brief Enumeration describing
|
||||
enum StoredSpecifierKind {
|
||||
StoredIdentifier = 0,
|
||||
StoredNamespaceOrAlias = 1,
|
||||
StoredTypeSpec = 2,
|
||||
StoredTypeSpecWithTemplate = 3
|
||||
};
|
||||
|
||||
/// \brief The nested name specifier that precedes this nested name
|
||||
/// specifier.
|
||||
///
|
||||
/// The pointer is the nested-name-specifier that precedes this
|
||||
/// one. The integer stores one of the first four values of type
|
||||
/// SpecifierKind.
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 2, StoredSpecifierKind> Prefix;
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 2> Prefix;
|
||||
|
||||
/// \brief The last component in the nested name specifier, which
|
||||
/// can be an identifier, a declaration, or a type.
|
||||
@@ -70,23 +63,21 @@ public:
|
||||
/// specifier.
|
||||
enum SpecifierKind {
|
||||
/// \brief An identifier, stored as an IdentifierInfo*.
|
||||
Identifier,
|
||||
/// \brief A namespace, stored as a NamespaceDecl*.
|
||||
Namespace,
|
||||
/// \brief A namespace alias, stored as a NamespaceAliasDecl*.
|
||||
NamespaceAlias,
|
||||
Identifier = 0,
|
||||
/// \brief A namespace, stored as a Namespace*.
|
||||
Namespace = 1,
|
||||
/// \brief A type, stored as a Type*.
|
||||
TypeSpec,
|
||||
TypeSpec = 2,
|
||||
/// \brief A type that was preceded by the 'template' keyword,
|
||||
/// stored as a Type*.
|
||||
TypeSpecWithTemplate,
|
||||
TypeSpecWithTemplate = 3,
|
||||
/// \brief The global specifier '::'. There is no stored value.
|
||||
Global
|
||||
Global = 4
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief Builds the global specifier.
|
||||
NestedNameSpecifier() : Prefix(0, StoredIdentifier), Specifier(0) { }
|
||||
NestedNameSpecifier() : Prefix(0, 0), Specifier(0) { }
|
||||
|
||||
/// \brief Copy constructor used internally to clone nested name
|
||||
/// specifiers.
|
||||
@@ -99,7 +90,7 @@ private:
|
||||
|
||||
/// \brief Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
static NestedNameSpecifier *FindOrInsert(const ASTContext &Context,
|
||||
static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
|
||||
const NestedNameSpecifier &Mockup);
|
||||
|
||||
public:
|
||||
@@ -108,24 +99,19 @@ public:
|
||||
/// The prefix must be dependent, since nested name specifiers
|
||||
/// referencing an identifier are only permitted when the identifier
|
||||
/// cannot be resolved.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
IdentifierInfo *II);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a namespace.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
NamespaceDecl *NS);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a namespace alias.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
NamespaceAliasDecl *Alias);
|
||||
|
||||
/// \brief Builds a nested name specifier that names a type.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
static NestedNameSpecifier *Create(ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
bool Template, const Type *T);
|
||||
bool Template, Type *T);
|
||||
|
||||
/// \brief Builds a specifier that consists of just an identifier.
|
||||
///
|
||||
@@ -133,12 +119,11 @@ public:
|
||||
/// prefix because the prefix is implied by something outside of the
|
||||
/// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
|
||||
/// type.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
IdentifierInfo *II);
|
||||
static NestedNameSpecifier *Create(ASTContext &Context, IdentifierInfo *II);
|
||||
|
||||
/// \brief Returns the nested name specifier representing the global
|
||||
/// scope.
|
||||
static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context);
|
||||
static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context);
|
||||
|
||||
/// \brief Return the prefix of this nested name specifier.
|
||||
///
|
||||
@@ -150,12 +135,16 @@ public:
|
||||
NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
|
||||
|
||||
/// \brief Determine what kind of nested name specifier is stored.
|
||||
SpecifierKind getKind() const;
|
||||
SpecifierKind getKind() const {
|
||||
if (Specifier == 0)
|
||||
return Global;
|
||||
return (SpecifierKind)Prefix.getInt();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the identifier stored in this nested name
|
||||
/// specifier.
|
||||
IdentifierInfo *getAsIdentifier() const {
|
||||
if (Prefix.getInt() == StoredIdentifier)
|
||||
if (Prefix.getInt() == Identifier)
|
||||
return (IdentifierInfo *)Specifier;
|
||||
|
||||
return 0;
|
||||
@@ -163,17 +152,18 @@ public:
|
||||
|
||||
/// \brief Retrieve the namespace stored in this nested name
|
||||
/// specifier.
|
||||
NamespaceDecl *getAsNamespace() const;
|
||||
NamespaceDecl *getAsNamespace() const {
|
||||
if (Prefix.getInt() == Namespace)
|
||||
return (NamespaceDecl *)Specifier;
|
||||
|
||||
/// \brief Retrieve the namespace alias stored in this nested name
|
||||
/// specifier.
|
||||
NamespaceAliasDecl *getAsNamespaceAlias() const;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type stored in this nested name specifier.
|
||||
const Type *getAsType() const {
|
||||
if (Prefix.getInt() == StoredTypeSpec ||
|
||||
Prefix.getInt() == StoredTypeSpecWithTemplate)
|
||||
return (const Type *)Specifier;
|
||||
Type *getAsType() const {
|
||||
if (Prefix.getInt() == TypeSpec ||
|
||||
Prefix.getInt() == TypeSpecWithTemplate)
|
||||
return (Type *)Specifier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -182,290 +172,28 @@ public:
|
||||
/// type or not.
|
||||
bool isDependent() const;
|
||||
|
||||
/// \brief Whether this nested name specifier involves a template
|
||||
/// parameter.
|
||||
bool isInstantiationDependent() const;
|
||||
|
||||
/// \brief Whether this nested-name-specifier contains an unexpanded
|
||||
/// parameter pack (for C++0x variadic templates).
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
|
||||
/// \brief Print this nested name specifier to the given output
|
||||
/// stream.
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
|
||||
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddPointer(Prefix.getOpaqueValue());
|
||||
ID.AddPointer(Specifier);
|
||||
}
|
||||
|
||||
void Destroy(ASTContext &Context);
|
||||
|
||||
/// \brief Dump the nested name specifier to standard output to aid
|
||||
/// in debugging.
|
||||
void dump(const LangOptions &LO);
|
||||
};
|
||||
|
||||
/// \brief A C++ nested-name-specifier augmented with source location
|
||||
/// information.
|
||||
class NestedNameSpecifierLoc {
|
||||
NestedNameSpecifier *Qualifier;
|
||||
void *Data;
|
||||
|
||||
/// \brief Determines the data length for the last component in the
|
||||
/// given nested-name-specifier.
|
||||
static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier);
|
||||
|
||||
/// \brief Determines the data length for the entire
|
||||
/// nested-name-specifier.
|
||||
static unsigned getDataLength(NestedNameSpecifier *Qualifier);
|
||||
|
||||
public:
|
||||
/// \brief Construct an empty nested-name-specifier.
|
||||
NestedNameSpecifierLoc() : Qualifier(0), Data(0) { }
|
||||
|
||||
/// \brief Construct a nested-name-specifier with source location information
|
||||
/// from
|
||||
NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data)
|
||||
: Qualifier(Qualifier), Data(Data) { }
|
||||
|
||||
/// \brief Evalutes true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
operator bool() const { return Qualifier; }
|
||||
|
||||
/// \brief Retrieve the nested-name-specifier to which this instance
|
||||
/// refers.
|
||||
NestedNameSpecifier *getNestedNameSpecifier() const {
|
||||
return Qualifier;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the opaque pointer that refers to source-location data.
|
||||
void *getOpaqueData() const { return Data; }
|
||||
|
||||
/// \brief Retrieve the source range covering the entirety of this
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c ::std::vector<int>::, the returned source range would cover
|
||||
/// from the initial '::' to the last '::'.
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
/// \brief Retrieve the source range covering just the last part of
|
||||
/// this nested-name-specifier, not including the prefix.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c ::std::vector<int>::, the returned source range would cover
|
||||
/// from "vector" to the last '::'.
|
||||
SourceRange getLocalSourceRange() const;
|
||||
|
||||
/// \brief Retrieve the location of the beginning of this
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getBeginLoc() const {
|
||||
return getSourceRange().getBegin();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the end of this
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getEndLoc() const {
|
||||
return getSourceRange().getEnd();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the beginning of this
|
||||
/// component of the nested-name-specifier.
|
||||
SourceLocation getLocalBeginLoc() const {
|
||||
return getLocalSourceRange().getBegin();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the end of this component of the
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getLocalEndLoc() const {
|
||||
return getLocalSourceRange().getEnd();
|
||||
}
|
||||
|
||||
/// \brief Return the prefix of this nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c ::std::vector<int>::, the prefix is \c ::std::. Note that the
|
||||
/// returned prefix may be empty, if this is the first component of
|
||||
/// the nested-name-specifier.
|
||||
NestedNameSpecifierLoc getPrefix() const {
|
||||
if (!Qualifier)
|
||||
return *this;
|
||||
|
||||
return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data);
|
||||
}
|
||||
|
||||
/// \brief For a nested-name-specifier that refers to a type,
|
||||
/// retrieve the type with source-location information.
|
||||
TypeLoc getTypeLoc() const;
|
||||
|
||||
/// \brief Determines the data length for the entire
|
||||
/// nested-name-specifier.
|
||||
unsigned getDataLength() const { return getDataLength(Qualifier); }
|
||||
|
||||
friend bool operator==(NestedNameSpecifierLoc X,
|
||||
NestedNameSpecifierLoc Y) {
|
||||
return X.Qualifier == Y.Qualifier && X.Data == Y.Data;
|
||||
}
|
||||
|
||||
friend bool operator!=(NestedNameSpecifierLoc X,
|
||||
NestedNameSpecifierLoc Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Class that aids in the construction of nested-name-specifiers along
|
||||
/// with source-location information for all of the components of the
|
||||
/// nested-name-specifier.
|
||||
class NestedNameSpecifierLocBuilder {
|
||||
/// \brief The current representation of the nested-name-specifier we're
|
||||
/// building.
|
||||
NestedNameSpecifier *Representation;
|
||||
|
||||
/// \brief Buffer used to store source-location information for the
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// Note that we explicitly manage the buffer (rather than using a
|
||||
/// SmallVector) because \c Declarator expects it to be possible to memcpy()
|
||||
/// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
|
||||
char *Buffer;
|
||||
|
||||
/// \brief The size of the buffer used to store source-location information
|
||||
/// for the nested-name-specifier.
|
||||
unsigned BufferSize;
|
||||
|
||||
/// \brief The capacity of the buffer used to store source-location
|
||||
/// information for the nested-name-specifier.
|
||||
unsigned BufferCapacity;
|
||||
|
||||
public:
|
||||
NestedNameSpecifierLocBuilder();
|
||||
|
||||
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
NestedNameSpecifierLocBuilder &
|
||||
operator=(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
~NestedNameSpecifierLocBuilder();
|
||||
|
||||
/// \brief Retrieve the representation of the nested-name-specifier.
|
||||
NestedNameSpecifier *getRepresentation() const { return Representation; }
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'type::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param TemplateKWLoc The location of the 'template' keyword, if present.
|
||||
///
|
||||
/// \param TL The TypeLoc that describes the type preceding the '::'.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL,
|
||||
SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'identifier::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param Identifier The identifier.
|
||||
///
|
||||
/// \param IdentifierLoc The location of the identifier.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, IdentifierInfo *Identifier,
|
||||
SourceLocation IdentifierLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'namespace::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param Namespace The namespace.
|
||||
///
|
||||
/// \param NamespaceLoc The location of the namespace name.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, NamespaceDecl *Namespace,
|
||||
SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'namespace-alias::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param Alias The namespace alias.
|
||||
///
|
||||
/// \param AliasLoc The location of the namespace alias
|
||||
/// name.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
|
||||
SourceLocation AliasLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Turn this (empty) nested-name-specifier into the global
|
||||
/// nested-name-specifier '::'.
|
||||
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Make a new nested-name-specifier from incomplete source-location
|
||||
/// information.
|
||||
///
|
||||
/// This routine should be used very, very rarely, in cases where we
|
||||
/// need to synthesize a nested-name-specifier. Most code should instead use
|
||||
/// \c Adopt() with a proper \c NestedNameSpecifierLoc.
|
||||
void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
|
||||
SourceRange R);
|
||||
|
||||
/// \brief Adopt an existing nested-name-specifier (with source-range
|
||||
/// information).
|
||||
void Adopt(NestedNameSpecifierLoc Other);
|
||||
|
||||
/// \brief Retrieve the source range covered by this nested-name-specifier.
|
||||
SourceRange getSourceRange() const {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
|
||||
}
|
||||
|
||||
/// \brief Retrieve a nested-name-specifier with location information,
|
||||
/// copied into the given AST context.
|
||||
///
|
||||
/// \param Context The context into which this nested-name-specifier will be
|
||||
/// copied.
|
||||
NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const;
|
||||
|
||||
/// \brief Retrieve a nested-name-specifier with location
|
||||
/// information based on the information in this builder. This loc
|
||||
/// will contain references to the builder's internal data and may
|
||||
/// be invalidated by any change to the builder.
|
||||
NestedNameSpecifierLoc getTemporary() const {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer);
|
||||
}
|
||||
|
||||
/// \brief Clear out this builder, and prepare it to build another
|
||||
/// nested-name-specifier with source-location information.
|
||||
void Clear() {
|
||||
Representation = 0;
|
||||
BufferSize = 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the underlying buffer.
|
||||
///
|
||||
/// \returns A pair containing a pointer to the buffer of source-location
|
||||
/// data and the size of the source-location data that resides in that
|
||||
/// buffer.
|
||||
std::pair<char *, unsigned> getBuffer() const {
|
||||
return std::make_pair(Buffer, BufferSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers
|
||||
/// into a diagnostic with <<.
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
NestedNameSpecifier *NNS) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
|
||||
DiagnosticsEngine::ak_nestednamespec);
|
||||
Diagnostic::ak_nestednamespec);
|
||||
return DB;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
//===- OperationKinds.h - Operation enums -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file enumerates the different kinds of operations that can be
|
||||
// performed by various expressions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_OPERATION_KINDS_H
|
||||
#define LLVM_CLANG_AST_OPERATION_KINDS_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// CastKind - The kind of operation required for a conversion.
|
||||
enum CastKind {
|
||||
/// CK_Dependent - A conversion which cannot yet be analyzed because
|
||||
/// either the expression or target type is dependent. These are
|
||||
/// created only for explicit casts; dependent ASTs aren't required
|
||||
/// to even approximately type-check.
|
||||
/// (T*) malloc(sizeof(T))
|
||||
/// reinterpret_cast<intptr_t>(A<T>::alloc());
|
||||
CK_Dependent,
|
||||
|
||||
/// CK_BitCast - A conversion which causes a bit pattern of one type
|
||||
/// to be reinterpreted as a bit pattern of another type. Generally
|
||||
/// the operands must have equivalent size and unrelated types.
|
||||
///
|
||||
/// The pointer conversion char* -> int* is a bitcast. A conversion
|
||||
/// from any pointer type to a C pointer type is a bitcast unless
|
||||
/// it's actually BaseToDerived or DerivedToBase. A conversion to a
|
||||
/// block pointer or ObjC pointer type is a bitcast only if the
|
||||
/// operand has the same type kind; otherwise, it's one of the
|
||||
/// specialized casts below.
|
||||
///
|
||||
/// Vector coercions are bitcasts.
|
||||
CK_BitCast,
|
||||
|
||||
/// CK_LValueBitCast - A conversion which reinterprets the address of
|
||||
/// an l-value as an l-value of a different kind. Used for
|
||||
/// reinterpret_casts of l-value expressions to reference types.
|
||||
/// bool b; reinterpret_cast<char&>(b) = 'a';
|
||||
CK_LValueBitCast,
|
||||
|
||||
/// CK_LValueToRValue - A conversion which causes the extraction of
|
||||
/// an r-value from the operand gl-value. The result of an r-value
|
||||
/// conversion is always unqualified.
|
||||
CK_LValueToRValue,
|
||||
|
||||
/// CK_GetObjCProperty - A conversion which calls an Objective-C
|
||||
/// property getter. The operand is an OK_ObjCProperty l-value; the
|
||||
/// result will generally be an r-value, but could be an ordinary
|
||||
/// gl-value if the property reference is to an implicit property
|
||||
/// for a method that returns a reference type.
|
||||
CK_GetObjCProperty,
|
||||
|
||||
/// CK_NoOp - A conversion which does not affect the type other than
|
||||
/// (possibly) adding qualifiers.
|
||||
/// int -> int
|
||||
/// char** -> const char * const *
|
||||
CK_NoOp,
|
||||
|
||||
/// CK_BaseToDerived - A conversion from a C++ class pointer/reference
|
||||
/// to a derived class pointer/reference.
|
||||
/// B *b = static_cast<B*>(a);
|
||||
CK_BaseToDerived,
|
||||
|
||||
/// CK_DerivedToBase - A conversion from a C++ class pointer
|
||||
/// to a base class pointer.
|
||||
/// A *a = new B();
|
||||
CK_DerivedToBase,
|
||||
|
||||
/// CK_UncheckedDerivedToBase - A conversion from a C++ class
|
||||
/// pointer/reference to a base class that can assume that the
|
||||
/// derived pointer is not null.
|
||||
/// const A &a = B();
|
||||
/// b->method_from_a();
|
||||
CK_UncheckedDerivedToBase,
|
||||
|
||||
/// CK_Dynamic - A C++ dynamic_cast.
|
||||
CK_Dynamic,
|
||||
|
||||
/// CK_ToUnion - The GCC cast-to-union extension.
|
||||
/// int -> union { int x; float y; }
|
||||
/// float -> union { int x; float y; }
|
||||
CK_ToUnion,
|
||||
|
||||
/// CK_ArrayToPointerDecay - Array to pointer decay.
|
||||
/// int[10] -> int*
|
||||
/// char[5][6] -> char(*)[6]
|
||||
CK_ArrayToPointerDecay,
|
||||
|
||||
/// CK_FunctionToPointerDecay - Function to pointer decay.
|
||||
/// void(int) -> void(*)(int)
|
||||
CK_FunctionToPointerDecay,
|
||||
|
||||
/// CK_NullToPointer - Null pointer constant to pointer, ObjC
|
||||
/// pointer, or block pointer.
|
||||
/// (void*) 0
|
||||
/// void (^block)() = 0;
|
||||
CK_NullToPointer,
|
||||
|
||||
/// CK_NullToMemberPointer - Null pointer constant to member pointer.
|
||||
/// int A::*mptr = 0;
|
||||
/// int (A::*fptr)(int) = nullptr;
|
||||
CK_NullToMemberPointer,
|
||||
|
||||
/// CK_BaseToDerivedMemberPointer - Member pointer in base class to
|
||||
/// member pointer in derived class.
|
||||
/// int B::*mptr = &A::member;
|
||||
CK_BaseToDerivedMemberPointer,
|
||||
|
||||
/// CK_DerivedToBaseMemberPointer - Member pointer in derived class to
|
||||
/// member pointer in base class.
|
||||
/// int A::*mptr = static_cast<int A::*>(&B::member);
|
||||
CK_DerivedToBaseMemberPointer,
|
||||
|
||||
/// CK_MemberPointerToBoolean - Member pointer to boolean. A check
|
||||
/// against the null member pointer.
|
||||
CK_MemberPointerToBoolean,
|
||||
|
||||
/// CK_UserDefinedConversion - Conversion using a user defined type
|
||||
/// conversion function.
|
||||
/// struct A { operator int(); }; int i = int(A());
|
||||
CK_UserDefinedConversion,
|
||||
|
||||
/// CK_ConstructorConversion - Conversion by constructor.
|
||||
/// struct A { A(int); }; A a = A(10);
|
||||
CK_ConstructorConversion,
|
||||
|
||||
/// CK_IntegralToPointer - Integral to pointer. A special kind of
|
||||
/// reinterpreting conversion. Applies to normal, ObjC, and block
|
||||
/// pointers.
|
||||
/// (char*) 0x1001aab0
|
||||
/// reinterpret_cast<int*>(0)
|
||||
CK_IntegralToPointer,
|
||||
|
||||
/// CK_PointerToIntegral - Pointer to integral. A special kind of
|
||||
/// reinterpreting conversion. Applies to normal, ObjC, and block
|
||||
/// pointers.
|
||||
/// (intptr_t) "help!"
|
||||
CK_PointerToIntegral,
|
||||
|
||||
/// CK_PointerToBoolean - Pointer to boolean conversion. A check
|
||||
/// against null. Applies to normal, ObjC, and block pointers.
|
||||
CK_PointerToBoolean,
|
||||
|
||||
/// CK_ToVoid - Cast to void, discarding the computed value.
|
||||
/// (void) malloc(2048)
|
||||
CK_ToVoid,
|
||||
|
||||
/// CK_VectorSplat - A conversion from an arithmetic type to a
|
||||
/// vector of that element type. Fills all elements ("splats") with
|
||||
/// the source value.
|
||||
/// __attribute__((ext_vector_type(4))) int v = 5;
|
||||
CK_VectorSplat,
|
||||
|
||||
/// CK_IntegralCast - A cast between integral types (other than to
|
||||
/// boolean). Variously a bitcast, a truncation, a sign-extension,
|
||||
/// or a zero-extension.
|
||||
/// long l = 5;
|
||||
/// (unsigned) i
|
||||
CK_IntegralCast,
|
||||
|
||||
/// CK_IntegralToBoolean - Integral to boolean. A check against zero.
|
||||
/// (bool) i
|
||||
CK_IntegralToBoolean,
|
||||
|
||||
/// CK_IntegralToFloating - Integral to floating point.
|
||||
/// float f = i;
|
||||
CK_IntegralToFloating,
|
||||
|
||||
/// CK_FloatingToIntegral - Floating point to integral. Rounds
|
||||
/// towards zero, discarding any fractional component.
|
||||
/// (int) f
|
||||
CK_FloatingToIntegral,
|
||||
|
||||
/// CK_FloatingToBoolean - Floating point to boolean.
|
||||
/// (bool) f
|
||||
CK_FloatingToBoolean,
|
||||
|
||||
/// CK_FloatingCast - Casting between floating types of different size.
|
||||
/// (double) f
|
||||
/// (float) ld
|
||||
CK_FloatingCast,
|
||||
|
||||
/// CK_CPointerToObjCPointerCast - Casting a C pointer kind to an
|
||||
/// Objective-C pointer.
|
||||
CK_CPointerToObjCPointerCast,
|
||||
|
||||
/// CK_BlockPointerToObjCPointerCast - Casting a block pointer to an
|
||||
/// ObjC pointer.
|
||||
CK_BlockPointerToObjCPointerCast,
|
||||
|
||||
/// CK_AnyPointerToBlockPointerCast - Casting any non-block pointer
|
||||
/// to a block pointer. Block-to-block casts are bitcasts.
|
||||
CK_AnyPointerToBlockPointerCast,
|
||||
|
||||
/// \brief Converting between two Objective-C object types, which
|
||||
/// can occur when performing reference binding to an Objective-C
|
||||
/// object.
|
||||
CK_ObjCObjectLValueCast,
|
||||
|
||||
/// \brief A conversion of a floating point real to a floating point
|
||||
/// complex of the original type. Injects the value as the real
|
||||
/// component with a zero imaginary component.
|
||||
/// float -> _Complex float
|
||||
CK_FloatingRealToComplex,
|
||||
|
||||
/// \brief Converts a floating point complex to floating point real
|
||||
/// of the source's element type. Just discards the imaginary
|
||||
/// component.
|
||||
/// _Complex long double -> long double
|
||||
CK_FloatingComplexToReal,
|
||||
|
||||
/// \brief Converts a floating point complex to bool by comparing
|
||||
/// against 0+0i.
|
||||
CK_FloatingComplexToBoolean,
|
||||
|
||||
/// \brief Converts between different floating point complex types.
|
||||
/// _Complex float -> _Complex double
|
||||
CK_FloatingComplexCast,
|
||||
|
||||
/// \brief Converts from a floating complex to an integral complex.
|
||||
/// _Complex float -> _Complex int
|
||||
CK_FloatingComplexToIntegralComplex,
|
||||
|
||||
/// \brief Converts from an integral real to an integral complex
|
||||
/// whose element type matches the source. Injects the value as
|
||||
/// the real component with a zero imaginary component.
|
||||
/// long -> _Complex long
|
||||
CK_IntegralRealToComplex,
|
||||
|
||||
/// \brief Converts an integral complex to an integral real of the
|
||||
/// source's element type by discarding the imaginary component.
|
||||
/// _Complex short -> short
|
||||
CK_IntegralComplexToReal,
|
||||
|
||||
/// \brief Converts an integral complex to bool by comparing against
|
||||
/// 0+0i.
|
||||
CK_IntegralComplexToBoolean,
|
||||
|
||||
/// \brief Converts between different integral complex types.
|
||||
/// _Complex char -> _Complex long long
|
||||
/// _Complex unsigned int -> _Complex signed int
|
||||
CK_IntegralComplexCast,
|
||||
|
||||
/// \brief Converts from an integral complex to a floating complex.
|
||||
/// _Complex unsigned -> _Complex float
|
||||
CK_IntegralComplexToFloatingComplex,
|
||||
|
||||
/// \brief [ARC] Produces a retainable object pointer so that it may
|
||||
/// be consumed, e.g. by being passed to a consuming parameter.
|
||||
/// Calls objc_retain.
|
||||
CK_ARCProduceObject,
|
||||
|
||||
/// \brief [ARC] Consumes a retainable object pointer that has just
|
||||
/// been produced, e.g. as the return value of a retaining call.
|
||||
/// Enters a cleanup to call objc_release at some indefinite time.
|
||||
CK_ARCConsumeObject,
|
||||
|
||||
/// \brief [ARC] Reclaim a retainable object pointer object that may
|
||||
/// have been produced and autoreleased as part of a function return
|
||||
/// sequence.
|
||||
CK_ARCReclaimReturnedObject,
|
||||
|
||||
/// \brief [ARC] Causes a value of block type to be copied to the
|
||||
/// heap, if it is not already there. A number of other operations
|
||||
/// in ARC cause blocks to be copied; this is for cases where that
|
||||
/// would not otherwise be guaranteed, such as when casting to a
|
||||
/// non-block pointer type.
|
||||
CK_ARCExtendBlockObject
|
||||
};
|
||||
|
||||
#define CK_Invalid ((CastKind) -1)
|
||||
|
||||
enum BinaryOperatorKind {
|
||||
// Operators listed in order of precedence.
|
||||
// Note that additions to this should also update the StmtVisitor class.
|
||||
BO_PtrMemD, BO_PtrMemI, // [C++ 5.5] Pointer-to-member operators.
|
||||
BO_Mul, BO_Div, BO_Rem, // [C99 6.5.5] Multiplicative operators.
|
||||
BO_Add, BO_Sub, // [C99 6.5.6] Additive operators.
|
||||
BO_Shl, BO_Shr, // [C99 6.5.7] Bitwise shift operators.
|
||||
BO_LT, BO_GT, BO_LE, BO_GE, // [C99 6.5.8] Relational operators.
|
||||
BO_EQ, BO_NE, // [C99 6.5.9] Equality operators.
|
||||
BO_And, // [C99 6.5.10] Bitwise AND operator.
|
||||
BO_Xor, // [C99 6.5.11] Bitwise XOR operator.
|
||||
BO_Or, // [C99 6.5.12] Bitwise OR operator.
|
||||
BO_LAnd, // [C99 6.5.13] Logical AND operator.
|
||||
BO_LOr, // [C99 6.5.14] Logical OR operator.
|
||||
BO_Assign, BO_MulAssign, // [C99 6.5.16] Assignment operators.
|
||||
BO_DivAssign, BO_RemAssign,
|
||||
BO_AddAssign, BO_SubAssign,
|
||||
BO_ShlAssign, BO_ShrAssign,
|
||||
BO_AndAssign, BO_XorAssign,
|
||||
BO_OrAssign,
|
||||
BO_Comma // [C99 6.5.17] Comma operator.
|
||||
};
|
||||
|
||||
enum UnaryOperatorKind {
|
||||
// Note that additions to this should also update the StmtVisitor class.
|
||||
UO_PostInc, UO_PostDec, // [C99 6.5.2.4] Postfix increment and decrement
|
||||
UO_PreInc, UO_PreDec, // [C99 6.5.3.1] Prefix increment and decrement
|
||||
UO_AddrOf, UO_Deref, // [C99 6.5.3.2] Address and indirection
|
||||
UO_Plus, UO_Minus, // [C99 6.5.3.3] Unary arithmetic
|
||||
UO_Not, UO_LNot, // [C99 6.5.3.3] Unary arithmetic
|
||||
UO_Real, UO_Imag, // "__real expr"/"__imag expr" Extension.
|
||||
UO_Extension // __extension__ marker.
|
||||
};
|
||||
|
||||
/// \brief The kind of bridging performed by the Objective-C bridge cast.
|
||||
enum ObjCBridgeCastKind {
|
||||
/// \brief Bridging via __bridge, which does nothing but reinterpret
|
||||
/// the bits.
|
||||
OBC_Bridge,
|
||||
/// \brief Bridging via __bridge_transfer, which transfers ownership of an
|
||||
/// Objective-C pointer into ARC.
|
||||
OBC_BridgeTransfer,
|
||||
/// \brief Bridging via __bridge_retain, which makes an ARC object available
|
||||
/// as a +1 C pointer.
|
||||
OBC_BridgeRetained
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -24,16 +24,8 @@ public:
|
||||
ParentMap(Stmt* ASTRoot);
|
||||
~ParentMap();
|
||||
|
||||
/// \brief Adds and/or updates the parent/child-relations of the complete
|
||||
/// stmt tree of S. All children of S including indirect descendants are
|
||||
/// visited and updated or inserted but not the parents of S.
|
||||
void addStmt(Stmt* S);
|
||||
|
||||
Stmt *getParent(Stmt*) const;
|
||||
Stmt *getParentIgnoreParens(Stmt *) const;
|
||||
Stmt *getParentIgnoreParenCasts(Stmt *) const;
|
||||
Stmt *getParentIgnoreParenImpCasts(Stmt *) const;
|
||||
Stmt *getOuterParenParent(Stmt *) const;
|
||||
|
||||
const Stmt *getParent(const Stmt* S) const {
|
||||
return getParent(const_cast<Stmt*>(S));
|
||||
@@ -43,10 +35,6 @@ public:
|
||||
return getParentIgnoreParens(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
const Stmt *getParentIgnoreParenCasts(const Stmt *S) const {
|
||||
return getParentIgnoreParenCasts(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
bool hasParent(Stmt* S) const {
|
||||
return getParent(S) != 0;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
#define LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
@@ -26,7 +27,7 @@ class LangOptions;
|
||||
class PrinterHelper {
|
||||
public:
|
||||
virtual ~PrinterHelper();
|
||||
virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0;
|
||||
virtual bool handledStmt(Stmt* E, llvm::raw_ostream& OS) = 0;
|
||||
};
|
||||
|
||||
/// \brief Describes how types, statements, expressions, and
|
||||
@@ -35,17 +36,14 @@ struct PrintingPolicy {
|
||||
/// \brief Create a default printing policy for C.
|
||||
PrintingPolicy(const LangOptions &LO)
|
||||
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
|
||||
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
|
||||
SuppressInitializers(false),
|
||||
Dump(false), ConstantArraySizeAsWritten(false),
|
||||
AnonymousTagLocations(true), SuppressStrongLifetime(false),
|
||||
Bool(LO.Bool) { }
|
||||
SuppressTag(false), SuppressTagKind(false), SuppressScope(false),
|
||||
Dump(false), ConstantArraySizeAsWritten(false) { }
|
||||
|
||||
/// \brief The number of spaces to use to indent each line.
|
||||
unsigned Indentation : 8;
|
||||
|
||||
/// \brief What language we're printing.
|
||||
LangOptions LangOpts;
|
||||
const LangOptions &LangOpts;
|
||||
|
||||
/// \brief Whether we should suppress printing of the actual specifiers for
|
||||
/// the given type or declaration.
|
||||
@@ -63,16 +61,6 @@ struct PrintingPolicy {
|
||||
/// "const int" type specifier and instead only print the "*y".
|
||||
bool SuppressSpecifiers : 1;
|
||||
|
||||
/// \brief Whether type printing should skip printing the tag keyword.
|
||||
///
|
||||
/// This is used when printing the inner type of elaborated types,
|
||||
/// (as the tag keyword is part of the elaborated type):
|
||||
///
|
||||
/// \code
|
||||
/// struct Geometry::Point;
|
||||
/// \endcode
|
||||
bool SuppressTagKeyword : 1;
|
||||
|
||||
/// \brief Whether type printing should skip printing the actual tag type.
|
||||
///
|
||||
/// This is used when the caller needs to print a tag definition in front
|
||||
@@ -83,22 +71,13 @@ struct PrintingPolicy {
|
||||
/// \endcode
|
||||
bool SuppressTag : 1;
|
||||
|
||||
/// \brief If we are printing a tag type, suppresses printing of the
|
||||
/// kind of tag, e.g., "struct", "union", "enum".
|
||||
bool SuppressTagKind : 1;
|
||||
|
||||
/// \brief Suppresses printing of scope specifiers.
|
||||
bool SuppressScope : 1;
|
||||
|
||||
/// \brief Suppress printing of variable initializers.
|
||||
///
|
||||
/// This flag is used when printing the loop variable in a for-range
|
||||
/// statement. For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// for (auto x : coll)
|
||||
/// \endcode
|
||||
///
|
||||
/// SuppressInitializers will be true when printing "auto x", so that the
|
||||
/// internal initializer constructed for x will not be printed.
|
||||
bool SuppressInitializers : 1;
|
||||
|
||||
/// \brief True when we are "dumping" rather than "pretty-printing",
|
||||
/// where dumping involves printing the internal details of the AST
|
||||
/// and pretty-printing involves printing something similar to
|
||||
@@ -122,19 +101,6 @@ struct PrintingPolicy {
|
||||
/// char a[9] = "A string";
|
||||
/// \endcode
|
||||
bool ConstantArraySizeAsWritten : 1;
|
||||
|
||||
/// \brief When printing an anonymous tag name, also print the location of
|
||||
/// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just
|
||||
/// prints "<anonymous>" for the name.
|
||||
bool AnonymousTagLocations : 1;
|
||||
|
||||
/// \brief When true, suppress printing of the __strong lifetime qualifier in
|
||||
/// ARC.
|
||||
unsigned SuppressStrongLifetime : 1;
|
||||
|
||||
/// \brief Whether we can use 'bool' rather than '_Bool', even if the language
|
||||
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
|
||||
unsigned Bool : 1;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user