Vendor import of clang trunk r256633:
https://llvm.org/svn/llvm-project/cfe/trunk@256633
This commit is contained in:
parent
7e86edd64b
commit
45b533945f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=292920 svn path=/vendor/clang/clang-trunk-r256633/; revision=292923; tag=vendor/clang/clang-trunk-r256633
230
CMakeLists.txt
230
CMakeLists.txt
@ -96,6 +96,7 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
||||
|
||||
option(LLVM_FORCE_USE_OLD_HOST_TOOLCHAIN
|
||||
"Set to ON to force using an old, unsupported host toolchain." OFF)
|
||||
option(CLANG_ENABLE_BOOTSTRAP "Generate the clang bootstrap target" OFF)
|
||||
|
||||
include(AddLLVM)
|
||||
include(TableGen)
|
||||
@ -115,6 +116,19 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} )
|
||||
|
||||
if(LLVM_INCLUDE_TESTS)
|
||||
set(Python_ADDITIONAL_VERSIONS 2.7)
|
||||
include(FindPythonInterp)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"Unable to find Python interpreter, required for builds and testing.
|
||||
|
||||
Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
|
||||
endif()
|
||||
|
||||
if( ${PYTHON_VERSION_STRING} VERSION_LESS 2.7 )
|
||||
message(FATAL_ERROR "Python 2.7 or newer is required")
|
||||
endif()
|
||||
|
||||
# Check prebuilt llvm/utils.
|
||||
if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
|
||||
AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/count${CMAKE_EXECUTABLE_SUFFIX}
|
||||
@ -167,7 +181,7 @@ else()
|
||||
set(BACKEND_PACKAGE_STRING "${PACKAGE_STRING}")
|
||||
endif()
|
||||
|
||||
find_package(LibXml2)
|
||||
find_package(LibXml2 2.5.3 QUIET)
|
||||
if (LIBXML2_FOUND)
|
||||
set(CLANG_HAVE_LIBXML 1)
|
||||
endif()
|
||||
@ -182,7 +196,7 @@ set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." )
|
||||
set(DEFAULT_SYSROOT "" CACHE PATH
|
||||
"Default <path> to all compiler invocations for --sysroot=<path>." )
|
||||
|
||||
set(CLANG_DEFAULT_OPENMP_RUNTIME "libgomp" CACHE STRING
|
||||
set(CLANG_DEFAULT_OPENMP_RUNTIME "libomp" CACHE STRING
|
||||
"Default OpenMP runtime used by -fopenmp.")
|
||||
|
||||
set(CLANG_VENDOR "" CACHE STRING
|
||||
@ -252,7 +266,10 @@ configure_file(
|
||||
|
||||
# Add appropriate flags for GCC
|
||||
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -fno-strict-aliasing")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual")
|
||||
if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
|
||||
endif ()
|
||||
|
||||
# Enable -pedantic for Clang even if it's not enabled for LLVM.
|
||||
if (NOT LLVM_ENABLE_PEDANTIC)
|
||||
@ -331,9 +348,13 @@ macro(set_clang_windows_version_resource_properties name)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(add_clang_subdirectory name)
|
||||
add_llvm_subdirectory(CLANG TOOL ${name})
|
||||
endmacro()
|
||||
|
||||
macro(add_clang_library name)
|
||||
cmake_parse_arguments(ARG
|
||||
""
|
||||
"SHARED"
|
||||
""
|
||||
"ADDITIONAL_HEADERS"
|
||||
${ARGN})
|
||||
@ -358,7 +379,7 @@ macro(add_clang_library name)
|
||||
set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
|
||||
|
||||
if(headers OR tds)
|
||||
set(srcs ${headers} ${tds})
|
||||
set(srcs ${headers} ${tds})
|
||||
endif()
|
||||
endif()
|
||||
endif(MSVC_IDE OR XCODE)
|
||||
@ -369,17 +390,29 @@ macro(add_clang_library name)
|
||||
${ARG_ADDITIONAL_HEADERS} # It may contain unparsed unknown args.
|
||||
)
|
||||
endif()
|
||||
llvm_add_library(${name} ${ARG_UNPARSED_ARGUMENTS} ${srcs})
|
||||
if(ARG_SHARED)
|
||||
set(ARG_ENABLE_SHARED SHARED)
|
||||
endif()
|
||||
llvm_add_library(${name} ${ARG_ENABLE_SHARED} ${ARG_UNPARSED_ARGUMENTS} ${srcs})
|
||||
|
||||
if(TARGET ${name})
|
||||
target_link_libraries(${name} ${cmake_2_8_12_INTERFACE} ${LLVM_COMMON_LIBS})
|
||||
|
||||
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "libclang")
|
||||
install(TARGETS ${name}
|
||||
COMPONENT ${name}
|
||||
EXPORT ClangTargets
|
||||
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
RUNTIME DESTINATION bin)
|
||||
|
||||
if (${ARG_SHARED} AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
add_custom_target(install-${name}
|
||||
DEPENDS ${name}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${name}
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
endif()
|
||||
endif()
|
||||
set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name})
|
||||
else()
|
||||
@ -397,6 +430,12 @@ macro(add_clang_executable name)
|
||||
set_clang_windows_version_resource_properties(${name})
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
macro(add_clang_symlink name dest)
|
||||
add_llvm_tool_symlink(${name} ${dest} ALWAYS_GENERATE)
|
||||
# Always generate install targets
|
||||
llvm_install_symlink(${name} ${dest} ALWAYS_GENERATE)
|
||||
endmacro()
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
include_directories(BEFORE
|
||||
@ -423,13 +462,28 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(INTERNAL_INSTALL_PREFIX)
|
||||
set(LIBCLANG_HEADERS_INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/include")
|
||||
else()
|
||||
set(LIBCLANG_HEADERS_INSTALL_DESTINATION include)
|
||||
endif()
|
||||
|
||||
install(DIRECTORY include/clang-c
|
||||
DESTINATION include
|
||||
COMPONENT libclang-headers
|
||||
DESTINATION "${LIBCLANG_HEADERS_INSTALL_DESTINATION}"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's.
|
||||
add_custom_target(install-libclang-headers
|
||||
DEPENDS
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=libclang-headers
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
endif()
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
|
||||
@ -467,6 +521,10 @@ set(LIBCLANG_LIBRARY_VERSION
|
||||
"Version number that will be placed into the libclang library , in the form XX.YY")
|
||||
mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
|
||||
|
||||
option(CLANG_INCLUDE_TESTS
|
||||
"Generate build targets for the Clang unit tests."
|
||||
${LLVM_INCLUDE_TESTS})
|
||||
|
||||
add_subdirectory(utils/TableGen)
|
||||
|
||||
add_subdirectory(include)
|
||||
@ -487,10 +545,6 @@ else()
|
||||
endif()
|
||||
add_subdirectory(examples)
|
||||
|
||||
option(CLANG_INCLUDE_TESTS
|
||||
"Generate build targets for the Clang unit tests."
|
||||
${LLVM_INCLUDE_TESTS})
|
||||
|
||||
if( CLANG_INCLUDE_TESTS )
|
||||
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include/gtest/gtest.h)
|
||||
add_subdirectory(unittests)
|
||||
@ -516,6 +570,7 @@ if( CLANG_INCLUDE_TESTS )
|
||||
ARGS ${LLVM_LIT_EXTRA_ARGS}
|
||||
)
|
||||
endif()
|
||||
add_subdirectory(utils/perf-training)
|
||||
endif()
|
||||
|
||||
option(CLANG_INCLUDE_DOCS "Generate build targets for the Clang docs."
|
||||
@ -527,7 +582,8 @@ endif()
|
||||
set(CLANG_ORDER_FILE "" CACHE FILEPATH
|
||||
"Order file to use when compiling clang in order to improve startup time.")
|
||||
|
||||
if (CLANG_BUILT_STANDALONE)
|
||||
if (CLANG_BUILT_STANDALONE OR CMAKE_VERSION VERSION_EQUAL 3 OR
|
||||
CMAKE_VERSION VERSION_GREATER 3)
|
||||
# Generate a list of CMake library targets so that other CMake projects can
|
||||
# link against them. LLVM calls its version of this file LLVMExports.cmake, but
|
||||
# the usual CMake convention seems to be ${Project}Targets.cmake.
|
||||
@ -551,3 +607,153 @@ if (CLANG_BUILT_STANDALONE)
|
||||
${CLANG_BINARY_DIR}/share/clang/cmake/ClangConfig.cmake
|
||||
COPYONLY)
|
||||
endif ()
|
||||
|
||||
if (CLANG_ENABLE_BOOTSTRAP)
|
||||
include(ExternalProject)
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.1.0)
|
||||
set(cmake_3_1_EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL 1)
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.3.20150708)
|
||||
set(cmake_3_4_USES_TERMINAL_OPTIONS
|
||||
USES_TERMINAL_CONFIGURE 1
|
||||
USES_TERMINAL_BUILD 1
|
||||
USES_TERMINAL_INSTALL 1
|
||||
)
|
||||
set(cmake_3_4_USES_TERMINAL USES_TERMINAL 1)
|
||||
endif()
|
||||
|
||||
if(NOT CLANG_STAGE)
|
||||
set(CLANG_STAGE stage1)
|
||||
message(STATUS "Setting current clang stage to: ${CLANG_STAGE}")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH "stage([0-9]*)" MATCHED_STAGE "${CLANG_STAGE}")
|
||||
if(MATCHED_STAGE)
|
||||
math(EXPR STAGE_NUM "${MATCHED_STAGE} + 1")
|
||||
set(NEXT_CLANG_STAGE stage${STAGE_NUM})
|
||||
else()
|
||||
set(NEXT_CLANG_STAGE bootstrap)
|
||||
endif()
|
||||
message(STATUS "Setting next clang stage to: ${NEXT_CLANG_STAGE}")
|
||||
|
||||
|
||||
set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-stamps/)
|
||||
set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-bins/)
|
||||
|
||||
# If on Darwin we need to make bootstrap depend on LTO and pass
|
||||
# DARWIN_LTO_LIBRARY so that -flto will work using the just-built compiler
|
||||
if(APPLE)
|
||||
set(LTO_DEP LTO llvm-ar llvm-ranlib)
|
||||
set(LTO_LIBRARY -DDARWIN_LTO_LIBRARY=${LLVM_SHLIB_OUTPUT_INTDIR}/libLTO.dylib)
|
||||
set(LTO_AR -DCMAKE_AR=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ar)
|
||||
set(LTO_RANLIB -DCMAKE_RANLIB=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ranlib)
|
||||
endif()
|
||||
|
||||
add_custom_target(${NEXT_CLANG_STAGE}-clear
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-cleared
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-cleared
|
||||
DEPENDS clang ${LTO_DEP}
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${BINARY_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${STAMP_DIR}
|
||||
COMMENT "Clobberring ${NEXT_CLANG_STAGE} build and stamp directories"
|
||||
)
|
||||
|
||||
if(CMAKE_VERBOSE_MAKEFILE)
|
||||
set(verbose -DCMAKE_VERBOSE_MAKEFILE=On)
|
||||
endif()
|
||||
|
||||
set(BOOTSTRAP_DEFAULT_PASSTHROUGH
|
||||
PACKAGE_VERSION
|
||||
LLVM_VERSION_MAJOR
|
||||
LLVM_VERSION_MINOR
|
||||
LLVM_VERSION_PATCH
|
||||
LLVM_VERSION_SUFFIX
|
||||
CLANG_REPOSITORY_STRING
|
||||
CMAKE_MAKE_PROGRAM)
|
||||
|
||||
if(TARGET compiler-rt)
|
||||
set(RUNTIME_DEP compiler-rt)
|
||||
endif()
|
||||
|
||||
# Find all variables that start with BOOTSTRAP_ and populate a variable with
|
||||
# them.
|
||||
get_cmake_property(variableNames VARIABLES)
|
||||
foreach(variableName ${variableNames})
|
||||
if(variableName MATCHES "^BOOTSTRAP_")
|
||||
string(SUBSTRING ${variableName} 10 -1 varName)
|
||||
string(REPLACE ";" "\;" value "${${variableName}}")
|
||||
list(APPEND PASSTHROUGH_VARIABLES
|
||||
-D${varName}=${value})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Populate the passthrough variables
|
||||
foreach(variableName ${CLANG_BOOTSTRAP_PASSTHROUGH} ${BOOTSTRAP_DEFAULT_PASSTHROUGH})
|
||||
if(${variableName})
|
||||
string(REPLACE ";" "\;" value ${${variableName}})
|
||||
list(APPEND PASSTHROUGH_VARIABLES
|
||||
-D${variableName}=${value})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
ExternalProject_Add(${NEXT_CLANG_STAGE}
|
||||
DEPENDS clang ${LTO_DEP} ${RUNTIME_DEP}
|
||||
PREFIX ${NEXT_CLANG_STAGE}
|
||||
SOURCE_DIR ${CMAKE_SOURCE_DIR}
|
||||
STAMP_DIR ${STAMP_DIR}
|
||||
BINARY_DIR ${BINARY_DIR}
|
||||
${cmake_3_1_EXCLUDE_FROM_ALL}
|
||||
CMAKE_ARGS
|
||||
# We shouldn't need to set this here, but INSTALL_DIR doesn't
|
||||
# seem to work, so instead I'm passing this through
|
||||
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
|
||||
${CLANG_BOOTSTRAP_CMAKE_ARGS}
|
||||
${PASSTHROUGH_VARIABLES}
|
||||
-DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++
|
||||
-DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
|
||||
-DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
|
||||
-DCLANG_STAGE=${NEXT_CLANG_STAGE}
|
||||
${LTO_LIBRARY} ${LTO_AR} ${LTO_RANLIB} ${verbose}
|
||||
INSTALL_COMMAND ""
|
||||
STEP_TARGETS configure build
|
||||
${cmake_3_4_USES_TERMINAL_OPTIONS}
|
||||
)
|
||||
|
||||
# exclude really-install from main target
|
||||
set_target_properties(${NEXT_CLANG_STAGE} PROPERTIES _EP_really-install_EXCLUDE_FROM_MAIN On)
|
||||
ExternalProject_Add_Step(${NEXT_CLANG_STAGE} really-install
|
||||
COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target install
|
||||
COMMENT "Performing install step for '${NEXT_CLANG_STAGE}'"
|
||||
DEPENDEES build
|
||||
${cmake_3_4_USES_TERMINAL}
|
||||
)
|
||||
ExternalProject_Add_StepTargets(${NEXT_CLANG_STAGE} really-install)
|
||||
add_custom_target(${NEXT_CLANG_STAGE}-install DEPENDS ${NEXT_CLANG_STAGE}-really-install)
|
||||
|
||||
if(NOT CLANG_BOOTSTRAP_TARGETS)
|
||||
set(CLANG_BOOTSTRAP_TARGETS check-llvm check-clang check-all)
|
||||
endif()
|
||||
foreach(target ${CLANG_BOOTSTRAP_TARGETS})
|
||||
# exclude from main target
|
||||
set_target_properties(${NEXT_CLANG_STAGE} PROPERTIES _EP_${target}_EXCLUDE_FROM_MAIN On)
|
||||
|
||||
ExternalProject_Add_Step(${NEXT_CLANG_STAGE} ${target}
|
||||
COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target ${target}
|
||||
COMMENT "Performing ${target} for '${NEXT_CLANG_STAGE}'"
|
||||
DEPENDEES configure
|
||||
${cmake_3_4_USES_TERMINAL}
|
||||
)
|
||||
|
||||
if(target MATCHES "^stage[0-9]*")
|
||||
add_custom_target(${target} DEPENDS ${NEXT_CLANG_STAGE}-${target})
|
||||
endif()
|
||||
|
||||
ExternalProject_Add_StepTargets(${NEXT_CLANG_STAGE} ${target})
|
||||
endforeach()
|
||||
endif()
|
||||
|
@ -33,22 +33,22 @@ N: Reid Kleckner
|
||||
E: rnk@google.com
|
||||
D: Microsoft C++ ABI compatibility and general Windows support
|
||||
|
||||
N: Manuel Klimek
|
||||
E: klimek@google.com
|
||||
D: AST matchers, LibTooling
|
||||
|
||||
N: Anton Korobeynikov
|
||||
E: anton@korobeynikov.info
|
||||
D: Exception handling, Windows codegen, ARM EABI
|
||||
|
||||
N: Ted Kremenek
|
||||
E: kremenek@apple.com
|
||||
N: Anna Zaks
|
||||
E: ganna@apple.com
|
||||
D: Clang Static Analyzer
|
||||
|
||||
N: John McCall
|
||||
E: rjmccall@apple.com
|
||||
D: Clang LLVM IR generation
|
||||
|
||||
N: Chad Rosier
|
||||
E: mcrosier@codeaurora.org
|
||||
D: Compiler driver
|
||||
|
||||
N: Richard Smith
|
||||
E: richard@metafoo.co.uk
|
||||
D: All parts of Clang not covered by someone else
|
||||
|
@ -44,6 +44,5 @@ From inside the Clang build directory, run 'make install' to install the Clang
|
||||
compiler and header files into the prefix directory selected when LLVM was
|
||||
configured.
|
||||
|
||||
The Clang compiler is available as 'clang' and 'clang++'. It supports a gcc like command line
|
||||
interface. See the man page for clang (installed into $prefix/share/man/man1)
|
||||
for more information.
|
||||
The Clang compiler is available as 'clang' and 'clang++'. It supports a gcc like
|
||||
command line interface. See the man page for clang for more information.
|
||||
|
5
Makefile
5
Makefile
@ -67,8 +67,11 @@ endif
|
||||
# http://gcc.gnu.org/PR41874
|
||||
# http://gcc.gnu.org/PR41838
|
||||
#
|
||||
# We can revisit this when LLVM/Clang support it.
|
||||
# We don't need to do this if the host compiler is clang.
|
||||
ifneq ($(CXX_COMPILER), "clang")
|
||||
CXX.Flags += -fno-strict-aliasing
|
||||
endif
|
||||
|
||||
|
||||
# Set up Clang's tblgen.
|
||||
ifndef CLANG_TBLGEN
|
||||
|
@ -1100,6 +1100,11 @@ def __repr__(self):
|
||||
CursorKind.CUDAHOST_ATTR = CursorKind(415)
|
||||
CursorKind.CUDASHARED_ATTR = CursorKind(416)
|
||||
|
||||
CursorKind.VISIBILITY_ATTR = CursorKind(417)
|
||||
|
||||
CursorKind.DLLEXPORT_ATTR = CursorKind(418)
|
||||
CursorKind.DLLIMPORT_ATTR = CursorKind(419)
|
||||
|
||||
###
|
||||
# Preprocessing
|
||||
CursorKind.PREPROCESSING_DIRECTIVE = CursorKind(500)
|
||||
@ -1112,7 +1117,8 @@ def __repr__(self):
|
||||
|
||||
# A module import declaration.
|
||||
CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
|
||||
|
||||
# A type alias template declaration
|
||||
CursorKind.TYPE_ALIAS_TEMPLATE_DECL = CursorKind(601)
|
||||
|
||||
### Template Argument Kinds ###
|
||||
class TemplateArgumentKind(BaseEnumeration):
|
||||
@ -1162,12 +1168,36 @@ def is_definition(self):
|
||||
"""
|
||||
return conf.lib.clang_isCursorDefinition(self)
|
||||
|
||||
def is_const_method(self):
|
||||
"""Returns True if the cursor refers to a C++ member function or member
|
||||
function template that is declared 'const'.
|
||||
"""
|
||||
return conf.lib.clang_CXXMethod_isConst(self)
|
||||
|
||||
def is_mutable_field(self):
|
||||
"""Returns True if the cursor refers to a C++ field that is declared
|
||||
'mutable'.
|
||||
"""
|
||||
return conf.lib.clang_CXXField_isMutable(self)
|
||||
|
||||
def is_pure_virtual_method(self):
|
||||
"""Returns True if the cursor refers to a C++ member function or member
|
||||
function template that is declared pure virtual.
|
||||
"""
|
||||
return conf.lib.clang_CXXMethod_isPureVirtual(self)
|
||||
|
||||
def is_static_method(self):
|
||||
"""Returns True if the cursor refers to a C++ member function or member
|
||||
function template that is declared 'static'.
|
||||
"""
|
||||
return conf.lib.clang_CXXMethod_isStatic(self)
|
||||
|
||||
def is_virtual_method(self):
|
||||
"""Returns True if the cursor refers to a C++ member function or member
|
||||
function template that is declared 'virtual'.
|
||||
"""
|
||||
return conf.lib.clang_CXXMethod_isVirtual(self)
|
||||
|
||||
def get_definition(self):
|
||||
"""
|
||||
If the cursor is a reference to a declaration or a declaration of
|
||||
@ -1673,6 +1703,7 @@ def __repr__(self):
|
||||
TypeKind.VARIABLEARRAY = TypeKind(115)
|
||||
TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
|
||||
TypeKind.MEMBERPOINTER = TypeKind(117)
|
||||
TypeKind.AUTO = TypeKind(118)
|
||||
|
||||
class RefQualifierKind(BaseEnumeration):
|
||||
"""Describes a specific ref-qualifier of a type."""
|
||||
@ -2877,6 +2908,14 @@ def cursor(self):
|
||||
[Index, c_char_p],
|
||||
c_object_p),
|
||||
|
||||
("clang_CXXField_isMutable",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_CXXMethod_isConst",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_CXXMethod_isPureVirtual",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
@ -97,6 +97,36 @@ def test_canonical():
|
||||
assert len(cursors) == 3
|
||||
assert cursors[1].canonical == cursors[2].canonical
|
||||
|
||||
def test_is_const_method():
|
||||
"""Ensure Cursor.is_const_method works."""
|
||||
source = 'class X { void foo() const; void bar(); };'
|
||||
tu = get_tu(source, lang='cpp')
|
||||
|
||||
cls = get_cursor(tu, 'X')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
bar = get_cursor(tu, 'bar')
|
||||
assert cls is not None
|
||||
assert foo is not None
|
||||
assert bar is not None
|
||||
|
||||
assert foo.is_const_method()
|
||||
assert not bar.is_const_method()
|
||||
|
||||
def test_is_mutable_field():
|
||||
"""Ensure Cursor.is_mutable_field works."""
|
||||
source = 'class X { int x_; mutable int y_; };'
|
||||
tu = get_tu(source, lang='cpp')
|
||||
|
||||
cls = get_cursor(tu, 'X')
|
||||
x_ = get_cursor(tu, 'x_')
|
||||
y_ = get_cursor(tu, 'y_')
|
||||
assert cls is not None
|
||||
assert x_ is not None
|
||||
assert y_ is not None
|
||||
|
||||
assert not x_.is_mutable_field()
|
||||
assert y_.is_mutable_field()
|
||||
|
||||
def test_is_static_method():
|
||||
"""Ensure Cursor.is_static_method works."""
|
||||
|
||||
@ -113,6 +143,36 @@ def test_is_static_method():
|
||||
assert foo.is_static_method()
|
||||
assert not bar.is_static_method()
|
||||
|
||||
def test_is_pure_virtual_method():
|
||||
"""Ensure Cursor.is_pure_virtual_method works."""
|
||||
source = 'class X { virtual void foo() = 0; virtual void bar(); };'
|
||||
tu = get_tu(source, lang='cpp')
|
||||
|
||||
cls = get_cursor(tu, 'X')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
bar = get_cursor(tu, 'bar')
|
||||
assert cls is not None
|
||||
assert foo is not None
|
||||
assert bar is not None
|
||||
|
||||
assert foo.is_pure_virtual_method()
|
||||
assert not bar.is_pure_virtual_method()
|
||||
|
||||
def test_is_virtual_method():
|
||||
"""Ensure Cursor.is_virtual_method works."""
|
||||
source = 'class X { virtual void foo(); void bar(); };'
|
||||
tu = get_tu(source, lang='cpp')
|
||||
|
||||
cls = get_cursor(tu, 'X')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
bar = get_cursor(tu, 'bar')
|
||||
assert cls is not None
|
||||
assert foo is not None
|
||||
assert bar is not None
|
||||
|
||||
assert foo.is_virtual_method()
|
||||
assert not bar.is_virtual_method()
|
||||
|
||||
def test_underlying_type():
|
||||
tu = get_tu('typedef int foo;')
|
||||
typedef = get_cursor(tu, 'foo')
|
||||
|
@ -13,6 +13,7 @@ def test_get_all_kinds():
|
||||
assert CursorKind.OBJ_SELF_EXPR in kinds
|
||||
assert CursorKind.MS_ASM_STMT in kinds
|
||||
assert CursorKind.MODULE_IMPORT_DECL in kinds
|
||||
assert CursorKind.TYPE_ALIAS_TEMPLATE_DECL in kinds
|
||||
|
||||
def test_kind_groups():
|
||||
"""Check that every kind classifies to exactly one group."""
|
||||
|
@ -134,7 +134,7 @@ def test_equal():
|
||||
|
||||
def test_type_spelling():
|
||||
"""Ensure Type.spelling works."""
|
||||
tu = get_tu('int c[5]; int i[]; int x; int v[x];')
|
||||
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
|
||||
c = get_cursor(tu, 'c')
|
||||
i = get_cursor(tu, 'i')
|
||||
x = get_cursor(tu, 'x')
|
||||
@ -253,7 +253,7 @@ def test_function_variadic():
|
||||
|
||||
def test_element_type():
|
||||
"""Ensure Type.element_type works."""
|
||||
tu = get_tu('int c[5]; int i[]; int x; int v[x];')
|
||||
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
|
||||
c = get_cursor(tu, 'c')
|
||||
i = get_cursor(tu, 'i')
|
||||
v = get_cursor(tu, 'v')
|
||||
|
32
cmake/caches/Apple-stage1.cmake
Normal file
32
cmake/caches/Apple-stage1.cmake
Normal file
@ -0,0 +1,32 @@
|
||||
# This file sets up a CMakeCache for Apple-style bootstrap builds. It can be
|
||||
# used on any Darwin system to approximate Apple Clang builds.
|
||||
|
||||
if($ENV{DT_TOOLCHAIN_DIR})
|
||||
set(CMAKE_INSTALL_PREFIX $ENV{DT_TOOLCHAIN_DIR}/usr/)
|
||||
else()
|
||||
set(CMAKE_INSTALL_PREFIX /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.toolchain/usr/)
|
||||
endif()
|
||||
|
||||
set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
|
||||
set(CLANG_VENDOR Apple CACHE STRING "")
|
||||
set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_UTILS OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
|
||||
set(CLANG_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "")
|
||||
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
|
||||
set(PACKAGE_VERSION 7.1.0 CACHE STRING "")
|
||||
|
||||
# LIBCXX Settings
|
||||
set(LIBCXX_INSTALL_LIBRARY OFF CACHE BOOL "")
|
||||
set(LIBCXX_INSTALL_HEADERS ON CACHE BOOL "")
|
||||
set(LIBCXX_OVERRIDE_DARWIN_INSTALL ON CACHE BOOL "")
|
||||
|
||||
#bootstrap
|
||||
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
|
||||
set(CLANG_BOOTSTRAP_CMAKE_ARGS
|
||||
-C ${CMAKE_CURRENT_LIST_DIR}/Apple-stage2.cmake
|
||||
CACHE STRING "")
|
30
cmake/caches/Apple-stage2.cmake
Normal file
30
cmake/caches/Apple-stage2.cmake
Normal file
@ -0,0 +1,30 @@
|
||||
# This file sets up a CMakeCache for Apple-style stage2 bootstrap. It is
|
||||
# specified by the stage1 build.
|
||||
|
||||
set(LLVM_TARGETS_TO_BUILD X86 ARM AArch64 CACHE STRING "")
|
||||
set(CLANG_VENDOR Apple CACHE STRING "")
|
||||
set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_UTILS OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
|
||||
set(CLANG_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "")
|
||||
set(CLANG_LINKS_TO_CREATE clang++ cc c++ CACHE STRING "")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -flto -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-Os -flto -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
|
||||
set(PACKAGE_VERSION 7.1.0 CACHE STRING "")
|
||||
|
||||
set(LIBCXX_INSTALL_LIBRARY OFF CACHE BOOL "")
|
||||
set(LIBCXX_INSTALL_HEADERS OFF CACHE BOOL "")
|
||||
|
||||
# setup toolchain
|
||||
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
|
||||
set(LLVM_TOOLCHAIN_TOOLS
|
||||
llvm-dsymutil
|
||||
llvm-cov
|
||||
llvm-dwarfdump
|
||||
llvm-profdata
|
||||
CACHE STRING "")
|
18
cmake/caches/README.txt
Normal file
18
cmake/caches/README.txt
Normal file
@ -0,0 +1,18 @@
|
||||
CMake Caches
|
||||
============
|
||||
|
||||
This directory contains CMake cache scripts that pre-populate the CMakeCache in
|
||||
a build directory with commonly used settings.
|
||||
|
||||
The first two cache files in the directory are used by Apple to build the clang
|
||||
distribution packaged with Xcode. You can use the caches with the following
|
||||
CMake invocation:
|
||||
|
||||
cmake -G <build system>
|
||||
-C <path to llvm>/tools/clang/cmake/caches/Apple-stage1.cmake
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
[-DCMAKE_INSTALL_PREFIX=<install path>]
|
||||
<path to llvm>
|
||||
|
||||
Building the `bootstrap` target from this generation will build clang, and
|
||||
`bootstrap-install` will install it.
|
@ -196,12 +196,11 @@ Disabling Instrumentation with ``__attribute__((no_sanitize("address")))``
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Some code should not be instrumented by AddressSanitizer. One may use the
|
||||
function attribute ``__attribute__((no_sanitize("address")))``
|
||||
(which has deprecated synonyms
|
||||
:ref:`no_sanitize_address <langext-address_sanitizer>` and
|
||||
`no_address_safety_analysis`) to disable instrumentation of a particular
|
||||
function. This attribute may not be supported by other compilers, so we suggest
|
||||
to use it together with ``__has_feature(address_sanitizer)``.
|
||||
function attribute ``__attribute__((no_sanitize("address")))`` (which has
|
||||
deprecated synonyms `no_sanitize_address` and `no_address_safety_analysis`) to
|
||||
disable instrumentation of a particular function. This attribute may not be
|
||||
supported by other compilers, so we suggest to use it together with
|
||||
``__has_feature(address_sanitizer)``.
|
||||
|
||||
Suppressing Errors in Recompiled Code (Blacklist)
|
||||
-------------------------------------------------
|
||||
@ -268,5 +267,4 @@ check-asan`` command.
|
||||
More Information
|
||||
================
|
||||
|
||||
`http://code.google.com/p/address-sanitizer <http://code.google.com/p/address-sanitizer/>`_
|
||||
|
||||
`<https://github.com/google/sanitizers/wiki/AddressSanitizer>`_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@ to format C/C++/Obj-C code.
|
||||
.. code-block:: console
|
||||
|
||||
$ clang-format -help
|
||||
OVERVIEW: A tool to format C/C++/Obj-C code.
|
||||
OVERVIEW: A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf code.
|
||||
|
||||
If no arguments are specified, it formats the code from standard input
|
||||
and writes the result to the standard output.
|
||||
@ -30,44 +30,53 @@ to format C/C++/Obj-C code.
|
||||
|
||||
Clang-format options:
|
||||
|
||||
-cursor=<uint> - The position of the cursor when invoking
|
||||
clang-format from an editor integration
|
||||
-dump-config - Dump configuration options to stdout and exit.
|
||||
Can be used with -style option.
|
||||
-i - Inplace edit <file>s, if specified.
|
||||
-length=<uint> - Format a range of this length (in bytes).
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -offset and -length pairs.
|
||||
When only a single -offset is specified without
|
||||
-length, clang-format will format up to the end
|
||||
of the file.
|
||||
Can only be used with one input file.
|
||||
-lines=<string> - <start line>:<end line> - format a range of
|
||||
lines (both 1-based).
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -lines arguments.
|
||||
Can't be used with -offset and -length.
|
||||
Can only be used with one input file.
|
||||
-offset=<uint> - Format a range starting at this byte offset.
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -offset and -length pairs.
|
||||
Can only be used with one input file.
|
||||
-output-replacements-xml - Output replacements as XML.
|
||||
-style=<string> - Coding style, currently supports:
|
||||
LLVM, Google, Chromium, Mozilla, WebKit.
|
||||
Use -style=file to load style configuration from
|
||||
.clang-format file located in one of the parent
|
||||
directories of the source file (or current
|
||||
directory for stdin).
|
||||
Use -style="{key: value, ...}" to set specific
|
||||
parameters, e.g.:
|
||||
-style="{BasedOnStyle: llvm, IndentWidth: 8}"
|
||||
-assume-filename=<string> - When reading from stdin, clang-format assumes this
|
||||
filename to look for a style config file (with
|
||||
-style=file) and to determine the language.
|
||||
-cursor=<uint> - The position of the cursor when invoking
|
||||
clang-format from an editor integration
|
||||
-dump-config - Dump configuration options to stdout and exit.
|
||||
Can be used with -style option.
|
||||
-fallback-style=<string> - The name of the predefined style used as a
|
||||
fallback in case clang-format is invoked with
|
||||
-style=file, but can not find the .clang-format
|
||||
file to use.
|
||||
Use -fallback-style=none to skip formatting.
|
||||
-i - Inplace edit <file>s, if specified.
|
||||
-length=<uint> - Format a range of this length (in bytes).
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -offset and -length pairs.
|
||||
When only a single -offset is specified without
|
||||
-length, clang-format will format up to the end
|
||||
of the file.
|
||||
Can only be used with one input file.
|
||||
-lines=<string> - <start line>:<end line> - format a range of
|
||||
lines (both 1-based).
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -lines arguments.
|
||||
Can't be used with -offset and -length.
|
||||
Can only be used with one input file.
|
||||
-offset=<uint> - Format a range starting at this byte offset.
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -offset and -length pairs.
|
||||
Can only be used with one input file.
|
||||
-output-replacements-xml - Output replacements as XML.
|
||||
-sort-includes - Sort touched include lines
|
||||
-style=<string> - Coding style, currently supports:
|
||||
LLVM, Google, Chromium, Mozilla, WebKit.
|
||||
Use -style=file to load style configuration from
|
||||
.clang-format file located in one of the parent
|
||||
directories of the source file (or current
|
||||
directory for stdin).
|
||||
Use -style="{key: value, ...}" to set specific
|
||||
parameters, e.g.:
|
||||
-style="{BasedOnStyle: llvm, IndentWidth: 8}"
|
||||
|
||||
General options:
|
||||
Generic Options:
|
||||
|
||||
-help - Display available options (-help-hidden for more)
|
||||
-help-list - Display list of available options (-help-list-hidden for more)
|
||||
-version - Display the version of this program
|
||||
-help - Display available options (-help-hidden for more)
|
||||
-help-list - Display list of available options (-help-list-hidden for more)
|
||||
-version - Display the version of this program
|
||||
|
||||
|
||||
When the desired code formatting style is different from the available options,
|
||||
|
@ -150,26 +150,61 @@ the configuration (without a prefix: ``Auto``).
|
||||
**AccessModifierOffset** (``int``)
|
||||
The extra indent or outdent of access modifiers, e.g. ``public:``.
|
||||
|
||||
**AlignAfterOpenBracket** (``bool``)
|
||||
**AlignAfterOpenBracket** (``BracketAlignmentStyle``)
|
||||
If ``true``, horizontally aligns arguments after an open bracket.
|
||||
|
||||
This applies to round brackets (parentheses), angle brackets and square
|
||||
brackets. This will result in formattings like
|
||||
\code
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
\endcode
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``BAS_Align`` (in configuration: ``Align``)
|
||||
Align parameters on the open bracket, e.g.:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
* ``BAS_DontAlign`` (in configuration: ``DontAlign``)
|
||||
Don't align, instead use ``ContinuationIndentWidth``, e.g.:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
* ``BAS_AlwaysBreak`` (in configuration: ``AlwaysBreak``)
|
||||
Always break after an open bracket, if the parameters don't fit
|
||||
on a single line, e.g.:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
someLongFunction(
|
||||
argument1, argument2);
|
||||
|
||||
|
||||
**AlignConsecutiveAssignments** (``bool``)
|
||||
If ``true``, aligns consecutive assignments.
|
||||
|
||||
This will align the assignment operators of consecutive lines. This
|
||||
will result in formattings like
|
||||
\code
|
||||
int aaaa = 12;
|
||||
int b = 23;
|
||||
int ccc = 23;
|
||||
\endcode
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int aaaa = 12;
|
||||
int b = 23;
|
||||
int ccc = 23;
|
||||
|
||||
**AlignConsecutiveDeclarations** (``bool``)
|
||||
If ``true``, aligns consecutive declarations.
|
||||
|
||||
This will align the declaration names of consecutive lines. This
|
||||
will result in formattings like
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int aaaa = 12;
|
||||
float b = 23;
|
||||
std::string ccc = 23;
|
||||
|
||||
**AlignEscapedNewlinesLeft** (``bool``)
|
||||
If ``true``, aligns escaped newlines as far left as possible.
|
||||
@ -219,7 +254,8 @@ the configuration (without a prefix: ``Auto``).
|
||||
single line.
|
||||
|
||||
**AlwaysBreakAfterDefinitionReturnType** (``DefinitionReturnTypeBreakingStyle``)
|
||||
The function definition return type breaking style to use.
|
||||
The function definition return type breaking style to use. This
|
||||
option is deprecated and is retained for backwards compatibility.
|
||||
|
||||
Possible values:
|
||||
|
||||
@ -229,7 +265,25 @@ the configuration (without a prefix: ``Auto``).
|
||||
* ``DRTBS_All`` (in configuration: ``All``)
|
||||
Always break after the return type.
|
||||
* ``DRTBS_TopLevel`` (in configuration: ``TopLevel``)
|
||||
Always break after the return types of top level functions.
|
||||
Always break after the return types of top-level functions.
|
||||
|
||||
|
||||
**AlwaysBreakAfterReturnType** (``ReturnTypeBreakingStyle``)
|
||||
The function declaration return type breaking style to use.
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``RTBS_None`` (in configuration: ``None``)
|
||||
Break after return type automatically.
|
||||
``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
|
||||
* ``RTBS_All`` (in configuration: ``All``)
|
||||
Always break after the return type.
|
||||
* ``RTBS_TopLevel`` (in configuration: ``TopLevel``)
|
||||
Always break after the return types of top-level functions.
|
||||
* ``RTBS_AllDefinitions`` (in configuration: ``AllDefinitions``)
|
||||
Always break after the return type of function definitions.
|
||||
* ``RTBS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``)
|
||||
Always break after the return type of top-level definitions.
|
||||
|
||||
|
||||
**AlwaysBreakBeforeMultilineStrings** (``bool``)
|
||||
@ -252,6 +306,30 @@ the configuration (without a prefix: ``Auto``).
|
||||
If ``false``, a function declaration's or function definition's
|
||||
parameters will either all be on the same line or will have one line each.
|
||||
|
||||
**BraceWrapping** (``BraceWrappingFlags``)
|
||||
Control of individual brace wrapping cases.
|
||||
|
||||
If ``BreakBeforeBraces`` is set to ``custom``, use this to specify how each
|
||||
individual brace case should be handled. Otherwise, this is ignored.
|
||||
|
||||
Nested configuration flags:
|
||||
|
||||
* ``bool AfterClass`` Wrap class definitions.
|
||||
* ``bool AfterControlStatement`` Wrap control statements (if/for/while/switch/..).
|
||||
* ``bool AfterEnum`` Wrap enum definitions.
|
||||
* ``bool AfterFunction`` Wrap function definitions.
|
||||
* ``bool AfterNamespace`` Wrap namespace definitions.
|
||||
* ``bool AfterObjCDeclaration`` Wrap ObjC definitions (@autoreleasepool, interfaces, ..).
|
||||
* ``bool AfterStruct`` Wrap struct definitions.
|
||||
* ``bool AfterUnion`` Wrap union definitions.
|
||||
* ``bool BeforeCatch`` Wrap before ``catch``.
|
||||
* ``bool BeforeElse`` Wrap before ``else``.
|
||||
* ``bool IndentBraces`` Indent the wrapped braces themselves.
|
||||
|
||||
|
||||
**BreakAfterJavaFieldAnnotations** (``bool``)
|
||||
Break after each annotation on a field in Java files.
|
||||
|
||||
**BreakBeforeBinaryOperators** (``BinaryOperatorStyle``)
|
||||
The way to wrap binary operators.
|
||||
|
||||
@ -279,13 +357,17 @@ the configuration (without a prefix: ``Auto``).
|
||||
Like ``Attach``, but break before braces on enum, function, and record
|
||||
definitions.
|
||||
* ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
|
||||
Like ``Attach``, but break before function definitions, and 'else'.
|
||||
Like ``Attach``, but break before function definitions, 'catch', and 'else'.
|
||||
* ``BS_Allman`` (in configuration: ``Allman``)
|
||||
Always break before braces.
|
||||
* ``BS_GNU`` (in configuration: ``GNU``)
|
||||
Always break before braces and add an extra level of indentation to
|
||||
braces of control statements, not to those of class, function
|
||||
or other definitions.
|
||||
* ``BS_WebKit`` (in configuration: ``WebKit``)
|
||||
Like ``Attach``, but break before functions.
|
||||
* ``BS_Custom`` (in configuration: ``Custom``)
|
||||
Configure each individual brace in ``BraceWrapping``.
|
||||
|
||||
|
||||
**BreakBeforeTernaryOperators** (``bool``)
|
||||
@ -356,13 +438,47 @@ the configuration (without a prefix: ``Auto``).
|
||||
instead of as function calls.
|
||||
|
||||
These are expected to be macros of the form:
|
||||
\code
|
||||
FOREACH(<variable-declaration>, ...)
|
||||
<loop-body>
|
||||
\endcode
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
FOREACH(<variable-declaration>, ...)
|
||||
<loop-body>
|
||||
|
||||
In the .clang-format configuration file, this can be configured like:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
ForEachMacros: ['RANGES_FOR', 'FOREACH']
|
||||
|
||||
For example: BOOST_FOREACH.
|
||||
|
||||
**IncludeCategories** (``std::vector<IncludeCategory>``)
|
||||
Regular expressions denoting the different #include categories used
|
||||
for ordering #includes.
|
||||
|
||||
These regular expressions are matched against the filename of an include
|
||||
(including the <> or "") in order. The value belonging to the first
|
||||
matching regular expression is assigned and #includes are sorted first
|
||||
according to increasing category number and then alphabetically within
|
||||
each category.
|
||||
|
||||
If none of the regular expressions match, UINT_MAX is assigned as
|
||||
category. The main header for a source file automatically gets category 0,
|
||||
so that it is kept at the beginning of the #includes
|
||||
(http://llvm.org/docs/CodingStandards.html#include-style).
|
||||
|
||||
To configure this in the .clang-format file, use:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.\*'
|
||||
Priority: 1
|
||||
|
||||
**IndentCaseLabels** (``bool``)
|
||||
Indent case labels one level from the switch statement.
|
||||
|
||||
@ -546,6 +662,26 @@ the configuration (without a prefix: ``Auto``).
|
||||
|
||||
.. END_FORMAT_STYLE_OPTIONS
|
||||
|
||||
Adding additional style options
|
||||
===============================
|
||||
|
||||
Each additional style option adds costs to the clang-format project. Some of
|
||||
these costs affect the clang-format developement itself, as we need to make
|
||||
sure that any given combination of options work and that new features don't
|
||||
break any of the existing options in any way. There are also costs for end users
|
||||
as options become less discoverable and people have to think about and make a
|
||||
decision on options they don't really care about.
|
||||
|
||||
The goal of the clang-format project is more on the side of supporting a
|
||||
limited set of styles really well as opposed to supporting every single style
|
||||
used by a codebase somewhere in the wild. Of course, we do want to support all
|
||||
major projects and thus have established the following bar for adding style
|
||||
options. Each new style option must ..
|
||||
|
||||
* be used in a project of significant size (have dozens of contributors)
|
||||
* have a publicly accessible style guide
|
||||
* have a person willing to contribute and maintain patches
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
|
@ -82,7 +82,7 @@ fixit-hints offered by clang. See :doc:`HowToSetupToolingForLLVM` for
|
||||
instructions on how to setup and used `clang-check`.
|
||||
|
||||
``clang-format``
|
||||
~~~~~~~~~~~~~~~~
|
||||
----------------
|
||||
|
||||
Clang-format is both a :doc:`library <LibFormat>` and a :doc:`stand-alone tool
|
||||
<ClangFormat>` with the goal of automatically reformatting C++ sources files
|
||||
@ -93,18 +93,6 @@ as a user tool (ideally with powerful IDE integrations) and as part of other
|
||||
refactoring tools, e.g. to do a reformatting of all the lines changed during a
|
||||
renaming.
|
||||
|
||||
``clang-modernize``
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
``clang-modernize`` migrates C++ code to use C++11 features where appropriate.
|
||||
Currently it can:
|
||||
|
||||
* convert loops to range-based for loops;
|
||||
|
||||
* convert null pointer constants (like ``NULL`` or ``0``) to C++11 ``nullptr``;
|
||||
|
||||
* replace the type specifier in variable declarations with the ``auto`` type specifier;
|
||||
|
||||
* add the ``override`` specifier to applicable member functions.
|
||||
|
||||
Extra Clang Tools
|
||||
=================
|
||||
@ -114,6 +102,15 @@ they'll be tracked here. The focus of this documentation is on the scope
|
||||
and features of the tools for other tool developers; each tool should
|
||||
provide its own user-focused documentation.
|
||||
|
||||
``clang-tidy``
|
||||
--------------
|
||||
|
||||
`clang-tidy <http://clang.llvm.org/extra/clang-tidy/>`_ is a clang-based C++
|
||||
linter tool. It provides an extensible framework for building compiler-based
|
||||
static analyses detecting and fixing bug-prone patterns, performance,
|
||||
portability and maintainability issues.
|
||||
|
||||
|
||||
Ideas for new Tools
|
||||
===================
|
||||
|
||||
@ -124,27 +121,6 @@ Ideas for new Tools
|
||||
``foo.begin()`` into ``begin(foo)`` and similarly for ``end()``, where
|
||||
``foo`` is a standard container. We could also detect similar patterns for
|
||||
arrays.
|
||||
* ``make_shared`` / ``make_unique`` conversion. Part of this transformation
|
||||
can be incorporated into the ``auto`` transformation. Will convert
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
std::shared_ptr<Foo> sp(new Foo);
|
||||
std::unique_ptr<Foo> up(new Foo);
|
||||
|
||||
func(std::shared_ptr<Foo>(new Foo), bar());
|
||||
|
||||
into:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
auto sp = std::make_shared<Foo>();
|
||||
auto up = std::make_unique<Foo>(); // In C++14 mode.
|
||||
|
||||
// This also affects correctness. For the cases where bar() throws,
|
||||
// make_shared() is safe and the original code may leak.
|
||||
func(std::make_shared<Foo>(), bar());
|
||||
|
||||
* ``tr1`` removal tool. Will migrate source code from using TR1 library
|
||||
features to C++11 library. For example:
|
||||
|
||||
|
@ -257,6 +257,18 @@ Code Generation Options
|
||||
|
||||
Generate debug information. Note that Clang debug information works best at -O0.
|
||||
|
||||
.. option:: -gmodules
|
||||
|
||||
Generate debug information that contains external references to
|
||||
types defined in clang modules or precompiled headers instead of
|
||||
emitting redundant debug type information into every object file.
|
||||
This option implies :option:`-fmodule-format=obj`.
|
||||
|
||||
This option should not be used when building static libraries for
|
||||
distribution to other machines because the debug info will contain
|
||||
references to the module cache on the machine the object files in
|
||||
the library were built on.
|
||||
|
||||
.. option:: -fstandalone-debug -fno-standalone-debug
|
||||
|
||||
Clang supports a number of optimizations to reduce the size of debug
|
||||
|
@ -20,20 +20,72 @@ program's control flow. These schemes have been optimized for performance,
|
||||
allowing developers to enable them in release builds.
|
||||
|
||||
To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``.
|
||||
As currently implemented, CFI relies on link-time optimization (LTO); so it is
|
||||
required to specify ``-flto``, and the linker used must support LTO, for example
|
||||
via the `gold plugin`_. To allow the checks to be implemented efficiently,
|
||||
the program must be structured such that certain object files are compiled
|
||||
with CFI enabled, and are statically linked into the program. This may
|
||||
preclude the use of shared libraries in some cases.
|
||||
You can also enable a subset of available :ref:`schemes <cfi-schemes>`.
|
||||
As currently implemented, all schemes rely on link-time optimization (LTO);
|
||||
so it is required to specify ``-flto``, and the linker used must support LTO,
|
||||
for example via the `gold plugin`_.
|
||||
|
||||
Clang currently implements forward-edge CFI for member function calls and
|
||||
bad cast checking. More schemes are under development.
|
||||
To allow the checks to be implemented efficiently, the program must be
|
||||
structured such that certain object files are compiled with CFI
|
||||
enabled, and are statically linked into the program. This may preclude
|
||||
the use of shared libraries in some cases. Experimental support for
|
||||
:ref:`cross-DSO control flow integrity <cfi-cross-dso>` exists that
|
||||
does not have these requirements. This cross-DSO support has unstable
|
||||
ABI at this time.
|
||||
|
||||
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
|
||||
|
||||
.. _cfi-schemes:
|
||||
|
||||
Available schemes
|
||||
=================
|
||||
|
||||
Available schemes are:
|
||||
|
||||
- ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
|
||||
<cfi-strictness>`.
|
||||
- ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
|
||||
dynamic type.
|
||||
- ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
|
||||
unrelated type to the wrong dynamic type.
|
||||
- ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
|
||||
the wrong dynamic type.
|
||||
- ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
|
||||
wrong dynamic type.
|
||||
- ``-fsanitize=cfi-icall``: Indirect call of a function with wrong dynamic
|
||||
type.
|
||||
|
||||
You can use ``-fsanitize=cfi`` to enable all the schemes and use
|
||||
``-fno-sanitize`` flag to narrow down the set of schemes as desired.
|
||||
For example, you can build your program with
|
||||
``-fsanitize=cfi -fno-sanitize=cfi-nvcall,cfi-icall``
|
||||
to use all schemes except for non-virtual member function call and indirect call
|
||||
checking.
|
||||
|
||||
Remember that you have to provide ``-flto`` if at least one CFI scheme is
|
||||
enabled.
|
||||
|
||||
Trapping and Diagnostics
|
||||
========================
|
||||
|
||||
By default, CFI will abort the program immediately upon detecting a control
|
||||
flow integrity violation. You can use the :ref:`-fno-sanitize-trap=
|
||||
<controlling-code-generation>` flag to cause CFI to print a diagnostic
|
||||
similar to the one below before the program aborts.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
bad-cast.cpp:109:7: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast (vtable address 0x000000425a50)
|
||||
0x000000425a50: note: vtable is of type 'A'
|
||||
00 00 00 00 f0 f1 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 5a 42 00
|
||||
^
|
||||
|
||||
If diagnostics are enabled, you can also configure CFI to continue program
|
||||
execution instead of aborting by using the :ref:`-fsanitize-recover=
|
||||
<controlling-code-generation>` flag.
|
||||
|
||||
Forward-Edge CFI for Virtual Calls
|
||||
----------------------------------
|
||||
==================================
|
||||
|
||||
This scheme checks that virtual calls take place using a vptr of the correct
|
||||
dynamic type; that is, the dynamic type of the called object must be a
|
||||
@ -41,14 +93,12 @@ derived class of the static type of the object used to make the call.
|
||||
This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vcall``.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not) must be compiled
|
||||
with ``-fsanitize=cfi-vcall`` enabled and be statically linked into the
|
||||
program. Classes in the C++ standard library (under namespace ``std``) are
|
||||
exempted from checking, and therefore programs may be linked against a
|
||||
pre-built standard library, but this may change in the future.
|
||||
of a virtual member function (whether inline or not), other than members
|
||||
of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
|
||||
``-fsanitize=cfi-vcall`` enabled and be statically linked into the program.
|
||||
|
||||
Performance
|
||||
~~~~~~~~~~~
|
||||
-----------
|
||||
|
||||
A performance overhead of less than 1% has been measured by running the
|
||||
Dromaeo benchmark suite against an instrumented version of the Chromium
|
||||
@ -59,7 +109,7 @@ Note that this scheme has not yet been optimized for binary size; an increase
|
||||
of up to 15% has been observed for Chromium.
|
||||
|
||||
Bad Cast Checking
|
||||
-----------------
|
||||
=================
|
||||
|
||||
This scheme checks that pointer casts are made to an object of the correct
|
||||
dynamic type; that is, the dynamic type of the object must be a derived class
|
||||
@ -85,18 +135,16 @@ If a program as a matter of policy forbids the second type of cast, that
|
||||
restriction can normally be enforced. However it may in some cases be necessary
|
||||
for a function to perform a forbidden cast to conform with an external API
|
||||
(e.g. the ``allocate`` member function of a standard library allocator). Such
|
||||
functions may be blacklisted using a :doc:`SanitizerSpecialCaseList`.
|
||||
functions may be :ref:`blacklisted <cfi-blacklist>`.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not) must be compiled with
|
||||
of a virtual member function (whether inline or not), other than members
|
||||
of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
|
||||
``-fsanitize=cfi-derived-cast`` or ``-fsanitize=cfi-unrelated-cast`` enabled
|
||||
and be statically linked into the program. Classes in the C++ standard library
|
||||
(under namespace ``std``) are exempted from checking, and therefore programs
|
||||
may be linked against a pre-built standard library, but this may change in
|
||||
the future.
|
||||
and be statically linked into the program.
|
||||
|
||||
Non-Virtual Member Function Call Checking
|
||||
-----------------------------------------
|
||||
=========================================
|
||||
|
||||
This scheme checks that non-virtual calls take place using an object of
|
||||
the correct dynamic type; that is, the dynamic type of the called object
|
||||
@ -106,16 +154,14 @@ polymorphic class type. This CFI scheme can be enabled on its own using
|
||||
``-fsanitize=cfi-nvcall``.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not) must be compiled
|
||||
with ``-fsanitize=cfi-nvcall`` enabled and be statically linked into the
|
||||
program. Classes in the C++ standard library (under namespace ``std``) are
|
||||
exempted from checking, and therefore programs may be linked against a
|
||||
pre-built standard library, but this may change in the future.
|
||||
of a virtual member function (whether inline or not), other than members
|
||||
of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
|
||||
``-fsanitize=cfi-nvcall`` enabled and be statically linked into the program.
|
||||
|
||||
.. _cfi-strictness:
|
||||
|
||||
Strictness
|
||||
~~~~~~~~~~
|
||||
----------
|
||||
|
||||
If a class has a single non-virtual base and does not introduce or override
|
||||
virtual member functions or fields other than an implicitly defined virtual
|
||||
@ -129,13 +175,97 @@ member functions on class instances with specific properties that works under
|
||||
most compilers and should not have security implications, so we allow it by
|
||||
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
|
||||
|
||||
Indirect Function Call Checking
|
||||
===============================
|
||||
|
||||
This scheme checks that function calls take place using a function of the
|
||||
correct dynamic type; that is, the dynamic type of the function must match
|
||||
the static type used at the call. This CFI scheme can be enabled on its own
|
||||
using ``-fsanitize=cfi-icall``.
|
||||
|
||||
For this scheme to work, each indirect function call in the program, other
|
||||
than calls in :ref:`blacklisted <cfi-blacklist>` functions, must call a
|
||||
function which was either compiled with ``-fsanitize=cfi-icall`` enabled,
|
||||
or whose address was taken by a function in a translation unit compiled with
|
||||
``-fsanitize=cfi-icall``.
|
||||
|
||||
If a function in a translation unit compiled with ``-fsanitize=cfi-icall``
|
||||
takes the address of a function not compiled with ``-fsanitize=cfi-icall``,
|
||||
that address may differ from the address taken by a function in a translation
|
||||
unit not compiled with ``-fsanitize=cfi-icall``. This is technically a
|
||||
violation of the C and C++ standards, but it should not affect most programs.
|
||||
|
||||
Each translation unit compiled with ``-fsanitize=cfi-icall`` must be
|
||||
statically linked into the program or shared library, and calls across
|
||||
shared library boundaries are handled as if the callee was not compiled with
|
||||
``-fsanitize=cfi-icall``.
|
||||
|
||||
This scheme is currently only supported on the x86 and x86_64 architectures.
|
||||
|
||||
``-fsanitize=cfi-icall`` and ``-fsanitize=function``
|
||||
----------------------------------------------------
|
||||
|
||||
This tool is similar to ``-fsanitize=function`` in that both tools check
|
||||
the types of function calls. However, the two tools occupy different points
|
||||
on the design space; ``-fsanitize=function`` is a developer tool designed
|
||||
to find bugs in local development builds, whereas ``-fsanitize=cfi-icall``
|
||||
is a security hardening mechanism designed to be deployed in release builds.
|
||||
|
||||
``-fsanitize=function`` has a higher space and time overhead due to a more
|
||||
complex type check at indirect call sites, as well as a need for run-time
|
||||
type information (RTTI), which may make it unsuitable for deployment. Because
|
||||
of the need for RTTI, ``-fsanitize=function`` can only be used with C++
|
||||
programs, whereas ``-fsanitize=cfi-icall`` can protect both C and C++ programs.
|
||||
|
||||
On the other hand, ``-fsanitize=function`` conforms more closely with the C++
|
||||
standard and user expectations around interaction with shared libraries;
|
||||
the identity of function pointers is maintained, and calls across shared
|
||||
library boundaries are no different from calls within a single program or
|
||||
shared library.
|
||||
|
||||
.. _cfi-blacklist:
|
||||
|
||||
Blacklist
|
||||
=========
|
||||
|
||||
A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
|
||||
source files, functions and types using the ``src``, ``fun`` and ``type``
|
||||
entity types.
|
||||
|
||||
In addition, if a type has a ``uuid`` attribute and the blacklist contains
|
||||
the type entry ``attr:uuid``, CFI checks are suppressed for that type. This
|
||||
allows all COM types to be easily blacklisted, which is useful as COM types
|
||||
are typically defined outside of the linked program.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Suppress checking for code in a file.
|
||||
src:bad_file.cpp
|
||||
src:bad_header.h
|
||||
# Ignore all functions with names containing MyFooBar.
|
||||
fun:*MyFooBar*
|
||||
# Ignore all types in the standard library.
|
||||
type:std::*
|
||||
# Ignore all types with a uuid attribute.
|
||||
type:attr:uuid
|
||||
|
||||
.. _cfi-cross-dso:
|
||||
|
||||
Shared library support
|
||||
======================
|
||||
|
||||
Use **-f[no-]sanitize-cfi-cross-dso** to enable the cross-DSO control
|
||||
flow integrity mode, which allows all CFI schemes listed above to
|
||||
apply across DSO boundaries. As in the regular CFI, each DSO must be
|
||||
built with ``-flto``.
|
||||
|
||||
Design
|
||||
------
|
||||
======
|
||||
|
||||
Please refer to the :doc:`design document<ControlFlowIntegrityDesign>`.
|
||||
|
||||
Publications
|
||||
------------
|
||||
============
|
||||
|
||||
`Control-Flow Integrity: Principles, Implementations, and Applications <http://research.microsoft.com/pubs/64250/ccs05.pdf>`_.
|
||||
Martin Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti.
|
||||
|
@ -273,3 +273,227 @@ Eliminating Bit Vector Checks for All-Ones Bit Vectors
|
||||
If the bit vector is all ones, the bit vector check is redundant; we simply
|
||||
need to check that the address is in range and well aligned. This is more
|
||||
likely to occur if the virtual tables are padded.
|
||||
|
||||
Forward-Edge CFI for Indirect Function Calls
|
||||
============================================
|
||||
|
||||
Under forward-edge CFI for indirect function calls, each unique function
|
||||
type has its own bit vector, and at each call site we need to check that the
|
||||
function pointer is a member of the function type's bit vector. This scheme
|
||||
works in a similar way to forward-edge CFI for virtual calls, the distinction
|
||||
being that we need to build bit vectors of function entry points rather than
|
||||
of virtual tables.
|
||||
|
||||
Unlike when re-arranging global variables, we cannot re-arrange functions
|
||||
in a particular order and base our calculations on the layout of the
|
||||
functions' entry points, as we have no idea how large a particular function
|
||||
will end up being (the function sizes could even depend on how we arrange
|
||||
the functions). Instead, we build a jump table, which is a block of code
|
||||
consisting of one branch instruction for each of the functions in the bit
|
||||
set that branches to the target function, and redirect any taken function
|
||||
addresses to the corresponding jump table entry. In this way, the distance
|
||||
between function entry points is predictable and controllable. In the object
|
||||
file's symbol table, the symbols for the target functions also refer to the
|
||||
jump table entries, so that addresses taken outside the module will pass
|
||||
any verification done inside the module.
|
||||
|
||||
In more concrete terms, suppose we have three functions ``f``, ``g``, ``h``
|
||||
which are members of a single bitset, and a function foo that returns their
|
||||
addresses:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
f:
|
||||
mov 0, %eax
|
||||
ret
|
||||
|
||||
g:
|
||||
mov 1, %eax
|
||||
ret
|
||||
|
||||
h:
|
||||
mov 2, %eax
|
||||
ret
|
||||
|
||||
foo:
|
||||
mov f, %eax
|
||||
mov g, %edx
|
||||
mov h, %ecx
|
||||
ret
|
||||
|
||||
Our jump table will (conceptually) look like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
f:
|
||||
jmp .Ltmp0 ; 5 bytes
|
||||
int3 ; 1 byte
|
||||
int3 ; 1 byte
|
||||
int3 ; 1 byte
|
||||
|
||||
g:
|
||||
jmp .Ltmp1 ; 5 bytes
|
||||
int3 ; 1 byte
|
||||
int3 ; 1 byte
|
||||
int3 ; 1 byte
|
||||
|
||||
h:
|
||||
jmp .Ltmp2 ; 5 bytes
|
||||
int3 ; 1 byte
|
||||
int3 ; 1 byte
|
||||
int3 ; 1 byte
|
||||
|
||||
.Ltmp0:
|
||||
mov 0, %eax
|
||||
ret
|
||||
|
||||
.Ltmp1:
|
||||
mov 1, %eax
|
||||
ret
|
||||
|
||||
.Ltmp2:
|
||||
mov 2, %eax
|
||||
ret
|
||||
|
||||
foo:
|
||||
mov f, %eax
|
||||
mov g, %edx
|
||||
mov h, %ecx
|
||||
ret
|
||||
|
||||
Because the addresses of ``f``, ``g``, ``h`` are evenly spaced at a power of
|
||||
2, and function types do not overlap (unlike class types with base classes),
|
||||
we can normally apply the `Alignment`_ and `Eliminating Bit Vector Checks
|
||||
for All-Ones Bit Vectors`_ optimizations thus simplifying the check at each
|
||||
call site to a range and alignment check.
|
||||
|
||||
Shared library support
|
||||
======================
|
||||
|
||||
**EXPERIMENTAL**
|
||||
|
||||
The basic CFI mode described above assumes that the application is a
|
||||
monolithic binary; at least that all possible virtual/indirect call
|
||||
targets and the entire class hierarchy are known at link time. The
|
||||
cross-DSO mode, enabled with **-f[no-]sanitize-cfi-cross-dso** relaxes
|
||||
this requirement by allowing virtual and indirect calls to cross the
|
||||
DSO boundary.
|
||||
|
||||
Assuming the following setup: the binary consists of several
|
||||
instrumented and several uninstrumented DSOs. Some of them may be
|
||||
dlopen-ed/dlclose-d periodically, even frequently.
|
||||
|
||||
- Calls made from uninstrumented DSOs are not checked and just work.
|
||||
- Calls inside any instrumented DSO are fully protected.
|
||||
- Calls between different instrumented DSOs are also protected, with
|
||||
a performance penalty (in addition to the monolithic CFI
|
||||
overhead).
|
||||
- Calls from an instrumented DSO to an uninstrumented one are
|
||||
unchecked and just work, with performance penalty.
|
||||
- Calls from an instrumented DSO outside of any known DSO are
|
||||
detected as CFI violations.
|
||||
|
||||
In the monolithic scheme a call site is instrumented as
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
if (!InlinedFastCheck(f))
|
||||
abort();
|
||||
call *f
|
||||
|
||||
In the cross-DSO scheme it becomes
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
if (!InlinedFastCheck(f))
|
||||
__cfi_slowpath(CallSiteTypeId, f);
|
||||
call *f
|
||||
|
||||
CallSiteTypeId
|
||||
--------------
|
||||
|
||||
``CallSiteTypeId`` is a stable process-wide identifier of the
|
||||
call-site type. For a virtual call site, the type in question is the class
|
||||
type; for an indirect function call it is the function signature. The
|
||||
mapping from a type to an identifier is an ABI detail. In the current,
|
||||
experimental, implementation the identifier of type T is calculated as
|
||||
follows:
|
||||
|
||||
- Obtain the mangled name for "typeinfo name for T".
|
||||
- Calculate MD5 hash of the name as a string.
|
||||
- Reinterpret the first 8 bytes of the hash as a little-endian
|
||||
64-bit integer.
|
||||
|
||||
It is possible, but unlikely, that collisions in the
|
||||
``CallSiteTypeId`` hashing will result in weaker CFI checks that would
|
||||
still be conservatively correct.
|
||||
|
||||
CFI_Check
|
||||
---------
|
||||
|
||||
In the general case, only the target DSO knows whether the call to
|
||||
function ``f`` with type ``CallSiteTypeId`` is valid or not. To
|
||||
export this information, every DSO implements
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr)
|
||||
|
||||
This function provides external modules with access to CFI checks for
|
||||
the targets inside this DSO. For each known ``CallSiteTypeId``, this
|
||||
functions performs an ``llvm.bitset.test`` with the corresponding bit
|
||||
set. It aborts if the type is unknown, or if the check fails.
|
||||
|
||||
The basic implementation is a large switch statement over all values
|
||||
of CallSiteTypeId supported by this DSO, and each case is similar to
|
||||
the InlinedFastCheck() in the basic CFI mode.
|
||||
|
||||
CFI Shadow
|
||||
----------
|
||||
|
||||
To route CFI checks to the target DSO's __cfi_check function, a
|
||||
mapping from possible virtual / indirect call targets to
|
||||
the corresponding __cfi_check functions is maintained. This mapping is
|
||||
implemented as a sparse array of 2 bytes for every possible page (4096
|
||||
bytes) of memory. The table is kept readonly (FIXME: not yet) most of
|
||||
the time.
|
||||
|
||||
There are 3 types of shadow values:
|
||||
|
||||
- Address in a CFI-instrumented DSO.
|
||||
- Unchecked address (a “trusted” non-instrumented DSO). Encoded as
|
||||
value 0xFFFF.
|
||||
- Invalid address (everything else). Encoded as value 0.
|
||||
|
||||
For a CFI-instrumented DSO, a shadow value encodes the address of the
|
||||
__cfi_check function for all call targets in the corresponding memory
|
||||
page. If Addr is the target address, and V is the shadow value, then
|
||||
the address of __cfi_check is calculated as
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
__cfi_check = AlignUpTo(Addr, 4096) - (V + 1) * 4096
|
||||
|
||||
This works as long as __cfi_check is aligned by 4096 bytes and located
|
||||
below any call targets in its DSO, but not more than 256MB apart from
|
||||
them.
|
||||
|
||||
CFI_SlowPath
|
||||
------------
|
||||
|
||||
The slow path check is implemented in compiler-rt library as
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
void __cfi_slowpath(uint64 CallSiteTypeId, void *TargetAddr)
|
||||
|
||||
This functions loads a shadow value for ``TargetAddr``, finds the
|
||||
address of __cfi_check as described above and calls that.
|
||||
|
||||
Position-independent executable requirement
|
||||
-------------------------------------------
|
||||
|
||||
Cross-DSO CFI mode requires that the main executable is built as PIE.
|
||||
In non-PIE executables the address of an external function (taken from
|
||||
the main executable) is the address of that function’s PLT record in
|
||||
the main executable. This would break the CFI checks.
|
||||
|
@ -1995,7 +1995,7 @@ are similar.
|
||||
* Make sure that ``children()`` 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 ``RecursiveASTVisitor`` and ``DataRecursiveASTVisitor``.
|
||||
sub-types in ``RecursiveASTVisitor``.
|
||||
* Add printing support (``StmtPrinter.cpp``) for your expression.
|
||||
* Add profiling support (``StmtProfile.cpp``) for your AST node, noting the
|
||||
distinguishing (non-source location) characteristics of an instance of
|
||||
|
@ -415,7 +415,7 @@ dash indicates that an operation is not accepted according to a corresponding
|
||||
specification.
|
||||
|
||||
============================== ======= ======= ======= =======
|
||||
Opeator OpenCL AltiVec GCC NEON
|
||||
Operator OpenCL AltiVec GCC NEON
|
||||
============================== ======= ======= ======= =======
|
||||
[] yes yes yes --
|
||||
unary operators +, -- yes yes yes --
|
||||
@ -1017,8 +1017,8 @@ The following type trait primitives are supported by Clang:
|
||||
``argtypes...`` such that no non-trivial functions are called as part of
|
||||
that initialization. This trait is required to implement the C++11 standard
|
||||
library.
|
||||
* ``__is_destructible`` (MSVC 2013): partially implemented
|
||||
* ``__is_nothrow_destructible`` (MSVC 2013): partially implemented
|
||||
* ``__is_destructible`` (MSVC 2013)
|
||||
* ``__is_nothrow_destructible`` (MSVC 2013)
|
||||
* ``__is_nothrow_assignable`` (MSVC 2013, clang)
|
||||
* ``__is_constructible`` (MSVC 2013, clang)
|
||||
* ``__is_nothrow_constructible`` (MSVC 2013, clang)
|
||||
@ -1540,6 +1540,33 @@ takes no arguments and produces a void result.
|
||||
|
||||
Query for this feature with ``__has_builtin(__builtin_unreachable)``.
|
||||
|
||||
``__builtin_unpredictable``
|
||||
---------------------------
|
||||
|
||||
``__builtin_unpredictable`` is used to indicate that a branch condition is
|
||||
unpredictable by hardware mechanisms such as branch prediction logic.
|
||||
|
||||
**Syntax**:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
__builtin_unpredictable(long long)
|
||||
|
||||
**Example of use**:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
if (__builtin_unpredictable(x > 0)) {
|
||||
foo();
|
||||
}
|
||||
|
||||
**Description**:
|
||||
|
||||
The ``__builtin_unpredictable()`` builtin is expected to be used with control
|
||||
flow conditions such as in ``if`` and ``switch`` statements.
|
||||
|
||||
Query for this feature with ``__has_builtin(__builtin_unpredictable)``.
|
||||
|
||||
``__sync_swap``
|
||||
---------------
|
||||
|
||||
@ -1652,17 +1679,20 @@ an example of their usage:
|
||||
errorcode_t security_critical_application(...) {
|
||||
unsigned x, y, result;
|
||||
...
|
||||
if (__builtin_umul_overflow(x, y, &result))
|
||||
if (__builtin_mul_overflow(x, y, &result))
|
||||
return kErrorCodeHackers;
|
||||
...
|
||||
use_multiply(result);
|
||||
...
|
||||
}
|
||||
|
||||
A complete enumeration of the builtins are:
|
||||
Clang provides the following checked arithmetic builtins:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
bool __builtin_add_overflow (type1 x, type2 y, type3 *sum);
|
||||
bool __builtin_sub_overflow (type1 x, type2 y, type3 *diff);
|
||||
bool __builtin_mul_overflow (type1 x, type2 y, type3 *prod);
|
||||
bool __builtin_uadd_overflow (unsigned x, unsigned y, unsigned *sum);
|
||||
bool __builtin_uaddl_overflow (unsigned long x, unsigned long y, unsigned long *sum);
|
||||
bool __builtin_uaddll_overflow(unsigned long long x, unsigned long long y, unsigned long long *sum);
|
||||
@ -1682,6 +1712,21 @@ A complete enumeration of the builtins are:
|
||||
bool __builtin_smull_overflow (long x, long y, long *prod);
|
||||
bool __builtin_smulll_overflow(long long x, long long y, long long *prod);
|
||||
|
||||
Each builtin performs the specified mathematical operation on the
|
||||
first two arguments and stores the result in the third argument. If
|
||||
possible, the result will be equal to mathematically-correct result
|
||||
and the builtin will return 0. Otherwise, the builtin will return
|
||||
1 and the result will be equal to the unique value that is equivalent
|
||||
to the mathematically-correct result modulo two raised to the *k*
|
||||
power, where *k* is the number of bits in the result type. The
|
||||
behavior of these builtins is well-defined for all argument values.
|
||||
|
||||
The first three builtins work generically for operands of any integer type,
|
||||
including boolean types. The operands need not have the same type as each
|
||||
other, or as the result. The other builtins may implicitly promote or
|
||||
convert their operands before performing the operation.
|
||||
|
||||
Query for this feature with ``__has_builtin(__builtin_add_overflow)``, etc.
|
||||
|
||||
.. _langext-__c11_atomic:
|
||||
|
||||
@ -1715,6 +1760,9 @@ The macros ``__ATOMIC_RELAXED``, ``__ATOMIC_CONSUME``, ``__ATOMIC_ACQUIRE``,
|
||||
provided, with values corresponding to the enumerators of C11's
|
||||
``memory_order`` enumeration.
|
||||
|
||||
(Note that Clang additionally provides GCC-compatible ``__atomic_*``
|
||||
builtins)
|
||||
|
||||
Low-level ARM exclusive memory builtins
|
||||
---------------------------------------
|
||||
|
||||
@ -1730,6 +1778,7 @@ instructions for implementing atomic operations.
|
||||
void __builtin_arm_clrex(void);
|
||||
|
||||
The types ``T`` currently supported are:
|
||||
|
||||
* Integer types with width at most 64 bits (or 128 bits on AArch64).
|
||||
* Floating-point types
|
||||
* Pointer types.
|
||||
@ -1748,6 +1797,26 @@ care should be exercised.
|
||||
For these reasons the higher level atomic primitives should be preferred where
|
||||
possible.
|
||||
|
||||
Non-temporal load/store builtins
|
||||
--------------------------------
|
||||
|
||||
Clang provides overloaded builtins allowing generation of non-temporal memory
|
||||
accesses.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
T __builtin_nontemporal_load(T *addr);
|
||||
void __builtin_nontemporal_store(T value, T *addr);
|
||||
|
||||
The types ``T`` currently supported are:
|
||||
|
||||
* Integer types.
|
||||
* Floating-point types.
|
||||
* Vector types.
|
||||
|
||||
Note that the compiler does not guarantee that non-temporal loads or stores
|
||||
will be used.
|
||||
|
||||
Non-standard C++11 Attributes
|
||||
=============================
|
||||
|
||||
@ -1990,11 +2059,23 @@ iterations. Full unrolling is only possible if the loop trip count is known at
|
||||
compile time. Partial unrolling replicates the loop body within the loop and
|
||||
reduces the trip count.
|
||||
|
||||
If ``unroll(full)`` is specified the unroller will attempt to fully unroll the
|
||||
If ``unroll(enable)`` is specified the unroller will attempt to fully unroll the
|
||||
loop if the trip count is known at compile time. If the fully unrolled code size
|
||||
is greater than an internal limit the loop will be partially unrolled up to this
|
||||
limit. If the loop count is not known at compile time the loop will not be
|
||||
unrolled.
|
||||
limit. If the trip count is not known at compile time the loop will be partially
|
||||
unrolled with a heuristically chosen unroll factor.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang loop unroll(enable)
|
||||
for(...) {
|
||||
...
|
||||
}
|
||||
|
||||
If ``unroll(full)`` is specified the unroller will attempt to fully unroll the
|
||||
loop if the trip count is known at compile time identically to
|
||||
``unroll(enable)``. However, with ``unroll(full)`` the loop will not be unrolled
|
||||
if the loop count is not known at compile time.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
@ -2006,7 +2087,7 @@ unrolled.
|
||||
The unroll count can be specified explicitly with ``unroll_count(_value_)`` where
|
||||
_value_ is a positive integer. If this value is greater than the trip count the
|
||||
loop will be fully unrolled. Otherwise the loop is partially unrolled subject
|
||||
to the same code size limit as with ``unroll(full)``.
|
||||
to the same code size limit as with ``unroll(enable)``.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
@ -28,6 +28,4 @@ There are plans to support LeakSanitizer in :doc:`MemorySanitizer` builds.
|
||||
More Information
|
||||
================
|
||||
|
||||
`https://code.google.com/p/address-sanitizer/wiki/LeakSanitizer
|
||||
<https://code.google.com/p/address-sanitizer/wiki/LeakSanitizer>`_
|
||||
|
||||
`<https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer>`_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -108,7 +108,6 @@ CMakeLists.txt should have the following contents:
|
||||
::
|
||||
|
||||
set(LLVM_LINK_COMPONENTS support)
|
||||
set(LLVM_USED_LIBS clangTooling clangBasic clangAST)
|
||||
|
||||
add_clang_executable(loop-convert
|
||||
LoopConvert.cpp
|
||||
|
@ -48,10 +48,7 @@ to disable inlining (just use ``-O1``) and tail call elimination
|
||||
% clang -fsanitize=memory -fno-omit-frame-pointer -g -O2 umr.cc
|
||||
|
||||
If a bug is detected, the program will print an error message to
|
||||
stderr and exit with a non-zero exit code. Currently, MemorySanitizer
|
||||
does not symbolize its output by default, so you may need to use a
|
||||
separate script to symbolize the result offline (this will be fixed in
|
||||
future).
|
||||
stderr and exit with a non-zero exit code.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
@ -60,7 +57,9 @@ future).
|
||||
#0 0x7f45944b418a in main umr.cc:6
|
||||
#1 0x7f45938b676c in __libc_start_main libc-start.c:226
|
||||
|
||||
By default, MemorySanitizer exits on the first detected error.
|
||||
By default, MemorySanitizer exits on the first detected error. If you
|
||||
find the error report hard to understand, try enabling
|
||||
:ref:`origin tracking <msan-origins>`.
|
||||
|
||||
``__has_feature(memory_sanitizer)``
|
||||
------------------------------------
|
||||
@ -80,14 +79,11 @@ whether MemorySanitizer is enabled. :ref:`\_\_has\_feature
|
||||
``__attribute__((no_sanitize_memory))``
|
||||
-----------------------------------------------
|
||||
|
||||
Some code should not be checked by MemorySanitizer.
|
||||
One may use the function attribute
|
||||
:ref:`no_sanitize_memory <langext-memory_sanitizer>`
|
||||
to disable uninitialized checks in a particular function.
|
||||
MemorySanitizer may still instrument such functions to avoid false positives.
|
||||
This attribute may not be
|
||||
supported by other compilers, so we suggest to use it together with
|
||||
``__has_feature(memory_sanitizer)``.
|
||||
Some code should not be checked by MemorySanitizer. One may use the function
|
||||
attribute `no_sanitize_memory` to disable uninitialized checks in a particular
|
||||
function. MemorySanitizer may still instrument such functions to avoid false
|
||||
positives. This attribute may not be supported by other compilers, so we
|
||||
suggest to use it together with ``__has_feature(memory_sanitizer)``.
|
||||
|
||||
Blacklist
|
||||
---------
|
||||
@ -105,10 +101,12 @@ MemorySanitizer uses an external symbolizer to print files and line numbers in
|
||||
reports. Make sure that ``llvm-symbolizer`` binary is in ``PATH``,
|
||||
or set environment variable ``MSAN_SYMBOLIZER_PATH`` to point to it.
|
||||
|
||||
.. _msan-origins:
|
||||
|
||||
Origin Tracking
|
||||
===============
|
||||
|
||||
MemorySanitizer can track origins of unitialized values, similar to
|
||||
MemorySanitizer can track origins of uninitialized values, similar to
|
||||
Valgrind's --track-origins option. This feature is enabled by
|
||||
``-fsanitize-memory-track-origins=2`` (or simply
|
||||
``-fsanitize-memory-track-origins``) Clang option. With the code from
|
||||
@ -146,14 +144,29 @@ By default, MemorySanitizer collects both allocation points and all
|
||||
intermediate stores the uninitialized value went through. Origin
|
||||
tracking has proved to be very useful for debugging MemorySanitizer
|
||||
reports. It slows down program execution by a factor of 1.5x-2x on top
|
||||
of the usual MemorySanitizer slowdown.
|
||||
of the usual MemorySanitizer slowdown and increases memory overhead.
|
||||
|
||||
Clang option ``-fsanitize-memory-track-origins=1`` enabled a slightly
|
||||
Clang option ``-fsanitize-memory-track-origins=1`` enables a slightly
|
||||
faster mode when MemorySanitizer collects only allocation points but
|
||||
not intermediate stores.
|
||||
|
||||
Use-after-destruction detection
|
||||
===============================
|
||||
|
||||
You can enable experimental use-after-destruction detection in MemorySanitizer.
|
||||
After invocation of the destructor, the object will be considered no longer
|
||||
readable, and using underlying memory will lead to error reports in runtime.
|
||||
|
||||
This feature is still experimental, in order to enable it at runtime you need
|
||||
to:
|
||||
|
||||
#. Pass addition Clang option ``-fsanitize-memory-use-after-dtor`` during
|
||||
compilation.
|
||||
#. Set environment variable `MSAN_OPTIONS=poison_in_dtor=1` before running
|
||||
the program.
|
||||
|
||||
Handling external code
|
||||
============================
|
||||
======================
|
||||
|
||||
MemorySanitizer requires that all program code is instrumented. This
|
||||
also includes any libraries that the program depends on, even libc.
|
||||
@ -170,9 +183,7 @@ self-built instrumented libc++ (as a replacement for libstdc++).
|
||||
Supported Platforms
|
||||
===================
|
||||
|
||||
MemorySanitizer is supported on
|
||||
|
||||
* Linux x86\_64 (tested on Ubuntu 12.04);
|
||||
MemorySanitizer is supported on Linux x86\_64/MIPS64/AArch64.
|
||||
|
||||
Limitations
|
||||
===========
|
||||
@ -183,22 +194,19 @@ Limitations
|
||||
address space. This means that tools like ``ulimit`` may not work as
|
||||
usually expected.
|
||||
* Static linking is not supported.
|
||||
* Non-position-independent executables are not supported. Therefore, the
|
||||
``fsanitize=memory`` flag will cause Clang to act as though the ``-fPIE``
|
||||
flag had been supplied if compiling without ``-fPIC``, and as though the
|
||||
``-pie`` flag had been supplied if linking an executable.
|
||||
* Depending on the version of Linux kernel, running without ASLR may
|
||||
be not supported. Note that GDB disables ASLR by default. To debug
|
||||
instrumented programs, use "set disable-randomization off".
|
||||
* Older versions of MSan (LLVM 3.7 and older) didn't work with
|
||||
non-position-independent executables, and could fail on some Linux
|
||||
kernel versions with disabled ASLR. Refer to documentation for older versions
|
||||
for more details.
|
||||
|
||||
Current Status
|
||||
==============
|
||||
|
||||
MemorySanitizer is an experimental tool. It is known to work on large
|
||||
real-world programs, like Clang/LLVM itself.
|
||||
MemorySanitizer is known to work on large real-world programs
|
||||
(like Clang/LLVM itself) that can be recompiled from source, including all
|
||||
dependent libraries.
|
||||
|
||||
More Information
|
||||
================
|
||||
|
||||
`http://code.google.com/p/memory-sanitizer <http://code.google.com/p/memory-sanitizer/>`_
|
||||
|
||||
`<https://github.com/google/sanitizers/wiki/MemorySanitizer>`_
|
||||
|
@ -222,7 +222,7 @@ Modules are modeled as if each submodule were a separate translation unit, and a
|
||||
|
||||
This behavior is currently only approximated when building a module with submodules. Entities within a submodule that has already been built are visible when building later submodules in that module. This can lead to fragile modules that depend on the build order used for the submodules of the module, and should not be relied upon. This behavior is subject to change.
|
||||
|
||||
As an example, in C, this implies that if two structs are defined in different submodules with the same name, those two types are distinct types (but may be *compatible* types if their definitions match. In C++, two structs defined with the same name in different submodules are the *same* type, and must be equivalent under C++'s One Definition Rule.
|
||||
As an example, in C, this implies that if two structs are defined in different submodules with the same name, those two types are distinct types (but may be *compatible* types if their definitions match). In C++, two structs defined with the same name in different submodules are the *same* type, and must be equivalent under C++'s One Definition Rule.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -205,10 +205,10 @@ following CMakeLists.txt to link it:
|
||||
|
||||
::
|
||||
|
||||
set(LLVM_USED_LIBS clangTooling)
|
||||
|
||||
add_clang_executable(find-class-decls FindClassDecls.cpp)
|
||||
|
||||
target_link_libraries(find-class-decls clangTooling)
|
||||
|
||||
When running this tool over a small code snippet it will output all
|
||||
declarations of a class n::m::C it found:
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
=======================
|
||||
Clang 3.7 Release Notes
|
||||
=======================
|
||||
=====================================
|
||||
Clang 3.8 (In-Progress) Release Notes
|
||||
=====================================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@ -8,12 +8,17 @@ Clang 3.7 Release Notes
|
||||
|
||||
Written by the `LLVM Team <http://llvm.org/>`_
|
||||
|
||||
.. warning::
|
||||
|
||||
These are in-progress notes for the upcoming Clang 3.8 release. You may
|
||||
prefer the `Clang 3.7 Release Notes
|
||||
<http://llvm.org/releases/3.7.0/tools/clang/docs/ReleaseNotes.html>`_.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document contains the release notes for the Clang C/C++/Objective-C
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.7. Here we
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.8. Here we
|
||||
describe the status of Clang in some detail, including major
|
||||
improvements from the previous release and new feature work. For the
|
||||
general LLVM release notes, see `the LLVM
|
||||
@ -26,7 +31,12 @@ the latest release, please check out the main please see the `Clang Web
|
||||
Site <http://clang.llvm.org>`_ or the `LLVM Web
|
||||
Site <http://llvm.org>`_.
|
||||
|
||||
What's New in Clang 3.7?
|
||||
Note that if you are reading this file from a Subversion checkout or the
|
||||
main Clang web page, this document applies to the *next* release, not
|
||||
the current one. To see the release notes for a specific release, please
|
||||
see the `releases page <http://llvm.org/releases/>`_.
|
||||
|
||||
What's New in Clang 3.8?
|
||||
========================
|
||||
|
||||
Some of the major new features and improvements to Clang are listed
|
||||
@ -37,223 +47,147 @@ sections with improvements to Clang's support for those languages.
|
||||
Major New Features
|
||||
------------------
|
||||
|
||||
- Use of the ``__declspec`` language extension for declaration attributes now
|
||||
requires passing the -fms-extensions or -fborland compiler flag. This language
|
||||
extension is also enabled when compiling CUDA code, but its use should be
|
||||
viewed as an implementation detail that is subject to change.
|
||||
|
||||
- On Windows targets, some uses of the ``__try``, ``__except``, and
|
||||
``__finally`` language constructs are supported in Clang 3.7. MSVC-compatible
|
||||
C++ exceptions are not yet supported, however.
|
||||
|
||||
- Clang 3.7 fully supports OpenMP 3.1 and reported to work on many platforms,
|
||||
including x86, x86-64 and Power. Also, pragma ``omp simd`` from OpenMP 4.0 is
|
||||
supported as well. See below for details.
|
||||
|
||||
- Clang 3.7 includes an implementation of :doc:`control flow integrity
|
||||
<ControlFlowIntegrity>`, a security hardening mechanism.
|
||||
|
||||
- Feature1...
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
-----------------------------------
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Clang's diagnostics are constantly being improved to catch more issues,
|
||||
explain them more clearly, and provide more accurate source information
|
||||
about them. The improvements since the 3.6 release include:
|
||||
about them. The improvements since the 3.7 release include:
|
||||
|
||||
- -Wrange-loop-analysis analyzes the loop variable type and the container type
|
||||
to determine whether copies are made of the container elements. If possible,
|
||||
suggest a const reference type to prevent copies, or a non-reference type
|
||||
to indicate a copy is made.
|
||||
|
||||
- -Wredundant-move warns when a parameter variable is moved on return and the
|
||||
return type is the same as the variable. Returning the variable directly
|
||||
will already make a move, so the call is not needed.
|
||||
|
||||
- -Wpessimizing-move warns when a local variable is moved on return and the
|
||||
return type is the same as the variable. Copy elision cannot take place with
|
||||
a move, but can take place if the variable is returned directly.
|
||||
|
||||
- -Wmove is a new warning group which has the previous two warnings,
|
||||
-Wredundant-move and -Wpessimizing-move, as well as previous warning
|
||||
-Wself-move. In addition, this group is part of -Wmost and -Wall now.
|
||||
|
||||
- -Winfinite-recursion, a warning for functions that only call themselves,
|
||||
is now part of -Wmost and -Wall.
|
||||
|
||||
- -Wobjc-circular-container prevents creation of circular containers,
|
||||
it covers ``NSMutableArray``, ``NSMutableSet``, ``NSMutableDictionary``,
|
||||
``NSMutableOrderedSet`` and all their subclasses.
|
||||
- ...
|
||||
|
||||
New Compiler Flags
|
||||
------------------
|
||||
|
||||
The sized deallocation feature of C++14 is now controlled by the
|
||||
``-fsized-deallocation`` flag. This feature relies on library support that
|
||||
isn't yet widely deployed, so the user must supply an extra flag to get the
|
||||
extra functionality.
|
||||
The option ....
|
||||
|
||||
|
||||
New Pragmas in Clang
|
||||
-----------------------
|
||||
|
||||
Clang now supports the ...
|
||||
|
||||
Windows Support
|
||||
---------------
|
||||
|
||||
Clang's support for building native Windows programs ...
|
||||
|
||||
|
||||
C Language Changes in Clang
|
||||
---------------------------
|
||||
|
||||
...
|
||||
|
||||
C11 Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
...
|
||||
|
||||
C++ Language Changes in Clang
|
||||
-----------------------------
|
||||
|
||||
- ...
|
||||
|
||||
C++11 Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
...
|
||||
|
||||
Objective-C Language Changes in Clang
|
||||
-------------------------------------
|
||||
|
||||
- ``objc_boxable`` attribute was added. Structs and unions marked with this attribute can be
|
||||
used with boxed expressions (``@(...)``) to create ``NSValue``.
|
||||
...
|
||||
|
||||
Profile Guided Optimization
|
||||
---------------------------
|
||||
OpenCL C Language Changes in Clang
|
||||
----------------------------------
|
||||
|
||||
Clang now accepts GCC-compatible flags for profile guided optimization (PGO).
|
||||
You can now use ``-fprofile-generate=<dir>``, ``-fprofile-use=<dir>``,
|
||||
``-fno-profile-generate`` and ``-fno-profile-use``. These flags have the
|
||||
same semantics as their GCC counterparts. However, the generated profile
|
||||
is still LLVM-specific. PGO profiles generated with Clang cannot be used
|
||||
by GCC and vice-versa.
|
||||
|
||||
Clang now emits function entry counts in profile-instrumented binaries.
|
||||
This has improved the computation of weights and frequencies in
|
||||
profile analysis.
|
||||
|
||||
OpenMP Support
|
||||
--------------
|
||||
OpenMP 3.1 is fully supported, but disabled by default. To enable it, please use
|
||||
the ``-fopenmp=libomp`` command line option. Your feedback (positive or negative) on
|
||||
using OpenMP-enabled clang would be much appreciated; please share it either on
|
||||
`cfe-dev <http://lists.llvm.org/mailman/listinfo/cfe-dev>`_ or `openmp-dev
|
||||
<http://lists.llvm.org/mailman/listinfo/openmp-dev>`_ mailing lists.
|
||||
|
||||
In addition to OpenMP 3.1, several important elements of the 4.0 version of the
|
||||
standard are supported as well:
|
||||
|
||||
- ``omp simd``, ``omp for simd`` and ``omp parallel for simd`` pragmas
|
||||
- atomic constructs
|
||||
- ``proc_bind`` clause of ``omp parallel`` pragma
|
||||
- ``depend`` clause of ``omp task`` pragma (except for array sections)
|
||||
- ``omp cancel`` and ``omp cancellation point`` pragmas
|
||||
- ``omp taskgroup`` pragma
|
||||
...
|
||||
|
||||
Internal API Changes
|
||||
--------------------
|
||||
|
||||
These are major API changes that have happened since the 3.6 release of
|
||||
These are major API changes that have happened since the 3.7 release of
|
||||
Clang. If upgrading an external codebase that uses Clang as a library,
|
||||
this section should help get you past the largest hurdles of upgrading.
|
||||
|
||||
- Some of the ``PPCallbacks`` interface now deals in ``MacroDefinition``
|
||||
objects instead of ``MacroDirective`` objects. This allows preserving
|
||||
full information on macros imported from modules.
|
||||
- ...
|
||||
|
||||
- ``clang-c/Index.h`` no longer ``#include``\s ``clang-c/Documentation.h``.
|
||||
You now need to explicitly ``#include "clang-c/Documentation.h"`` if
|
||||
you use the libclang documentation API.
|
||||
AST Matchers
|
||||
------------
|
||||
The AST matcher functions were renamed to reflect the exact AST node names,
|
||||
which is a breaking change to AST matching code. The following matchers were
|
||||
affected:
|
||||
|
||||
======================= ============================
|
||||
Previous Matcher Name New Matcher Name
|
||||
======================= ============================
|
||||
recordDecl recordDecl and cxxRecordDecl
|
||||
ctorInitializer cxxCtorInitializer
|
||||
constructorDecl cxxConstructorDecl
|
||||
destructorDecl cxxDestructorDecl
|
||||
methodDecl cxxMethodDecl
|
||||
conversionDecl cxxConversionDecl
|
||||
memberCallExpr cxxMemberCallExpr
|
||||
constructExpr cxxConstructExpr
|
||||
unresolvedConstructExpr cxxUnresolvedConstructExpr
|
||||
thisExpr cxxThisExpr
|
||||
bindTemporaryExpr cxxBindTemporaryExpr
|
||||
newExpr cxxNewExpr
|
||||
deleteExpr cxxDeleteExpr
|
||||
defaultArgExpr cxxDefaultArgExpr
|
||||
operatorCallExpr cxxOperatorCallExpr
|
||||
forRangeStmt cxxForRangeStmt
|
||||
catchStmt cxxCatchStmt
|
||||
tryStmt cxxTryStmt
|
||||
throwExpr cxxThrowExpr
|
||||
boolLiteral cxxBoolLiteral
|
||||
nullPtrLiteralExpr cxxNullPtrLiteralExpr
|
||||
reinterpretCastExpr cxxReinterpretCastExpr
|
||||
staticCastExpr cxxStaticCastExpr
|
||||
dynamicCastExpr cxxDynamicCastExpr
|
||||
constCastExpr cxxConstCastExpr
|
||||
functionalCastExpr cxxFunctionalCastExpr
|
||||
temporaryObjectExpr cxxTemporaryObjectExpr
|
||||
CUDAKernalCallExpr cudaKernelCallExpr
|
||||
======================= ============================
|
||||
|
||||
recordDecl() previously matched AST nodes of type CXXRecordDecl, but now
|
||||
matches AST nodes of type RecordDecl. If a CXXRecordDecl is required, use the
|
||||
cxxRecordDecl() matcher instead.
|
||||
|
||||
...
|
||||
|
||||
libclang
|
||||
--------
|
||||
|
||||
...
|
||||
|
||||
Static Analyzer
|
||||
---------------
|
||||
|
||||
* The generated plists now contain the name of the check that generated it.
|
||||
...
|
||||
|
||||
* Configuration options can now be passed to the checkers (not just the static
|
||||
analyzer core).
|
||||
Core Analysis Improvements
|
||||
==========================
|
||||
|
||||
* New check for dereferencing object that the result of a zero-length
|
||||
allocation.
|
||||
- ...
|
||||
|
||||
* Also check functions in precompiled headers.
|
||||
New Issues Found
|
||||
================
|
||||
|
||||
* Properly handle alloca() in some checkers.
|
||||
- ...
|
||||
|
||||
* Various improvements to the retain count checker.
|
||||
Python Binding Changes
|
||||
----------------------
|
||||
|
||||
The following methods have been added:
|
||||
|
||||
clang-tidy
|
||||
----------
|
||||
Added new checks:
|
||||
- ...
|
||||
|
||||
* google-global-names-in-headers: flag global namespace pollution in header
|
||||
files.
|
||||
|
||||
* misc-assert-side-effect: detects ``assert()`` conditions with side effects
|
||||
which can cause different behavior in debug / release builds.
|
||||
|
||||
* misc-assign-operator-signature: finds declarations of assign operators with
|
||||
the wrong return and/or argument types.
|
||||
|
||||
* misc-inaccurate-erase: warns when some elements of a container are not
|
||||
removed due to using the ``erase()`` algorithm incorrectly.
|
||||
|
||||
* misc-inefficient-algorithm: warns on inefficient use of STL algorithms on
|
||||
associative containers.
|
||||
|
||||
* misc-macro-parentheses: finds macros that can have unexpected behavior due
|
||||
to missing parentheses.
|
||||
|
||||
* misc-macro-repeated-side-effects: checks for repeated argument with side
|
||||
effects in macros.
|
||||
|
||||
* misc-noexcept-move-constructor: flags user-defined move constructors and
|
||||
assignment operators not marked with ``noexcept`` or marked with
|
||||
``noexcept(expr)`` where ``expr`` evaluates to ``false`` (but is not a
|
||||
``false`` literal itself).
|
||||
|
||||
* misc-static-assert: replaces ``assert()`` with ``static_assert()`` if the
|
||||
condition is evaluable at compile time.
|
||||
|
||||
* readability-container-size-empty: checks whether a call to the ``size()``
|
||||
method can be replaced with a call to ``empty()``.
|
||||
|
||||
* readability-else-after-return: flags conditional statements having the
|
||||
``else`` branch, when the ``true`` branch has a ``return`` as the last statement.
|
||||
|
||||
* readability-redundant-string-cstr: finds unnecessary calls to
|
||||
``std::string::c_str()``.
|
||||
|
||||
* readability-shrink-to-fit: replaces copy and swap tricks on shrinkable
|
||||
containers with the ``shrink_to_fit()`` method call.
|
||||
|
||||
* readability-simplify-boolean-expr: looks for boolean expressions involving
|
||||
boolean constants and simplifies them to use the appropriate boolean
|
||||
expression directly (``if (x == true) ... -> if (x)``, etc.)
|
||||
|
||||
SystemZ
|
||||
-------
|
||||
|
||||
* Clang will now always default to the z10 processor when compiling
|
||||
without any ``-march=`` option. Previous releases used to automatically
|
||||
detect the current host CPU when compiling natively. If you wish to
|
||||
still have clang detect the current host CPU, you now need to use the
|
||||
``-march=native`` option.
|
||||
|
||||
* Clang now provides the ``<s390intrin.h>`` header file.
|
||||
|
||||
* Clang now supports the transactional-execution facility and
|
||||
provides associated builtins and the ``<htmintrin.h>`` and
|
||||
``<htmxlintrin.h>`` header files. Support is enabled by default
|
||||
on zEC12 and above, and can additionally be enabled or disabled
|
||||
via the ``-mhtm`` / ``-mno-htm`` command line options.
|
||||
|
||||
* Clang now supports the vector facility. This includes a
|
||||
change in the ABI to pass arguments and return values of
|
||||
vector types in vector registers, as well as a change in
|
||||
the default alignment of vector types. Support is enabled
|
||||
by default on z13 and above, and can additionally be enabled
|
||||
or disabled via the ``-mvx`` / ``-mno-vx`` command line options.
|
||||
|
||||
* Clang now supports the System z vector language extension,
|
||||
providing a "vector" keyword to define vector types, and a
|
||||
set of builtins defined in the ``<vecintrin.h>`` header file.
|
||||
This can be enabled via the ``-fzvector`` command line option.
|
||||
For compatibility with GCC, Clang also supports the
|
||||
``-mzvector`` option as an alias.
|
||||
|
||||
* Several cases of ABI incompatibility with GCC have been fixed.
|
||||
|
||||
|
||||
Last release which will run on Windows XP and Windows Vista
|
||||
-----------------------------------------------------------
|
||||
|
||||
This is expected to the be the last major release of Clang that will support
|
||||
running on Windows XP and Windows Vista. For the next major release the
|
||||
minimum Windows version requirement will be Windows 7.
|
||||
Significant Known Problems
|
||||
==========================
|
||||
|
||||
Additional Information
|
||||
======================
|
||||
|
@ -249,6 +249,41 @@ These counters may also be used for in-process coverage-guided fuzzers. See
|
||||
uintptr_t
|
||||
__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
|
||||
|
||||
Tracing basic blocks
|
||||
====================
|
||||
An *experimental* feature to support basic block (or edge) tracing.
|
||||
With ``-fsanitize-coverage=trace-bb`` the compiler will insert
|
||||
``__sanitizer_cov_trace_basic_block(s32 *id)`` before every function, basic block, or edge
|
||||
(depending on the value of ``-fsanitize-coverage=[func,bb,edge]``).
|
||||
|
||||
Tracing data flow
|
||||
=================
|
||||
|
||||
An *experimental* feature to support data-flow-guided fuzzing.
|
||||
With ``-fsanitize-coverage=trace-cmp`` the compiler will insert extra instrumentation
|
||||
around comparison instructions and switch statements.
|
||||
The fuzzer will need to define the following functions,
|
||||
they will be called by the instrumented code.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// Called before a comparison instruction.
|
||||
// SizeAndType is a packed value containing
|
||||
// - [63:32] the Size of the operands of comparison in bits
|
||||
// - [31:0] the Type of comparison (one of ICMP_EQ, ... ICMP_SLE)
|
||||
// Arg1 and Arg2 are arguments of the comparison.
|
||||
void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, uint64_t Arg2);
|
||||
|
||||
// Called before a switch statement.
|
||||
// Val is the switch operand.
|
||||
// Cases[0] is the number of case constants.
|
||||
// Cases[1] is the size of Val in bits.
|
||||
// Cases[2:] are the case constants.
|
||||
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases);
|
||||
|
||||
This interface is a subject to change.
|
||||
The current implementation is not thread-safe and thus can be safely used only for single-threaded targets.
|
||||
|
||||
Output directory
|
||||
================
|
||||
|
||||
|
@ -86,25 +86,22 @@ this purpose.
|
||||
``__attribute__((no_sanitize_thread))``
|
||||
-----------------------------------------------
|
||||
|
||||
Some code should not be instrumented by ThreadSanitizer.
|
||||
One may use the function attribute
|
||||
:ref:`no_sanitize_thread <langext-thread_sanitizer>`
|
||||
to disable instrumentation of plain (non-atomic) loads/stores in a particular function.
|
||||
ThreadSanitizer still instruments such functions to avoid false positives and
|
||||
provide meaningful stack traces.
|
||||
This attribute may not be
|
||||
supported by other compilers, so we suggest to use it together with
|
||||
``__has_feature(thread_sanitizer)``.
|
||||
Some code should not be instrumented by ThreadSanitizer. One may use the
|
||||
function attribute `no_sanitize_thread` to disable instrumentation of plain
|
||||
(non-atomic) loads/stores in a particular function. ThreadSanitizer still
|
||||
instruments such functions to avoid false positives and provide meaningful stack
|
||||
traces. This attribute may not be supported by other compilers, so we suggest
|
||||
to use it together with ``__has_feature(thread_sanitizer)``.
|
||||
|
||||
Blacklist
|
||||
---------
|
||||
|
||||
ThreadSanitizer supports ``src`` and ``fun`` entity types in
|
||||
:doc:`SanitizerSpecialCaseList`, that can be used to suppress data race reports in
|
||||
the specified source files or functions. Unlike functions marked with
|
||||
:ref:`no_sanitize_thread <langext-thread_sanitizer>` attribute,
|
||||
blacklisted functions are not instrumented at all. This can lead to false positives
|
||||
due to missed synchronization via atomic operations and missed stack frames in reports.
|
||||
:doc:`SanitizerSpecialCaseList`, that can be used to suppress data race reports
|
||||
in the specified source files or functions. Unlike functions marked with
|
||||
`no_sanitize_thread` attribute, blacklisted functions are not instrumented at
|
||||
all. This can lead to false positives due to missed synchronization via atomic
|
||||
operations and missed stack frames in reports.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
@ -134,5 +131,4 @@ especially in the form of minimized standalone tests is more than welcome.
|
||||
|
||||
More Information
|
||||
----------------
|
||||
`http://code.google.com/p/thread-sanitizer <http://code.google.com/p/thread-sanitizer/>`_.
|
||||
|
||||
`<https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual>`_
|
||||
|
204
docs/UndefinedBehaviorSanitizer.rst
Normal file
204
docs/UndefinedBehaviorSanitizer.rst
Normal file
@ -0,0 +1,204 @@
|
||||
==========================
|
||||
UndefinedBehaviorSanitizer
|
||||
==========================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
UndefinedBehaviorSanitizer (UBSan) is a fast undefined behavior detector.
|
||||
UBSan modifies the program at compile-time to catch various kinds of undefined
|
||||
behavior during program execution, for example:
|
||||
|
||||
* Using misaligned or null pointer
|
||||
* Signed integer overflow
|
||||
* Conversion to, from, or between floating-point types which would
|
||||
overflow the destination
|
||||
|
||||
See the full list of available :ref:`checks <ubsan-checks>` below.
|
||||
|
||||
UBSan has an optional run-time library which provides better error reporting.
|
||||
The checks have small runtime cost and no impact on address space layout or ABI.
|
||||
|
||||
How to build
|
||||
============
|
||||
|
||||
Build LLVM/Clang with `CMake <http://llvm.org/docs/CMake.html>`_.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Use ``clang++`` to compile and link your program with ``-fsanitize=undefined``
|
||||
flag. Make sure to use ``clang++`` (not ``ld``) as a linker, so that your
|
||||
executable is linked with proper UBSan runtime libraries. You can use ``clang``
|
||||
instead of ``clang++`` if you're compiling/linking C code.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% cat test.cc
|
||||
int main(int argc, char **argv) {
|
||||
int k = 0x7fffffff;
|
||||
k += argc;
|
||||
return 0;
|
||||
}
|
||||
% clang++ -fsanitize=undefined test.cc
|
||||
% ./a.out
|
||||
test.cc:3:5: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
|
||||
|
||||
You can enable only a subset of :ref:`checks <ubsan-checks>` offered by UBSan,
|
||||
and define the desired behavior for each kind of check:
|
||||
|
||||
* print a verbose error report and continue execution (default);
|
||||
* print a verbose error report and exit the program;
|
||||
* execute a trap instruction (doesn't require UBSan run-time support).
|
||||
|
||||
For example if you compile/link your program as:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -fsanitize=signed-integer-overflow,null,alignment -fno-sanitize-recover=null -fsanitize-trap=alignment
|
||||
|
||||
the program will continue execution after signed integer overflows, exit after
|
||||
the first invalid use of a null pointer, and trap after the first use of misaligned
|
||||
pointer.
|
||||
|
||||
.. _ubsan-checks:
|
||||
|
||||
Availablle checks
|
||||
=================
|
||||
|
||||
Available checks are:
|
||||
|
||||
- ``-fsanitize=alignment``: Use of a misaligned pointer or creation
|
||||
of a misaligned reference.
|
||||
- ``-fsanitize=bool``: Load of a ``bool`` value which is neither
|
||||
``true`` nor ``false``.
|
||||
- ``-fsanitize=bounds``: Out of bounds array indexing, in cases
|
||||
where the array bound can be statically determined.
|
||||
- ``-fsanitize=enum``: Load of a value of an enumerated type which
|
||||
is not in the range of representable values for that enumerated
|
||||
type.
|
||||
- ``-fsanitize=float-cast-overflow``: Conversion to, from, or
|
||||
between floating-point types which would overflow the
|
||||
destination.
|
||||
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
||||
zero.
|
||||
- ``-fsanitize=function``: Indirect call of a function through a
|
||||
function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
|
||||
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
|
||||
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
|
||||
parameter which is declared to never be null.
|
||||
- ``-fsanitize=null``: Use of a null pointer or creation of a null
|
||||
reference.
|
||||
- ``-fsanitize=object-size``: An attempt to use bytes which the
|
||||
optimizer can determine are not part of the object being
|
||||
accessed. The sizes of objects are determined using
|
||||
``__builtin_object_size``, and consequently may be able to detect
|
||||
more problems at higher optimization levels.
|
||||
- ``-fsanitize=return``: In C++, reaching the end of a
|
||||
value-returning function without returning a value.
|
||||
- ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
|
||||
from a function which is declared to never return null.
|
||||
- ``-fsanitize=shift``: Shift operators where the amount shifted is
|
||||
greater or equal to the promoted bit-width of the left hand side
|
||||
or less than zero, or where the left hand side is negative. For a
|
||||
signed left shift, also checks for signed overflow in C, and for
|
||||
unsigned overflow in C++. You can use ``-fsanitize=shift-base`` or
|
||||
``-fsanitize=shift-exponent`` to check only left-hand side or
|
||||
right-hand side of shift operation, respectively.
|
||||
- ``-fsanitize=signed-integer-overflow``: Signed integer overflow,
|
||||
including all the checks added by ``-ftrapv``, and checking for
|
||||
overflow in signed division (``INT_MIN / -1``).
|
||||
- ``-fsanitize=unreachable``: If control flow reaches
|
||||
``__builtin_unreachable``.
|
||||
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer
|
||||
overflows.
|
||||
- ``-fsanitize=vla-bound``: A variable-length array whose bound
|
||||
does not evaluate to a positive value.
|
||||
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that
|
||||
it is of the wrong dynamic type, or that its lifetime has not
|
||||
begun or has ended. Incompatible with ``-fno-rtti``. Link must
|
||||
be performed by ``clang++``, not ``clang``, to make sure C++-specific
|
||||
parts of the runtime library and C++ standard libraries are present.
|
||||
|
||||
You can also use the following check groups:
|
||||
- ``-fsanitize=undefined``: All of the checks listed above other than
|
||||
``unsigned-integer-overflow``.
|
||||
- ``-fsanitize=undefined-trap``: Deprecated alias of
|
||||
``-fsanitize=undefined``.
|
||||
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
|
||||
behavior (e.g. unsigned integer overflow).
|
||||
|
||||
Stack traces and report symbolization
|
||||
=====================================
|
||||
If you want UBSan to print symbolized stack trace for each error report, you
|
||||
will need to:
|
||||
|
||||
#. Compile with ``-g`` and ``-fno-omit-frame-pointer`` to get proper debug
|
||||
information in your binary.
|
||||
#. Run your program with environment variable
|
||||
``UBSAN_OPTIONS=print_stacktrace=1``.
|
||||
#. Make sure ``llvm-symbolizer`` binary is in ``PATH``.
|
||||
|
||||
Issue Suppression
|
||||
=================
|
||||
|
||||
UndefinedBehaviorSanitizer is not expected to produce false positives.
|
||||
If you see one, look again; most likely it is a true positive!
|
||||
|
||||
Disabling Instrumentation with ``__attribute__((no_sanitize("undefined")))``
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
You disable UBSan checks for particular functions with
|
||||
``__attribute__((no_sanitize("undefined")))``. You can use all values of
|
||||
``-fsanitize=`` flag in this attribute, e.g. if your function deliberately
|
||||
contains possible signed integer overflow, you can use
|
||||
``__attribute__((no_sanitize("signed-integer-overflow")))``.
|
||||
|
||||
This attribute may not be
|
||||
supported by other compilers, so consider using it together with
|
||||
``#if defined(__clang__)``.
|
||||
|
||||
Suppressing Errors in Recompiled Code (Blacklist)
|
||||
-------------------------------------------------
|
||||
|
||||
UndefinedBehaviorSanitizer supports ``src`` and ``fun`` entity types in
|
||||
:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
|
||||
in the specified source files or functions.
|
||||
|
||||
Supported Platforms
|
||||
===================
|
||||
|
||||
UndefinedBehaviorSanitizer is supported on the following OS:
|
||||
|
||||
* Android
|
||||
* Linux
|
||||
* FreeBSD
|
||||
* OS X 10.6 onwards
|
||||
|
||||
and for the following architectures:
|
||||
|
||||
* i386/x86\_64
|
||||
* ARM
|
||||
* AArch64
|
||||
* PowerPC64
|
||||
* MIPS/MIPS64
|
||||
|
||||
Current Status
|
||||
==============
|
||||
|
||||
UndefinedBehaviorSanitizer is available on selected platforms starting from LLVM
|
||||
3.3. The test suite is integrated into the CMake build and can be run with
|
||||
``check-ubsan`` command.
|
||||
|
||||
More Information
|
||||
================
|
||||
|
||||
* From LLVM project blog:
|
||||
`What Every C Programmer Should Know About Undefined Behavior
|
||||
<http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html>`_
|
||||
* From John Regehr's *Embedded in Academia* blog:
|
||||
`A Guide to Undefined Behavior in C and C++
|
||||
<http://blog.regehr.org/archives/213>`_
|
@ -148,8 +148,8 @@ Formatting of Diagnostics
|
||||
|
||||
Clang aims to produce beautiful diagnostics by default, particularly for
|
||||
new users that first come to Clang. However, different people have
|
||||
different preferences, and sometimes Clang is driven by another program
|
||||
that wants to parse simple and consistent output, not a person. For
|
||||
different preferences, and sometimes Clang is driven not by a human,
|
||||
but by a program that wants consistent and easily parsable output. For
|
||||
these cases, Clang provides a wide range of options to control the exact
|
||||
output format of the diagnostics that it generates.
|
||||
|
||||
@ -952,26 +952,18 @@ are listed below.
|
||||
``-fsanitize=address``:
|
||||
:doc:`AddressSanitizer`, a memory error
|
||||
detector.
|
||||
- ``-fsanitize=integer``: Enables checks for undefined or
|
||||
suspicious integer behavior.
|
||||
- .. _opt_fsanitize_thread:
|
||||
|
||||
``-fsanitize=thread``: :doc:`ThreadSanitizer`, a data race detector.
|
||||
- .. _opt_fsanitize_memory:
|
||||
|
||||
``-fsanitize=memory``: :doc:`MemorySanitizer`,
|
||||
an *experimental* detector of uninitialized reads. Not ready for
|
||||
widespread use.
|
||||
a detector of uninitialized reads. Requires instrumentation of all
|
||||
program code.
|
||||
- .. _opt_fsanitize_undefined:
|
||||
|
||||
``-fsanitize=undefined``: Fast and compatible undefined behavior
|
||||
checker. Enables the undefined behavior checks that have small
|
||||
runtime cost and no impact on address space layout or ABI. This
|
||||
includes all of the checks listed below other than
|
||||
``unsigned-integer-overflow``.
|
||||
|
||||
- ``-fsanitize=undefined-trap``: This is a deprecated alias for
|
||||
``-fsanitize=undefined``.
|
||||
``-fsanitize=undefined``: :doc:`UndefinedBehaviorSanitizer`,
|
||||
a fast and compatible undefined behavior checker.
|
||||
|
||||
- ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
|
||||
flow analysis.
|
||||
@ -980,103 +972,17 @@ are listed below.
|
||||
- ``-fsanitize=safe-stack``: :doc:`safe stack <SafeStack>`
|
||||
protection against stack-based memory corruption errors.
|
||||
|
||||
The following more fine-grained checks are also available:
|
||||
|
||||
- ``-fsanitize=alignment``: Use of a misaligned pointer or creation
|
||||
of a misaligned reference.
|
||||
- ``-fsanitize=bool``: Load of a ``bool`` value which is neither
|
||||
``true`` nor ``false``.
|
||||
- ``-fsanitize=bounds``: Out of bounds array indexing, in cases
|
||||
where the array bound can be statically determined.
|
||||
- ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
|
||||
<cfi-strictness>`.
|
||||
- ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
|
||||
dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
|
||||
unrelated type to the wrong dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
|
||||
the wrong dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
|
||||
wrong dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=enum``: Load of a value of an enumerated type which
|
||||
is not in the range of representable values for that enumerated
|
||||
type.
|
||||
- ``-fsanitize=float-cast-overflow``: Conversion to, from, or
|
||||
between floating-point types which would overflow the
|
||||
destination.
|
||||
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
||||
zero.
|
||||
- ``-fsanitize=function``: Indirect call of a function through a
|
||||
function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
|
||||
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
|
||||
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
|
||||
parameter which is declared to never be null.
|
||||
- ``-fsanitize=null``: Use of a null pointer or creation of a null
|
||||
reference.
|
||||
- ``-fsanitize=object-size``: An attempt to use bytes which the
|
||||
optimizer can determine are not part of the object being
|
||||
accessed. The sizes of objects are determined using
|
||||
``__builtin_object_size``, and consequently may be able to detect
|
||||
more problems at higher optimization levels.
|
||||
- ``-fsanitize=return``: In C++, reaching the end of a
|
||||
value-returning function without returning a value.
|
||||
- ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
|
||||
from a function which is declared to never return null.
|
||||
- ``-fsanitize=shift``: Shift operators where the amount shifted is
|
||||
greater or equal to the promoted bit-width of the left hand side
|
||||
or less than zero, or where the left hand side is negative. For a
|
||||
signed left shift, also checks for signed overflow in C, and for
|
||||
unsigned overflow in C++. You can use ``-fsanitize=shift-base`` or
|
||||
``-fsanitize=shift-exponent`` to check only left-hand side or
|
||||
right-hand side of shift operation, respectively.
|
||||
- ``-fsanitize=signed-integer-overflow``: Signed integer overflow,
|
||||
including all the checks added by ``-ftrapv``, and checking for
|
||||
overflow in signed division (``INT_MIN / -1``).
|
||||
- ``-fsanitize=unreachable``: If control flow reaches
|
||||
``__builtin_unreachable``.
|
||||
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer
|
||||
overflows.
|
||||
- ``-fsanitize=vla-bound``: A variable-length array whose bound
|
||||
does not evaluate to a positive value.
|
||||
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that
|
||||
it is of the wrong dynamic type, or that its lifetime has not
|
||||
begun or has ended. Incompatible with ``-fno-rtti``.
|
||||
|
||||
You can turn off or modify checks for certain source files, functions
|
||||
or even variables by providing a special file:
|
||||
|
||||
- ``-fsanitize-blacklist=/path/to/blacklist/file``: disable or modify
|
||||
sanitizer checks for objects listed in the file. See
|
||||
:doc:`SanitizerSpecialCaseList` for file format description.
|
||||
- ``-fno-sanitize-blacklist``: don't use blacklist file, if it was
|
||||
specified earlier in the command line.
|
||||
|
||||
Extra features of MemorySanitizer (require explicit
|
||||
``-fsanitize=memory``):
|
||||
|
||||
- ``-fsanitize-memory-track-origins[=level]``: Enables origin tracking in
|
||||
MemorySanitizer. Adds a second section to MemorySanitizer
|
||||
reports pointing to the heap or stack allocation the
|
||||
uninitialized bits came from. Slows down execution by additional
|
||||
1.5x-2x.
|
||||
|
||||
Possible values for level are 0 (off), 1, 2 (default). Level 2
|
||||
adds more sections to MemorySanitizer reports describing the
|
||||
order of memory stores the uninitialized value went
|
||||
through. This mode may use extra memory in programs that copy
|
||||
uninitialized memory a lot.
|
||||
There are more fine-grained checks available: see
|
||||
the :ref:`list <ubsan-checks>` of specific kinds of
|
||||
undefined behavior that can be detected and the :ref:`list <cfi-schemes>`
|
||||
of control flow integrity schemes.
|
||||
|
||||
The ``-fsanitize=`` argument must also be provided when linking, in
|
||||
order to link to the appropriate runtime library. When using
|
||||
``-fsanitize=vptr`` (or a group that includes it, such as
|
||||
``-fsanitize=undefined``) with a C++ program, the link must be
|
||||
performed by ``clang++``, not ``clang``, in order to link against the
|
||||
C++-specific parts of the runtime library.
|
||||
order to link to the appropriate runtime library.
|
||||
|
||||
It is not possible to combine more than one of the ``-fsanitize=address``,
|
||||
``-fsanitize=thread``, and ``-fsanitize=memory`` checkers in the same
|
||||
program. The ``-fsanitize=undefined`` checks can only be combined with
|
||||
``-fsanitize=address``.
|
||||
program.
|
||||
|
||||
**-f[no-]sanitize-recover=check1,check2,...**
|
||||
|
||||
@ -1084,10 +990,12 @@ are listed below.
|
||||
If the check is fatal, program will halt after the first error
|
||||
of this kind is detected and error report is printed.
|
||||
|
||||
By default, non-fatal checks are those enabled by UndefinedBehaviorSanitizer,
|
||||
By default, non-fatal checks are those enabled by
|
||||
:doc:`UndefinedBehaviorSanitizer`,
|
||||
except for ``-fsanitize=return`` and ``-fsanitize=unreachable``. Some
|
||||
sanitizers (e.g. :doc:`AddressSanitizer`) may not support recovery,
|
||||
and always crash the program after the issue is detected.
|
||||
sanitizers may not support recovery (or not support it by default
|
||||
e.g. :doc:`AddressSanitizer`), and always crash the program after the issue
|
||||
is detected.
|
||||
|
||||
Note that the ``-fsanitize-trap`` flag has precedence over this flag.
|
||||
This means that if a check has been configured to trap elsewhere on the
|
||||
@ -1107,14 +1015,24 @@ are listed below.
|
||||
be used (for instance, when building libc or a kernel module), or where
|
||||
the binary size increase caused by the sanitizer runtime is a concern.
|
||||
|
||||
This flag is only compatible with ``local-bounds``,
|
||||
``unsigned-integer-overflow``, sanitizers in the ``cfi`` group and
|
||||
sanitizers in the ``undefined`` group other than ``vptr``. If this flag
|
||||
This flag is only compatible with :doc:`control flow integrity
|
||||
<ControlFlowIntegrity>` schemes and :doc:`UndefinedBehaviorSanitizer`
|
||||
checks other than ``vptr``. If this flag
|
||||
is supplied together with ``-fsanitize=undefined``, the ``vptr`` sanitizer
|
||||
will be implicitly disabled.
|
||||
|
||||
This flag is enabled by default for sanitizers in the ``cfi`` group.
|
||||
|
||||
.. option:: -fsanitize-blacklist=/path/to/blacklist/file
|
||||
|
||||
Disable or modify sanitizer checks for objects (source files, functions,
|
||||
variables, types) listed in the file. See
|
||||
:doc:`SanitizerSpecialCaseList` for file format description.
|
||||
|
||||
.. option:: -fno-sanitize-blacklist
|
||||
|
||||
Don't use blacklist file, if it was specified earlier in the command line.
|
||||
|
||||
**-f[no-]sanitize-coverage=[type,features,...]**
|
||||
|
||||
Enable simple code coverage in addition to certain sanitizers.
|
||||
@ -1124,6 +1042,12 @@ are listed below.
|
||||
|
||||
Deprecated alias for ``-fsanitize-trap=undefined``.
|
||||
|
||||
.. option:: -fsanitize-cfi-cross-dso
|
||||
|
||||
Enable cross-DSO control flow integrity checks. This flag modifies
|
||||
the behavior of sanitizers in the ``cfi`` group to allow checking
|
||||
of cross-DSO virtual and indirect calls.
|
||||
|
||||
.. option:: -fno-assume-sane-operator-new
|
||||
|
||||
Don't assume that the C++'s new operator is sane.
|
||||
@ -1157,6 +1081,13 @@ are listed below.
|
||||
efficient model can be used. The TLS model can be overridden per
|
||||
variable using the ``tls_model`` attribute.
|
||||
|
||||
.. option:: -femulated-tls
|
||||
|
||||
Select emulated TLS model, which overrides all -ftls-model choices.
|
||||
|
||||
In emulated TLS mode, all access to TLS variables are converted to
|
||||
calls to __emutls_get_address in the runtime library.
|
||||
|
||||
.. option:: -mhwdiv=[values]
|
||||
|
||||
Select the ARM modes (arm or thumb) that support hardware division
|
||||
@ -1183,7 +1114,7 @@ are listed below.
|
||||
This option restricts the generated code to use general registers
|
||||
only. This only applies to the AArch64 architecture.
|
||||
|
||||
**-f[no-]max-unknown-pointer-align=[number]**
|
||||
**-f[no-]max-type-align=[number]**
|
||||
Instruct the code generator to not enforce a higher alignment than the given
|
||||
number (of bytes) when accessing memory via an opaque pointer or reference.
|
||||
This cap is ignored when directly accessing a variable or when the pointee
|
||||
@ -1211,7 +1142,7 @@ are listed below.
|
||||
|
||||
void initialize_vector(__aligned_v16si *v) {
|
||||
// The compiler may assume that ‘v’ is 64-byte aligned, regardless of the
|
||||
// value of -fmax-unknown-pointer-align.
|
||||
// value of -fmax-type-align.
|
||||
}
|
||||
|
||||
|
||||
@ -1338,15 +1269,18 @@ read by the backend. LLVM supports three different sample profile formats:
|
||||
|
||||
1. ASCII text. This is the easiest one to generate. The file is divided into
|
||||
sections, which correspond to each of the functions with profile
|
||||
information. The format is described below.
|
||||
information. The format is described below. It can also be generated from
|
||||
the binary or gcov formats using the ``llvm-profdata`` tool.
|
||||
|
||||
2. Binary encoding. This uses a more efficient encoding that yields smaller
|
||||
profile files, which may be useful when generating large profiles. It can be
|
||||
generated from the text format using the ``llvm-profdata`` tool.
|
||||
profile files. This is the format generated by the ``create_llvm_prof`` tool
|
||||
in http://github.com/google/autofdo.
|
||||
|
||||
3. GCC encoding. This is based on the gcov format, which is accepted by GCC. It
|
||||
is only interesting in environments where GCC and Clang co-exist. Similarly
|
||||
to the binary encoding, it can be generated using the ``llvm-profdata`` tool.
|
||||
is only interesting in environments where GCC and Clang co-exist. This
|
||||
encoding is only generated by the ``create_gcov`` tool in
|
||||
http://github.com/google/autofdo. It can be read by LLVM and
|
||||
``llvm-profdata``, but it cannot be generated by either.
|
||||
|
||||
If you are using Linux Perf to generate sampling profiles, you can use the
|
||||
conversion tool ``create_llvm_prof`` described in the previous section.
|
||||
@ -1360,19 +1294,32 @@ Sample Profile Text Format
|
||||
This section describes the ASCII text format for sampling profiles. It is,
|
||||
arguably, the easiest one to generate. If you are interested in generating any
|
||||
of the other two, consult the ``ProfileData`` library in in LLVM's source tree
|
||||
(specifically, ``llvm/lib/ProfileData/SampleProfWriter.cpp``).
|
||||
(specifically, ``include/llvm/ProfileData/SampleProfReader.h``).
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
function1:total_samples:total_head_samples
|
||||
offset1[.discriminator]: number_of_samples [fn1:num fn2:num ... ]
|
||||
offset2[.discriminator]: number_of_samples [fn3:num fn4:num ... ]
|
||||
...
|
||||
offsetN[.discriminator]: number_of_samples [fn5:num fn6:num ... ]
|
||||
offset1[.discriminator]: number_of_samples [fn1:num fn2:num ... ]
|
||||
offset2[.discriminator]: number_of_samples [fn3:num fn4:num ... ]
|
||||
...
|
||||
offsetN[.discriminator]: number_of_samples [fn5:num fn6:num ... ]
|
||||
offsetA[.discriminator]: fnA:num_of_total_samples
|
||||
offsetA1[.discriminator]: number_of_samples [fn7:num fn8:num ... ]
|
||||
offsetA1[.discriminator]: number_of_samples [fn9:num fn10:num ... ]
|
||||
offsetB[.discriminator]: fnB:num_of_total_samples
|
||||
offsetB1[.discriminator]: number_of_samples [fn11:num fn12:num ... ]
|
||||
|
||||
The file may contain blank lines between sections and within a
|
||||
section. However, the spacing within a single line is fixed. Additional
|
||||
spaces will result in an error while reading the file.
|
||||
This is a nested tree in which the identation represents the nesting level
|
||||
of the inline stack. There are no blank lines in the file. And the spacing
|
||||
within a single line is fixed. Additional spaces will result in an error
|
||||
while reading the file.
|
||||
|
||||
Any line starting with the '#' character is completely ignored.
|
||||
|
||||
Inlined calls are represented with indentation. The Inline stack is a
|
||||
stack of source locations in which the top of the stack represents the
|
||||
leaf function, and the bottom of the stack represents the actual
|
||||
symbol to which the instruction belongs.
|
||||
|
||||
Function names must be mangled in order for the profile loader to
|
||||
match them in the current translation unit. The two numbers in the
|
||||
@ -1381,6 +1328,14 @@ function (first number), and the total number of samples accumulated
|
||||
in the prologue of the function (second number). This head sample
|
||||
count provides an indicator of how frequently the function is invoked.
|
||||
|
||||
There are two types of lines in the function body.
|
||||
|
||||
- Sampled line represents the profile information of a source location.
|
||||
``offsetN[.discriminator]: number_of_samples [fn5:num fn6:num ... ]``
|
||||
|
||||
- Callsite line represents the profile information of an inlined callsite.
|
||||
``offsetA[.discriminator]: fnA:num_of_total_samples``
|
||||
|
||||
Each sampled line may contain several items. Some are optional (marked
|
||||
below):
|
||||
|
||||
@ -1434,6 +1389,24 @@ d. [OPTIONAL] Potential call targets and samples. If present, this
|
||||
instruction that calls one of ``foo()``, ``bar()`` and ``baz()``,
|
||||
with ``baz()`` being the relatively more frequently called target.
|
||||
|
||||
As an example, consider a program with the call chain ``main -> foo -> bar``.
|
||||
When built with optimizations enabled, the compiler may inline the
|
||||
calls to ``bar`` and ``foo`` inside ``main``. The generated profile
|
||||
could then be something like this:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
main:35504:0
|
||||
1: _Z3foov:35504
|
||||
2: _Z32bari:31977
|
||||
1.1: 31977
|
||||
2: 0
|
||||
|
||||
This profile indicates that there were a total of 35,504 samples
|
||||
collected in main. All of those were at line 1 (the call to ``foo``).
|
||||
Of those, 31,977 were spent inside the body of ``bar``. The last line
|
||||
of the profile (``2: 0``) corresponds to line 2 inside ``main``. No
|
||||
samples were collected there.
|
||||
|
||||
Profiling with Instrumentation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -1527,9 +1500,25 @@ with respect to profile creation and use.
|
||||
profile file, it reads from that file. If ``pathname`` is a directory name,
|
||||
it reads from ``pathname/default.profdata``.
|
||||
|
||||
Disabling Instrumentation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In certain situations, it may be useful to disable profile generation or use
|
||||
for specific files in a build, without affecting the main compilation flags
|
||||
used for the other files in the project.
|
||||
|
||||
In these cases, you can use the flag ``-fno-profile-instr-generate`` (or
|
||||
``-fno-profile-generate``) to disable profile generation, and
|
||||
``-fno-profile-instr-use`` (or ``-fno-profile-use``) to disable profile use.
|
||||
|
||||
Note that these flags should appear after the corresponding profile
|
||||
flags to have an effect.
|
||||
|
||||
Controlling Debug Information
|
||||
-----------------------------
|
||||
|
||||
Controlling Size of Debug Information
|
||||
-------------------------------------
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Debug info kind generated by Clang can be set by one of the flags listed
|
||||
below. If multiple flags are present, the last one is used.
|
||||
@ -1573,6 +1562,21 @@ below. If multiple flags are present, the last one is used.
|
||||
|
||||
Generate complete debug info.
|
||||
|
||||
Controlling Debugger "Tuning"
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While Clang generally emits standard DWARF debug info (http://dwarfstd.org),
|
||||
different debuggers may know how to take advantage of different specific DWARF
|
||||
features. You can "tune" the debug info for one of several different debuggers.
|
||||
|
||||
.. option:: -ggdb, -glldb, -gsce
|
||||
|
||||
Tune the debug info for the ``gdb``, ``lldb``, or Sony Computer Entertainment
|
||||
debugger, respectively. Each of these options implies **-g**. (Therefore, if
|
||||
you want both **-gline-tables-only** and debugger tuning, the tuning option
|
||||
must come first.)
|
||||
|
||||
|
||||
Comment Parsing Options
|
||||
-----------------------
|
||||
|
||||
@ -1832,6 +1836,32 @@ Objective-C Language Features
|
||||
Objective-C++ Language Features
|
||||
===============================
|
||||
|
||||
.. _openmp:
|
||||
|
||||
OpenMP Features
|
||||
===============
|
||||
|
||||
Clang supports all OpenMP 3.1 directives and clauses. In addition, some
|
||||
features of OpenMP 4.0 are supported. For example, ``#pragma omp simd``,
|
||||
``#pragma omp for simd``, ``#pragma omp parallel for simd`` directives, extended
|
||||
set of atomic constructs, ``proc_bind`` clause for all parallel-based
|
||||
directives, ``depend`` clause for ``#pragma omp task`` directive (except for
|
||||
array sections), ``#pragma omp cancel`` and ``#pragma omp cancellation point``
|
||||
directives, and ``#pragma omp taskgroup`` directive.
|
||||
|
||||
Use :option:`-fopenmp` to enable OpenMP. Support for OpenMP can be disabled with
|
||||
:option:`-fno-openmp`.
|
||||
|
||||
Controlling implementation limits
|
||||
---------------------------------
|
||||
|
||||
.. option:: -fopenmp-use-tls
|
||||
|
||||
Controls code generation for OpenMP threadprivate variables. In presence of
|
||||
this option all threadprivate variables are generated the same way as thread
|
||||
local variables, using TLS support. If :option:`-fno-openmp-use-tls`
|
||||
is provided or target does not support TLS, code generation for threadprivate
|
||||
variables relies on OpenMP runtime library.
|
||||
|
||||
.. _target_features:
|
||||
|
||||
@ -2019,11 +2049,11 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
||||
/FI <value> Include file before parsing
|
||||
/Fi<file> Set preprocess output file name (with /P)
|
||||
/Fo<file or directory> Set output object file, or directory (ends in / or \) (with /c)
|
||||
/fp:except-
|
||||
/fp:except
|
||||
/fp:fast
|
||||
/fp:precise
|
||||
/fp:strict
|
||||
/fp:except-
|
||||
/fp:except
|
||||
/fp:fast
|
||||
/fp:precise
|
||||
/fp:strict
|
||||
/GA Assume thread-local variables are defined in the executable
|
||||
/GF- Disable string pooling
|
||||
/GR- Disable emission of RTTI data
|
||||
@ -2049,10 +2079,9 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
||||
/Oi Enable use of builtin functions
|
||||
/Os Optimize for size
|
||||
/Ot Optimize for speed
|
||||
/Ox Maximum optimization
|
||||
/Oy- Disable frame pointer omission
|
||||
/Oy Enable frame pointer omission
|
||||
/O<n> Optimization level
|
||||
/O<value> Optimization level
|
||||
/o <file or directory> Set output file or directory (ends in / or \)
|
||||
/P Preprocess to file
|
||||
/Qvec- Disable the loop vectorization passes
|
||||
@ -2075,11 +2104,12 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
||||
/W1 Enable -Wall
|
||||
/W2 Enable -Wall
|
||||
/W3 Enable -Wall
|
||||
/W4 Enable -Wall
|
||||
/W4 Enable -Wall and -Wextra
|
||||
/Wall Enable -Wall
|
||||
/WX- Do not treat warnings as errors
|
||||
/WX Treat warnings as errors
|
||||
/w Disable all warnings
|
||||
/Z7 Enable CodeView debug information in object files
|
||||
/Zc:sizedDealloc- Disable C++14 sized global deallocation functions
|
||||
/Zc:sizedDealloc Enable C++14 sized global deallocation functions
|
||||
/Zc:strictStrings Treat string literals as const
|
||||
@ -2087,7 +2117,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
||||
/Zc:threadSafeInit Enable thread-safe initialization of static variables
|
||||
/Zc:trigraphs- Disable trigraphs (default)
|
||||
/Zc:trigraphs Enable trigraphs
|
||||
/Zi Enable debug information
|
||||
/Zi Alias for /Z7. Does not produce PDBs.
|
||||
/Zl Don't mention any default libraries in the object file
|
||||
/Zp Set the default maximum struct packing alignment to 1
|
||||
/Zp<value> Specify the default maximum struct packing alignment
|
||||
/Zs Syntax-check only
|
||||
@ -2119,6 +2150,7 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
||||
-fsanitize-trap=<value> Enable trapping for specified sanitizers
|
||||
-fsanitize=<check> Turn on runtime checks for various forms of undefined or suspicious
|
||||
behavior. See user manual for available checks
|
||||
-gcodeview Generate CodeView debug information
|
||||
-mllvm <value> Additional arguments to forward to LLVM's option processing
|
||||
-Qunused-arguments Don't emit warning for unused driver arguments
|
||||
-R<remark> Enable the specified remark
|
||||
|
@ -138,6 +138,29 @@ ExprInspection checks
|
||||
clang_analyzer_warnIfReached(); // no-warning
|
||||
}
|
||||
|
||||
- void clang_analyzer_warnOnDeadSymbol(int);
|
||||
|
||||
Subscribe for a delayed warning when the symbol that represents the value of
|
||||
the argument is garbage-collected by the analyzer.
|
||||
|
||||
When calling 'clang_analyzer_warnOnDeadSymbol(x)', if value of 'x' is a
|
||||
symbol, then this symbol is marked by the ExprInspection checker. Then,
|
||||
during each garbage collection run, the checker sees if the marked symbol is
|
||||
being collected and issues the 'SYMBOL DEAD' warning if it does.
|
||||
This way you know where exactly, up to the line of code, the symbol dies.
|
||||
|
||||
It is unlikely that you call this function after the symbol is already dead,
|
||||
because the very reference to it as the function argument prevents it from
|
||||
dying. However, if the argument is not a symbol but a concrete value,
|
||||
no warning would be issued.
|
||||
|
||||
Example usage::
|
||||
|
||||
do {
|
||||
int x = generate_some_integer();
|
||||
clang_analyzer_warnOnDeadSymbol(x);
|
||||
} while(0); // expected-warning{{SYMBOL DEAD}}
|
||||
|
||||
|
||||
Statistics
|
||||
==========
|
||||
|
92
docs/analyzer/nullability.rst
Normal file
92
docs/analyzer/nullability.rst
Normal file
@ -0,0 +1,92 @@
|
||||
============
|
||||
Nullability Checks
|
||||
============
|
||||
|
||||
This document is a high level description of the nullablility checks.
|
||||
These checks intended to use the annotations that is described in this
|
||||
RFC: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2015-March/041798.html.
|
||||
|
||||
Let's consider the following 2 categories:
|
||||
|
||||
1) nullable
|
||||
============
|
||||
|
||||
If a pointer 'p' has a nullable annotation and no explicit null check or assert, we should warn in the following cases:
|
||||
- 'p' gets implicitly converted into nonnull pointer, for example, we are passing it to a function that takes a nonnull parameter.
|
||||
- 'p' gets dereferenced
|
||||
|
||||
Taking a branch on nullable pointers are the same like taking branch on null unspecified pointers.
|
||||
|
||||
Explicit cast from nullable to nonnul::
|
||||
|
||||
__nullable id foo;
|
||||
id bar = foo;
|
||||
takesNonNull((_nonnull) bar); <— should not warn here (backward compatibility hack)
|
||||
anotherTakesNonNull(bar); <— would be great to warn here, but not necessary(*)
|
||||
|
||||
Because bar corresponds to the same symbol all the time it is not easy to implement the checker that way the cast only suppress the first call but not the second. For this reason in the first implementation after a contradictory cast happens, I will treat bar as nullable unspecified, this way all of the warnings will be suppressed. Treating the symbol as nullable unspecified also has an advantage that in case the takesNonNull function body is being inlined, the will be no warning, when the symbol is dereferenced. In case I have time after the initial version I might spend additional time to try to find a more sophisticated solution, in which we would produce the second warning (*).
|
||||
|
||||
2) nonnull
|
||||
============
|
||||
|
||||
- Dereferencing a nonnull, or sending message to it is ok.
|
||||
- Converting nonnull to nullable is Ok.
|
||||
- When there is an explicit cast from nonnull to nullable I will trust the cast (it is probable there for a reason, because this cast does not suppress any warnings or errors).
|
||||
- But what should we do about null checks?::
|
||||
|
||||
__nonnull id takesNonnull(__nonnull id x) {
|
||||
if (x == nil) {
|
||||
// Defensive backward compatible code:
|
||||
....
|
||||
return nil; <- Should the analyzer cover this piece of code? Should we require the cast (__nonnull)nil?
|
||||
}
|
||||
....
|
||||
}
|
||||
|
||||
There are these directions:
|
||||
- We can either take the branch; this way the branch is analyzed
|
||||
- Should we not warn about any nullability issues in that branch? Probably not, it is ok to break the nullability postconditions when the nullability preconditions are violated.
|
||||
- We can assume that these pointers are not null and we lose coverage with the analyzer. (This can be implemented either in constraint solver or in the checker itself.)
|
||||
|
||||
Other Issues to keep in mind/take care of:
|
||||
Messaging:
|
||||
- Sending a message to a nullable pointer
|
||||
- Even though the method might return a nonnull pointer, when it was sent to a nullable pointer the return type will be nullable.
|
||||
- The result is nullable unless the receiver is known to be non null.
|
||||
- Sending a message to a unspecified or nonnull pointer
|
||||
- If the pointer is not assumed to be nil, we should be optimistic and use the nullability implied by the method.
|
||||
- This will not happen automatically, since the AST will have null unspecified in this case.
|
||||
|
||||
Inlining
|
||||
============
|
||||
|
||||
A symbol may need to be treated differently inside an inlined body. For example, consider these conversions from nonnull to nullable in presence of inlining::
|
||||
|
||||
id obj = getNonnull();
|
||||
takesNullable(obj);
|
||||
takesNonnull(obj);
|
||||
|
||||
void takesNullable(nullable id obj) {
|
||||
obj->ivar // we should assume obj is nullable and warn here
|
||||
}
|
||||
|
||||
With no special treatment, when the takesNullable is inlined the analyzer will not warn when the obj symbol is dereferenced. One solution for this is to reanalyze takesNullable as a top level function to get possible violations. The alternative method, deducing nullability information from the arguments after inlining is not robust enough (for example there might be more parameters with different nullability, but in the given path the two parameters might end up being the same symbol or there can be nested functions that take different view of the nullability of the same symbol). So the symbol will remain nonnull to avoid false positives but the functions that takes nullable parameters will be analyzed separately as well without inlining.
|
||||
|
||||
Annotations on multi level pointers
|
||||
============
|
||||
|
||||
Tracking multiple levels of annotations for pointers pointing to pointers would make the checker more complicated, because this way a vector of nullability qualifiers would be needed to be tracked for each symbol. This is not a big caveat, since once the top level pointer is dereferenced, the symvol for the inner pointer will have the nullability information. The lack of multi level annotation tracking only observable, when multiple levels of pointers are passed to a function which has a parameter with multiple levels of annotations. So for now the checker support the top level nullability qualifiers only.::
|
||||
|
||||
int * __nonnull * __nullable p;
|
||||
int ** q = p;
|
||||
takesStarNullableStarNullable(q);
|
||||
|
||||
Implementation notes
|
||||
============
|
||||
|
||||
What to track?
|
||||
- The checker would track memory regions, and to each relevant region a qualifier information would be attached which is either nullable, nonnull or null unspecified (or contradicted to suppress warnings for a specific region).
|
||||
- On a branch, where a nullable pointer is known to be non null, the checker treat it as a same way as a pointer annotated as nonnull.
|
||||
- When there is an explicit cast from a null unspecified to either nonnull or nullable I will trust the cast.
|
||||
- Unannotated pointers are treated the same way as pointers annotated with nullability unspecified qualifier, unless the region is wrapped in ASSUME_NONNULL macros.
|
||||
- We might want to implement a callback for entry points to top level functions, where the pointer nullability assumptions would be made.
|
@ -12,6 +12,7 @@
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
from datetime import date
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
@ -41,16 +42,16 @@
|
||||
|
||||
# General information about the project.
|
||||
project = u'Clang'
|
||||
copyright = u'2007-2015, The Clang Team'
|
||||
copyright = u'2007-%d, The Clang Team' % date.today().year
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '3.7'
|
||||
version = '3.8'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '3.7'
|
||||
release = '3.8'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -169,7 +169,7 @@ SHORT_NAMES = NO
|
||||
# description.)
|
||||
# The default value is: NO.
|
||||
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
|
||||
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
|
||||
# line (until the first dot) of a Qt-style comment as the brief description. If
|
||||
@ -177,7 +177,7 @@ JAVADOC_AUTOBRIEF = NO
|
||||
# requiring an explicit \brief command for a brief description.)
|
||||
# The default value is: NO.
|
||||
|
||||
QT_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = YES
|
||||
|
||||
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
|
||||
# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
|
||||
|
@ -24,6 +24,7 @@ Using Clang as a Compiler
|
||||
AddressSanitizer
|
||||
ThreadSanitizer
|
||||
MemorySanitizer
|
||||
UndefinedBehaviorSanitizer
|
||||
DataFlowSanitizer
|
||||
LeakSanitizer
|
||||
SanitizerCoverage
|
||||
|
@ -166,7 +166,7 @@ def act_on_decl(declaration, comment, allowed_types):
|
||||
\s*AST_POLYMORPHIC_SUPPORTED_TYPES\(([^)]*)\)
|
||||
\)\s*;\s*$""", declaration, flags=re.X)
|
||||
if m:
|
||||
loc, name, n_results, results = m.groups()[0:4]
|
||||
loc, name, results = m.groups()[0:3]
|
||||
result_types = [r.strip() for r in results.split(',')]
|
||||
|
||||
comment_result_types = extract_result_types(comment)
|
||||
@ -191,8 +191,8 @@ def act_on_decl(declaration, comment, allowed_types):
|
||||
\)\s*{\s*$""", declaration, flags=re.X)
|
||||
|
||||
if m:
|
||||
p, n, name, n_results, results = m.groups()[0:5]
|
||||
args = m.groups()[5:]
|
||||
p, n, name, results = m.groups()[0:4]
|
||||
args = m.groups()[4:]
|
||||
result_types = [r.strip() for r in results.split(',')]
|
||||
if allowed_types and allowed_types != result_types:
|
||||
raise Exception('Inconsistent documentation for: %s' % name)
|
||||
@ -364,6 +364,6 @@ def sort_table(matcher_type, matcher_map):
|
||||
reference = re.sub(r'<!-- START_TRAVERSAL_MATCHERS.*END_TRAVERSAL_MATCHERS -->',
|
||||
'%s', reference, flags=re.S) % traversal_matcher_table
|
||||
|
||||
with open('../LibASTMatchersReference.html', 'w') as output:
|
||||
with open('../LibASTMatchersReference.html', 'wb') as output:
|
||||
output.write(reference)
|
||||
|
||||
|
@ -36,14 +36,35 @@ def __init__(self, name, type, comment):
|
||||
self.type = type
|
||||
self.comment = comment.strip()
|
||||
self.enum = None
|
||||
self.nested_struct = None
|
||||
|
||||
def __str__(self):
|
||||
s = '**%s** (``%s``)\n%s' % (self.name, self.type,
|
||||
doxygen2rst(indent(self.comment, 2)))
|
||||
if self.enum:
|
||||
s += indent('\n\nPossible values:\n\n%s\n' % self.enum, 2)
|
||||
if self.nested_struct:
|
||||
s += indent('\n\nNested configuration flags:\n\n%s\n' %self.nested_struct,
|
||||
2)
|
||||
return s
|
||||
|
||||
class NestedStruct:
|
||||
def __init__(self, name, comment):
|
||||
self.name = name
|
||||
self.comment = comment.strip()
|
||||
self.values = []
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(map(str, self.values))
|
||||
|
||||
class NestedField:
|
||||
def __init__(self, name, comment):
|
||||
self.name = name
|
||||
self.comment = comment.strip()
|
||||
|
||||
def __str__(self):
|
||||
return '* ``%s`` %s' % (self.name, doxygen2rst(self.comment))
|
||||
|
||||
class Enum:
|
||||
def __init__(self, name, comment):
|
||||
self.name = name
|
||||
@ -65,18 +86,24 @@ def __str__(self):
|
||||
doxygen2rst(indent(self.comment, 2)))
|
||||
|
||||
def clean_comment_line(line):
|
||||
return line[3:].strip() + '\n'
|
||||
if line == '/// \\code':
|
||||
return '\n.. code-block:: c++\n\n'
|
||||
if line == '/// \\endcode':
|
||||
return ''
|
||||
return line[4:] + '\n'
|
||||
|
||||
def read_options(header):
|
||||
class State:
|
||||
BeforeStruct, Finished, InStruct, InFieldComment, InEnum, \
|
||||
InEnumMemberComment = range(6)
|
||||
BeforeStruct, Finished, InStruct, InNestedStruct, InNestedFieldComent, \
|
||||
InFieldComment, InEnum, InEnumMemberComment = range(8)
|
||||
state = State.BeforeStruct
|
||||
|
||||
options = []
|
||||
enums = {}
|
||||
nested_structs = {}
|
||||
comment = ''
|
||||
enum = None
|
||||
nested_struct = None
|
||||
|
||||
for line in header:
|
||||
line = line.strip()
|
||||
@ -97,13 +124,31 @@ class State:
|
||||
state = State.InEnum
|
||||
name = re.sub(r'enum\s+(\w+)\s*\{', '\\1', line)
|
||||
enum = Enum(name, comment)
|
||||
elif line.startswith('struct'):
|
||||
state = State.InNestedStruct
|
||||
name = re.sub(r'struct\s+(\w+)\s*\{', '\\1', line)
|
||||
nested_struct = NestedStruct(name, comment)
|
||||
elif line.endswith(';'):
|
||||
state = State.InStruct
|
||||
field_type, field_name = re.match(r'([<>:\w]+)\s+(\w+);', line).groups()
|
||||
field_type, field_name = re.match(r'([<>:\w(,\s)]+)\s+(\w+);',
|
||||
line).groups()
|
||||
option = Option(str(field_name), str(field_type), comment)
|
||||
options.append(option)
|
||||
else:
|
||||
raise Exception('Invalid format, expected comment, field or enum')
|
||||
elif state == State.InNestedStruct:
|
||||
if line.startswith('///'):
|
||||
state = State.InNestedFieldComent
|
||||
comment = clean_comment_line(line)
|
||||
elif line == '};':
|
||||
state = State.InStruct
|
||||
nested_structs[nested_struct.name] = nested_struct
|
||||
elif state == State.InNestedFieldComent:
|
||||
if line.startswith('///'):
|
||||
comment += clean_comment_line(line)
|
||||
else:
|
||||
state = State.InNestedStruct
|
||||
nested_struct.values.append(NestedField(line.replace(';', ''), comment))
|
||||
elif state == State.InEnum:
|
||||
if line.startswith('///'):
|
||||
state = State.InEnumMemberComment
|
||||
@ -124,9 +169,12 @@ class State:
|
||||
|
||||
for option in options:
|
||||
if not option.type in ['bool', 'unsigned', 'int', 'std::string',
|
||||
'std::vector<std::string>']:
|
||||
'std::vector<std::string>',
|
||||
'std::vector<IncludeCategory>']:
|
||||
if enums.has_key(option.type):
|
||||
option.enum = enums[option.type]
|
||||
elif nested_structs.has_key(option.type):
|
||||
option.nested_struct = nested_structs[option.type];
|
||||
else:
|
||||
raise Exception('Unknown type: %s' % option.type)
|
||||
return options
|
||||
@ -140,6 +188,6 @@ class State:
|
||||
|
||||
contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text)
|
||||
|
||||
with open(DOC_FILE, 'w') as output:
|
||||
with open(DOC_FILE, 'wb') as output:
|
||||
output.write(contents)
|
||||
|
||||
|
@ -30,7 +30,7 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const
|
||||
return;
|
||||
|
||||
if (II->isStr("main")) {
|
||||
ExplodedNode *N = C.generateSink();
|
||||
ExplodedNode *N = C.generateErrorNode();
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
|
@ -125,6 +125,12 @@ clang_CompileCommands_getCommand(CXCompileCommands, unsigned I);
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_CompileCommand_getDirectory(CXCompileCommand);
|
||||
|
||||
/**
|
||||
* \brief Get the filename associated with the CompileCommand.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_CompileCommand_getFilename(CXCompileCommand);
|
||||
|
||||
/**
|
||||
* \brief Get the number of arguments in the compiler invocation.
|
||||
*
|
||||
|
@ -40,6 +40,11 @@ typedef struct {
|
||||
unsigned private_flags;
|
||||
} CXString;
|
||||
|
||||
typedef struct {
|
||||
CXString *Strings;
|
||||
unsigned Count;
|
||||
} CXStringSet;
|
||||
|
||||
/**
|
||||
* \brief Retrieve the character data associated with the given string.
|
||||
*/
|
||||
@ -50,6 +55,11 @@ CINDEX_LINKAGE const char *clang_getCString(CXString string);
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_disposeString(CXString string);
|
||||
|
||||
/**
|
||||
* \brief Free the given string set.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_disposeStringSet(CXStringSet *set);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@
|
||||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||
*/
|
||||
#define CINDEX_VERSION_MAJOR 0
|
||||
#define CINDEX_VERSION_MINOR 30
|
||||
#define CINDEX_VERSION_MINOR 32
|
||||
|
||||
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
||||
((major) * 10000) \
|
||||
@ -285,7 +285,6 @@ CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex);
|
||||
*/
|
||||
typedef void *CXFile;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Retrieve the complete file and path name of the given file.
|
||||
*/
|
||||
@ -705,7 +704,6 @@ CINDEX_LINKAGE unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags);
|
||||
CINDEX_LINKAGE CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
|
||||
unsigned Index);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Describes the kind of error that occurred (if any) in a call to
|
||||
* \c clang_loadDiagnostics.
|
||||
@ -1202,7 +1200,15 @@ enum CXTranslationUnit_Flags {
|
||||
* included into the set of code completions returned from this translation
|
||||
* unit.
|
||||
*/
|
||||
CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80
|
||||
CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80,
|
||||
|
||||
/**
|
||||
* \brief Used to indicate that the precompiled preamble should be created on
|
||||
* the first parse. Otherwise it will be created on the first reparse. This
|
||||
* trades runtime on the first parse (serializing the preamble takes time) for
|
||||
* reduced runtime on the second parse (can now reuse the preamble).
|
||||
*/
|
||||
CXTranslationUnit_CreatePreambleOnFirstParse = 0x100
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1288,6 +1294,17 @@ clang_parseTranslationUnit2(CXIndex CIdx,
|
||||
unsigned options,
|
||||
CXTranslationUnit *out_TU);
|
||||
|
||||
/**
|
||||
* \brief Same as clang_parseTranslationUnit2 but requires a full command line
|
||||
* for \c command_line_args including argv[0]. This is useful if the standard
|
||||
* library paths are relative to the binary.
|
||||
*/
|
||||
CINDEX_LINKAGE enum CXErrorCode clang_parseTranslationUnit2FullArgv(
|
||||
CXIndex CIdx, const char *source_filename,
|
||||
const char *const *command_line_args, int num_command_line_args,
|
||||
struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files,
|
||||
unsigned options, CXTranslationUnit *out_TU);
|
||||
|
||||
/**
|
||||
* \brief Flags that control how translation units are saved.
|
||||
*
|
||||
@ -1573,7 +1590,7 @@ enum CXCursorKind {
|
||||
CXCursor_ObjCImplementationDecl = 18,
|
||||
/** \brief An Objective-C \@implementation for a category. */
|
||||
CXCursor_ObjCCategoryImplDecl = 19,
|
||||
/** \brief A typedef */
|
||||
/** \brief A typedef. */
|
||||
CXCursor_TypedefDecl = 20,
|
||||
/** \brief A C++ class method. */
|
||||
CXCursor_CXXMethod = 21,
|
||||
@ -1982,7 +1999,11 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_ObjCSelfExpr = 146,
|
||||
|
||||
CXCursor_LastExpr = CXCursor_ObjCSelfExpr,
|
||||
/** \brief OpenMP 4.0 [2.4, Array Section].
|
||||
*/
|
||||
CXCursor_OMPArraySectionExpr = 147,
|
||||
|
||||
CXCursor_LastExpr = CXCursor_OMPArraySectionExpr,
|
||||
|
||||
/* Statements */
|
||||
CXCursor_FirstStmt = 200,
|
||||
@ -2227,17 +2248,33 @@ enum CXCursorKind {
|
||||
|
||||
/** \brief OpenMP taskgroup directive.
|
||||
*/
|
||||
CXCursor_OMPTaskgroupDirective = 254,
|
||||
CXCursor_OMPTaskgroupDirective = 254,
|
||||
|
||||
/** \brief OpenMP cancellation point directive.
|
||||
*/
|
||||
CXCursor_OMPCancellationPointDirective = 255,
|
||||
CXCursor_OMPCancellationPointDirective = 255,
|
||||
|
||||
/** \brief OpenMP cancel directive.
|
||||
*/
|
||||
CXCursor_OMPCancelDirective = 256,
|
||||
CXCursor_OMPCancelDirective = 256,
|
||||
|
||||
CXCursor_LastStmt = CXCursor_OMPCancelDirective,
|
||||
/** \brief OpenMP target data directive.
|
||||
*/
|
||||
CXCursor_OMPTargetDataDirective = 257,
|
||||
|
||||
/** \brief OpenMP taskloop directive.
|
||||
*/
|
||||
CXCursor_OMPTaskLoopDirective = 258,
|
||||
|
||||
/** \brief OpenMP taskloop simd directive.
|
||||
*/
|
||||
CXCursor_OMPTaskLoopSimdDirective = 259,
|
||||
|
||||
/** \brief OpenMP distribute directive.
|
||||
*/
|
||||
CXCursor_OMPDistributeDirective = 260,
|
||||
|
||||
CXCursor_LastStmt = CXCursor_OMPDistributeDirective,
|
||||
|
||||
/**
|
||||
* \brief Cursor that represents the translation unit itself.
|
||||
@ -2271,7 +2308,10 @@ enum CXCursorKind {
|
||||
CXCursor_CUDAGlobalAttr = 414,
|
||||
CXCursor_CUDAHostAttr = 415,
|
||||
CXCursor_CUDASharedAttr = 416,
|
||||
CXCursor_LastAttr = CXCursor_CUDASharedAttr,
|
||||
CXCursor_VisibilityAttr = 417,
|
||||
CXCursor_DLLExport = 418,
|
||||
CXCursor_DLLImport = 419,
|
||||
CXCursor_LastAttr = CXCursor_DLLImport,
|
||||
|
||||
/* Preprocessing */
|
||||
CXCursor_PreprocessingDirective = 500,
|
||||
@ -2287,8 +2327,9 @@ enum CXCursorKind {
|
||||
* \brief A module import declaration.
|
||||
*/
|
||||
CXCursor_ModuleImportDecl = 600,
|
||||
CXCursor_TypeAliasTemplateDecl = 601,
|
||||
CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
|
||||
CXCursor_LastExtraDecl = CXCursor_ModuleImportDecl,
|
||||
CXCursor_LastExtraDecl = CXCursor_TypeAliasTemplateDecl,
|
||||
|
||||
/**
|
||||
* \brief A code completion overload candidate.
|
||||
@ -2439,6 +2480,32 @@ enum CXLinkageKind {
|
||||
*/
|
||||
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
|
||||
|
||||
enum CXVisibilityKind {
|
||||
/** \brief This value indicates that no visibility information is available
|
||||
* for a provided CXCursor. */
|
||||
CXVisibility_Invalid,
|
||||
|
||||
/** \brief Symbol not seen by the linker. */
|
||||
CXVisibility_Hidden,
|
||||
/** \brief Symbol seen by the linker but resolves to a symbol inside this object. */
|
||||
CXVisibility_Protected,
|
||||
/** \brief Symbol seen by the linker and acts like a normal symbol. */
|
||||
CXVisibility_Default
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describe the visibility of the entity referred to by a cursor.
|
||||
*
|
||||
* This returns the default visibility if not explicitly specified by
|
||||
* a visibility attribute. The default visibility may be changed by
|
||||
* commandline arguments.
|
||||
*
|
||||
* \param cursor The cursor to query.
|
||||
*
|
||||
* \returns The visibility of the cursor.
|
||||
*/
|
||||
CINDEX_LINKAGE enum CXVisibilityKind clang_getCursorVisibility(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Determine the availability of the entity that this cursor refers to,
|
||||
* taking the current target platform into account.
|
||||
@ -2558,7 +2625,6 @@ CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor);
|
||||
*/
|
||||
CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor);
|
||||
|
||||
|
||||
/**
|
||||
* \brief A fast container representing a set of CXCursors.
|
||||
*/
|
||||
@ -2851,7 +2917,8 @@ enum CXTypeKind {
|
||||
CXType_IncompleteArray = 114,
|
||||
CXType_VariableArray = 115,
|
||||
CXType_DependentSizedArray = 116,
|
||||
CXType_MemberPointer = 117
|
||||
CXType_MemberPointer = 117,
|
||||
CXType_Auto = 118
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2876,7 +2943,6 @@ enum CXCallingConv {
|
||||
CXCallingConv_Unexposed = 200
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief The type of an element in the abstract syntax tree.
|
||||
*
|
||||
@ -3314,7 +3380,6 @@ CINDEX_LINKAGE long long clang_Cursor_getOffsetOfField(CXCursor C);
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Cursor_isAnonymous(CXCursor C);
|
||||
|
||||
|
||||
enum CXRefQualifierKind {
|
||||
/** \brief No ref-qualifier was provided. */
|
||||
CXRefQualifier_None = 0,
|
||||
@ -3443,7 +3508,6 @@ CINDEX_LINKAGE CXCursor clang_getOverloadedDecl(CXCursor cursor,
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \brief For cursors representing an iboutletcollection attribute,
|
||||
* this function returns the collection element type.
|
||||
@ -3597,7 +3661,6 @@ CINDEX_LINKAGE CXString
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_constructUSR_ObjCProtocol(const char *protocol_name);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Construct a USR for a specified Objective-C instance variable and
|
||||
* the USR for its containing class.
|
||||
@ -3723,7 +3786,6 @@ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor);
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
|
||||
|
||||
|
||||
/**
|
||||
* \brief If the cursor points to a selector identifier in an Objective-C
|
||||
* method or message expression, this returns the selector index.
|
||||
@ -3853,6 +3915,12 @@ CINDEX_LINKAGE CXString clang_Cursor_getBriefCommentText(CXCursor C);
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the CXStrings representing the mangled symbols of the C++
|
||||
* constructor or destructor at the cursor.
|
||||
*/
|
||||
CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -3947,6 +4015,11 @@ CXFile clang_Module_getTopLevelHeader(CXTranslationUnit,
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Determine if a C++ field is declared 'mutable'.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXXField_isMutable(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Determine if a C++ member function or member function template is
|
||||
* pure virtual.
|
||||
@ -4939,8 +5012,7 @@ enum CXCursorKind clang_codeCompleteGetContainerKind(
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *Results);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns the currently-entered selector for an Objective-C message
|
||||
* send, formatted like "initWithFoo:bar:". Only guaranteed to return a
|
||||
@ -4959,7 +5031,6 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results);
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \defgroup CINDEX_MISC Miscellaneous utility functions
|
||||
*
|
||||
@ -4972,7 +5043,6 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results);
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getClangVersion(void);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Enable/disable crash recovery.
|
||||
*
|
||||
@ -5658,6 +5728,18 @@ CINDEX_LINKAGE int clang_indexSourceFile(CXIndexAction,
|
||||
CXTranslationUnit *out_TU,
|
||||
unsigned TU_options);
|
||||
|
||||
/**
|
||||
* \brief Same as clang_indexSourceFile but requires a full command line
|
||||
* for \c command_line_args including argv[0]. This is useful if the standard
|
||||
* library paths are relative to the binary.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_indexSourceFileFullArgv(
|
||||
CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks,
|
||||
unsigned index_callbacks_size, unsigned index_options,
|
||||
const char *source_filename, const char *const *command_line_args,
|
||||
int num_command_line_args, struct CXUnsavedFile *unsaved_files,
|
||||
unsigned num_unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options);
|
||||
|
||||
/**
|
||||
* \brief Index the given translation unit via callbacks implemented through
|
||||
* #IndexerCallbacks.
|
||||
@ -5739,7 +5821,6 @@ CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T,
|
||||
CXFieldVisitor visitor,
|
||||
CXClientData client_data);
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -5752,4 +5833,3 @@ CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T,
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "clang/Basic/AddressSpaces.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/Module.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/SanitizerBlacklist.h"
|
||||
@ -70,6 +71,7 @@ namespace clang {
|
||||
class VTableContextBase;
|
||||
|
||||
namespace Builtin { class Context; }
|
||||
enum BuiltinTemplateKind : int;
|
||||
|
||||
namespace comments {
|
||||
class FullComment;
|
||||
@ -176,8 +178,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
ClassScopeSpecializationPattern;
|
||||
|
||||
/// \brief Mapping from materialized temporaries with static storage duration
|
||||
/// that appear in constant initializers to their evaluated values.
|
||||
llvm::DenseMap<const MaterializeTemporaryExpr*, APValue>
|
||||
/// that appear in constant initializers to their evaluated values. These are
|
||||
/// allocated in a std::map because their address must be stable.
|
||||
llvm::DenseMap<const MaterializeTemporaryExpr *, APValue *>
|
||||
MaterializedTemporaryValues;
|
||||
|
||||
/// \brief Representation of a "canonical" template template parameter that
|
||||
@ -215,6 +218,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// __builtin_va_list type.
|
||||
mutable TypedefDecl *BuiltinVaListDecl;
|
||||
|
||||
/// The typedef for the predefined \c __builtin_ms_va_list type.
|
||||
mutable TypedefDecl *BuiltinMSVaListDecl;
|
||||
|
||||
/// \brief The typedef for the predefined \c id type.
|
||||
mutable TypedefDecl *ObjCIdDecl;
|
||||
|
||||
@ -242,6 +248,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// The identifier 'NSCopying'.
|
||||
IdentifierInfo *NSCopyingName = nullptr;
|
||||
|
||||
/// The identifier '__make_integer_seq'.
|
||||
mutable IdentifierInfo *MakeIntegerSeqName = nullptr;
|
||||
|
||||
QualType ObjCConstantStringType;
|
||||
mutable RecordDecl *CFConstantStringTypeDecl;
|
||||
|
||||
@ -395,6 +404,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
mutable ExternCContextDecl *ExternCContext;
|
||||
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl;
|
||||
|
||||
/// \brief The associated SourceManager object.a
|
||||
SourceManager &SourceMgr;
|
||||
@ -433,6 +443,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
const TargetInfo *Target;
|
||||
const TargetInfo *AuxTarget;
|
||||
clang::PrintingPolicy PrintingPolicy;
|
||||
|
||||
public:
|
||||
@ -446,10 +457,59 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// \brief Contains parents of a node.
|
||||
typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 2> ParentVector;
|
||||
|
||||
/// \brief Maps from a node to its parents.
|
||||
/// \brief Maps from a node to its parents. This is used for nodes that have
|
||||
/// pointer identity only, which are more common and we can save space by
|
||||
/// only storing a unique pointer to them.
|
||||
typedef llvm::DenseMap<const void *,
|
||||
llvm::PointerUnion<ast_type_traits::DynTypedNode *,
|
||||
ParentVector *>> ParentMap;
|
||||
llvm::PointerUnion4<const Decl *, const Stmt *,
|
||||
ast_type_traits::DynTypedNode *,
|
||||
ParentVector *>> ParentMapPointers;
|
||||
|
||||
/// Parent map for nodes without pointer identity. We store a full
|
||||
/// DynTypedNode for all keys.
|
||||
typedef llvm::DenseMap<
|
||||
ast_type_traits::DynTypedNode,
|
||||
llvm::PointerUnion4<const Decl *, const Stmt *,
|
||||
ast_type_traits::DynTypedNode *, ParentVector *>>
|
||||
ParentMapOtherNodes;
|
||||
|
||||
/// Container for either a single DynTypedNode or for an ArrayRef to
|
||||
/// DynTypedNode. For use with ParentMap.
|
||||
class DynTypedNodeList {
|
||||
typedef ast_type_traits::DynTypedNode DynTypedNode;
|
||||
llvm::AlignedCharArrayUnion<ast_type_traits::DynTypedNode,
|
||||
ArrayRef<DynTypedNode>> Storage;
|
||||
bool IsSingleNode;
|
||||
|
||||
public:
|
||||
DynTypedNodeList(const DynTypedNode &N) : IsSingleNode(true) {
|
||||
new (Storage.buffer) DynTypedNode(N);
|
||||
}
|
||||
DynTypedNodeList(ArrayRef<DynTypedNode> A) : IsSingleNode(false) {
|
||||
new (Storage.buffer) ArrayRef<DynTypedNode>(A);
|
||||
}
|
||||
|
||||
const ast_type_traits::DynTypedNode *begin() const {
|
||||
if (!IsSingleNode)
|
||||
return reinterpret_cast<const ArrayRef<DynTypedNode> *>(Storage.buffer)
|
||||
->begin();
|
||||
return reinterpret_cast<const DynTypedNode *>(Storage.buffer);
|
||||
}
|
||||
|
||||
const ast_type_traits::DynTypedNode *end() const {
|
||||
if (!IsSingleNode)
|
||||
return reinterpret_cast<const ArrayRef<DynTypedNode> *>(Storage.buffer)
|
||||
->end();
|
||||
return reinterpret_cast<const DynTypedNode *>(Storage.buffer) + 1;
|
||||
}
|
||||
|
||||
size_t size() const { return end() - begin(); }
|
||||
bool empty() const { return begin() == end(); }
|
||||
const DynTypedNode &operator[](size_t N) const {
|
||||
assert(N < size() && "Out of bounds!");
|
||||
return *(begin() + N);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Returns the parents of the given node.
|
||||
///
|
||||
@ -475,13 +535,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
///
|
||||
/// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc,
|
||||
/// NestedNameSpecifier or NestedNameSpecifierLoc.
|
||||
template <typename NodeT>
|
||||
ArrayRef<ast_type_traits::DynTypedNode> getParents(const NodeT &Node) {
|
||||
template <typename NodeT> DynTypedNodeList getParents(const NodeT &Node) {
|
||||
return getParents(ast_type_traits::DynTypedNode::create(Node));
|
||||
}
|
||||
|
||||
ArrayRef<ast_type_traits::DynTypedNode>
|
||||
getParents(const ast_type_traits::DynTypedNode &Node);
|
||||
DynTypedNodeList getParents(const ast_type_traits::DynTypedNode &Node);
|
||||
|
||||
const clang::PrintingPolicy &getPrintingPolicy() const {
|
||||
return PrintingPolicy;
|
||||
@ -501,6 +559,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
void *Allocate(size_t Size, unsigned Align = 8) const {
|
||||
return BumpAlloc.Allocate(Size, Align);
|
||||
}
|
||||
template <typename T> T *Allocate(size_t Num = 1) const {
|
||||
return static_cast<T *>(Allocate(Num * sizeof(T), llvm::alignOf<T>()));
|
||||
}
|
||||
void Deallocate(void *Ptr) const { }
|
||||
|
||||
/// Return the total amount of physical memory allocated for representing
|
||||
@ -516,7 +577,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
}
|
||||
|
||||
const TargetInfo &getTargetInfo() const { return *Target; }
|
||||
|
||||
const TargetInfo *getAuxTargetInfo() const { return AuxTarget; }
|
||||
|
||||
/// getIntTypeForBitwidth -
|
||||
/// sets integer QualTy according to specified details:
|
||||
/// bitwidth, signed/unsigned.
|
||||
@ -812,6 +874,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
|
||||
|
||||
ExternCContextDecl *getExternCContextDecl() const;
|
||||
BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
|
||||
|
||||
// Builtin Types.
|
||||
CanQualType VoidTy;
|
||||
@ -835,17 +898,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
|
||||
CanQualType ObjCBuiltinBoolTy;
|
||||
CanQualType OCLImage1dTy, OCLImage1dArrayTy, OCLImage1dBufferTy;
|
||||
CanQualType OCLImage2dTy, OCLImage2dArrayTy;
|
||||
CanQualType OCLImage2dTy, OCLImage2dArrayTy, OCLImage2dDepthTy;
|
||||
CanQualType OCLImage2dArrayDepthTy, OCLImage2dMSAATy, OCLImage2dArrayMSAATy;
|
||||
CanQualType OCLImage2dMSAADepthTy, OCLImage2dArrayMSAADepthTy;
|
||||
CanQualType OCLImage3dTy;
|
||||
CanQualType OCLSamplerTy, OCLEventTy;
|
||||
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
|
||||
CanQualType OCLQueueTy, OCLNDRangeTy, OCLReserveIDTy;
|
||||
CanQualType OMPArraySectionTy;
|
||||
|
||||
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
|
||||
mutable QualType AutoDeductTy; // Deduction against 'auto'.
|
||||
mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'.
|
||||
|
||||
// Type used to help define __builtin_va_list for some targets.
|
||||
// The type is built when constructing 'BuiltinVaListDecl'.
|
||||
mutable QualType VaListTagTy;
|
||||
// Decl used to help define __builtin_va_list for some targets.
|
||||
// The decl is built when constructing 'BuiltinVaListDecl'.
|
||||
mutable Decl *VaListTagDecl;
|
||||
|
||||
ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents,
|
||||
SelectorTable &sels, Builtin::Context &builtins);
|
||||
@ -881,6 +948,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
void PrintStats() const;
|
||||
const SmallVectorImpl<Type *>& getTypes() const { return Types; }
|
||||
|
||||
BuiltinTemplateDecl *buildBuiltinTemplateDecl(BuiltinTemplateKind BTK,
|
||||
const IdentifierInfo *II) const;
|
||||
|
||||
/// \brief Create a new implicit TU-level CXXRecordDecl or RecordDecl
|
||||
/// declaration.
|
||||
RecordDecl *buildImplicitRecord(StringRef Name,
|
||||
@ -955,6 +1025,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
const FunctionType *adjustFunctionType(const FunctionType *Fn,
|
||||
FunctionType::ExtInfo EInfo);
|
||||
|
||||
/// Adjust the given function result type.
|
||||
CanQualType getCanonicalFunctionResultType(QualType ResultType) const;
|
||||
|
||||
/// \brief Change the result type of a function type once it is deduced.
|
||||
void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType);
|
||||
|
||||
@ -1227,7 +1300,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
UnaryTransformType::UTTKind UKind) const;
|
||||
|
||||
/// \brief C++11 deduced auto type.
|
||||
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
|
||||
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
|
||||
bool IsDependent) const;
|
||||
|
||||
/// \brief C++11 deduction pattern for 'auto' type.
|
||||
@ -1381,6 +1454,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
return NSCopyingName;
|
||||
}
|
||||
|
||||
IdentifierInfo *getMakeIntegerSeqName() const {
|
||||
if (!MakeIntegerSeqName)
|
||||
MakeIntegerSeqName = &Idents.get("__make_integer_seq");
|
||||
return MakeIntegerSeqName;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the Objective-C "instancetype" type, if already known;
|
||||
/// otherwise, returns a NULL type;
|
||||
QualType getObjCInstanceType() {
|
||||
@ -1569,7 +1648,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// \brief Retrieve the C type declaration corresponding to the predefined
|
||||
/// \c __va_list_tag type used to help define the \c __builtin_va_list type
|
||||
/// for some targets.
|
||||
QualType getVaListTagType() const;
|
||||
Decl *getVaListTagDecl() const;
|
||||
|
||||
/// Retrieve the C type declaration corresponding to the predefined
|
||||
/// \c __builtin_ms_va_list type.
|
||||
TypedefDecl *getBuiltinMSVaListDecl() const;
|
||||
|
||||
/// Retrieve the type of the \c __builtin_ms_va_list type.
|
||||
QualType getBuiltinMSVaListType() const {
|
||||
return getTypeDeclType(getBuiltinMSVaListDecl());
|
||||
}
|
||||
|
||||
/// \brief Return a type with additional \c const, \c volatile, or
|
||||
/// \c restrict qualifiers.
|
||||
@ -1774,7 +1862,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// record (struct/union/class) \p D, which indicates its size and field
|
||||
/// position information.
|
||||
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const;
|
||||
const ASTRecordLayout *BuildMicrosoftASTRecordLayout(const RecordDecl *D) const;
|
||||
|
||||
/// \brief Get or compute information about the layout of the specified
|
||||
/// Objective-C interface.
|
||||
@ -2170,9 +2257,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
const FunctionProtoType *FromFunctionType,
|
||||
const FunctionProtoType *ToFunctionType);
|
||||
|
||||
void ResetObjCLayout(const ObjCContainerDecl *CD) {
|
||||
ObjCLayouts[CD] = nullptr;
|
||||
}
|
||||
void ResetObjCLayout(const ObjCContainerDecl *CD);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Integer Predicates
|
||||
@ -2187,16 +2272,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
// corresponding unsigned integer type.
|
||||
QualType getCorrespondingUnsignedType(QualType T) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Iterators.
|
||||
//===--------------------------------------------------------------------===//
|
||||
typedef llvm::iterator_range<SmallVectorImpl<Type *>::const_iterator>
|
||||
type_const_range;
|
||||
|
||||
type_const_range types() const {
|
||||
return type_const_range(Types.begin(), Types.end());
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Integer Values
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -2233,16 +2308,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
/// \brief Get the duplicate declaration of a ObjCMethod in the same
|
||||
/// interface, or null if none exists.
|
||||
const ObjCMethodDecl *getObjCMethodRedeclaration(
|
||||
const ObjCMethodDecl *MD) const {
|
||||
return ObjCMethodRedecls.lookup(MD);
|
||||
}
|
||||
const ObjCMethodDecl *
|
||||
getObjCMethodRedeclaration(const ObjCMethodDecl *MD) const;
|
||||
|
||||
void setObjCMethodRedeclaration(const ObjCMethodDecl *MD,
|
||||
const ObjCMethodDecl *Redecl) {
|
||||
assert(!getObjCMethodRedeclaration(MD) && "MD already has a redeclaration");
|
||||
ObjCMethodRedecls[MD] = Redecl;
|
||||
}
|
||||
const ObjCMethodDecl *Redecl);
|
||||
|
||||
/// \brief Returns the Objective-C interface that \p ND belongs to if it is
|
||||
/// an Objective-C method/property/ivar etc. that is part of an interface,
|
||||
@ -2307,6 +2377,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx);
|
||||
|
||||
void addTypedefNameForUnnamedTagDecl(TagDecl *TD, TypedefNameDecl *TND);
|
||||
|
||||
TypedefNameDecl *getTypedefNameForUnnamedTagDecl(const TagDecl *TD);
|
||||
|
||||
void addDeclaratorForUnnamedTagDecl(TagDecl *TD, DeclaratorDecl *DD);
|
||||
|
||||
DeclaratorDecl *getDeclaratorForUnnamedTagDecl(const TagDecl *TD);
|
||||
|
||||
void setManglingNumber(const NamedDecl *ND, unsigned Number);
|
||||
unsigned getManglingNumber(const NamedDecl *ND) const;
|
||||
|
||||
@ -2388,9 +2466,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// This routine may only be invoked once for a given ASTContext object.
|
||||
/// It is normally invoked after ASTContext construction.
|
||||
///
|
||||
/// \param Target The target
|
||||
void InitBuiltinTypes(const TargetInfo &Target);
|
||||
|
||||
/// \param Target The target
|
||||
void InitBuiltinTypes(const TargetInfo &Target,
|
||||
const TargetInfo *AuxTarget = nullptr);
|
||||
|
||||
private:
|
||||
void InitBuiltinType(CanQualType &R, BuiltinType::Kind K);
|
||||
|
||||
@ -2429,9 +2508,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
/// \brief A set of deallocations that should be performed when the
|
||||
/// ASTContext is destroyed.
|
||||
typedef llvm::SmallDenseMap<void(*)(void*), llvm::SmallVector<void*, 16> >
|
||||
DeallocationMap;
|
||||
DeallocationMap Deallocations;
|
||||
// FIXME: We really should have a better mechanism in the ASTContext to
|
||||
// manage running destructors for types which do variable sized allocation
|
||||
// within the AST. In some places we thread the AST bump pointer allocator
|
||||
// into the datastructures which avoids this mess during deallocation but is
|
||||
// wasteful of memory, and here we require a lot of error prone book keeping
|
||||
// in order to track and run destructors while we're tearing things down.
|
||||
typedef llvm::SmallVector<std::pair<void (*)(void *), void *>, 16>
|
||||
DeallocationFunctionsAndArguments;
|
||||
DeallocationFunctionsAndArguments Deallocations;
|
||||
|
||||
// FIXME: This currently contains the set of StoredDeclMaps used
|
||||
// by DeclContext objects. This probably should not be in ASTContext,
|
||||
@ -2443,7 +2528,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
void ReleaseDeclContextMaps();
|
||||
void ReleaseParentMapEntries();
|
||||
|
||||
std::unique_ptr<ParentMap> AllParents;
|
||||
std::unique_ptr<ParentMapPointers> PointerParents;
|
||||
std::unique_ptr<ParentMapOtherNodes> OtherParents;
|
||||
|
||||
std::unique_ptr<VTableContextBase> VTContext;
|
||||
|
||||
|
@ -92,18 +92,6 @@ class ASTMutationListener {
|
||||
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
|
||||
const ObjCInterfaceDecl *IFD) {}
|
||||
|
||||
/// \brief A objc class extension redeclared or introduced a property.
|
||||
///
|
||||
/// \param Prop the property in the class extension
|
||||
///
|
||||
/// \param OrigProp the property from the original interface that was declared
|
||||
/// or null if the property was introduced.
|
||||
///
|
||||
/// \param ClassExt the class extension.
|
||||
virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
|
||||
const ObjCPropertyDecl *OrigProp,
|
||||
const ObjCCategoryDecl *ClassExt) {}
|
||||
|
||||
/// \brief A declaration is marked used which was not previously marked used.
|
||||
///
|
||||
/// \param D the declaration marked used
|
||||
|
@ -106,18 +106,25 @@ class ASTNodeKind {
|
||||
}
|
||||
};
|
||||
|
||||
/// Check if the given ASTNodeKind identifies a type that offers pointer
|
||||
/// identity. This is useful for the fast path in DynTypedNode.
|
||||
bool hasPointerIdentity() const {
|
||||
return KindId > NKI_LastKindWithoutPointerIdentity;
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Kind ids.
|
||||
///
|
||||
/// Includes all possible base and derived kinds.
|
||||
enum NodeKindId {
|
||||
NKI_None,
|
||||
NKI_CXXCtorInitializer,
|
||||
NKI_TemplateArgument,
|
||||
NKI_NestedNameSpecifier,
|
||||
NKI_NestedNameSpecifierLoc,
|
||||
NKI_QualType,
|
||||
NKI_TypeLoc,
|
||||
NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc,
|
||||
NKI_CXXCtorInitializer,
|
||||
NKI_NestedNameSpecifier,
|
||||
NKI_Decl,
|
||||
#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
@ -238,7 +245,11 @@ class DynTypedNode {
|
||||
/// Note that this is not supported by all AST nodes. For AST nodes
|
||||
/// that don't have a pointer-defined identity inside the AST, this
|
||||
/// method returns NULL.
|
||||
const void *getMemoizationData() const { return MemoizationData; }
|
||||
const void *getMemoizationData() const {
|
||||
return NodeKind.hasPointerIdentity()
|
||||
? *reinterpret_cast<void *const *>(Storage.buffer)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/// \brief Prints the node to the given output stream.
|
||||
void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
|
||||
@ -257,6 +268,32 @@ class DynTypedNode {
|
||||
/// FIXME: Implement comparsion for other node types (currently
|
||||
/// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
|
||||
bool operator<(const DynTypedNode &Other) const {
|
||||
if (!NodeKind.isSame(Other.NodeKind))
|
||||
return NodeKind < Other.NodeKind;
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
|
||||
return getUnchecked<QualType>().getAsOpaquePtr() <
|
||||
Other.getUnchecked<QualType>().getAsOpaquePtr();
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) {
|
||||
auto TLA = getUnchecked<TypeLoc>();
|
||||
auto TLB = Other.getUnchecked<TypeLoc>();
|
||||
return std::make_pair(TLA.getType().getAsOpaquePtr(),
|
||||
TLA.getOpaqueData()) <
|
||||
std::make_pair(TLB.getType().getAsOpaquePtr(),
|
||||
TLB.getOpaqueData());
|
||||
}
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
|
||||
NodeKind)) {
|
||||
auto NNSLA = getUnchecked<NestedNameSpecifierLoc>();
|
||||
auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>();
|
||||
return std::make_pair(NNSLA.getNestedNameSpecifier(),
|
||||
NNSLA.getOpaqueData()) <
|
||||
std::make_pair(NNSLB.getNestedNameSpecifier(),
|
||||
NNSLB.getOpaqueData());
|
||||
}
|
||||
|
||||
assert(getMemoizationData() && Other.getMemoizationData());
|
||||
return getMemoizationData() < Other.getMemoizationData();
|
||||
}
|
||||
@ -270,6 +307,13 @@ class DynTypedNode {
|
||||
if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
|
||||
return getUnchecked<QualType>() == Other.getUnchecked<QualType>();
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind))
|
||||
return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>();
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(NodeKind))
|
||||
return getUnchecked<NestedNameSpecifierLoc>() ==
|
||||
Other.getUnchecked<NestedNameSpecifierLoc>();
|
||||
|
||||
assert(getMemoizationData() && Other.getMemoizationData());
|
||||
return getMemoizationData() == Other.getMemoizationData();
|
||||
}
|
||||
@ -278,6 +322,47 @@ class DynTypedNode {
|
||||
}
|
||||
/// @}
|
||||
|
||||
/// \brief Hooks for using DynTypedNode as a key in a DenseMap.
|
||||
struct DenseMapInfo {
|
||||
static inline DynTypedNode getEmptyKey() {
|
||||
DynTypedNode Node;
|
||||
Node.NodeKind = ASTNodeKind::DenseMapInfo::getEmptyKey();
|
||||
return Node;
|
||||
}
|
||||
static inline DynTypedNode getTombstoneKey() {
|
||||
DynTypedNode Node;
|
||||
Node.NodeKind = ASTNodeKind::DenseMapInfo::getTombstoneKey();
|
||||
return Node;
|
||||
}
|
||||
static unsigned getHashValue(const DynTypedNode &Val) {
|
||||
// FIXME: Add hashing support for the remaining types.
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(Val.NodeKind)) {
|
||||
auto TL = Val.getUnchecked<TypeLoc>();
|
||||
return llvm::hash_combine(TL.getType().getAsOpaquePtr(),
|
||||
TL.getOpaqueData());
|
||||
}
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
|
||||
Val.NodeKind)) {
|
||||
auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>();
|
||||
return llvm::hash_combine(NNSL.getNestedNameSpecifier(),
|
||||
NNSL.getOpaqueData());
|
||||
}
|
||||
|
||||
assert(Val.getMemoizationData());
|
||||
return llvm::hash_value(Val.getMemoizationData());
|
||||
}
|
||||
static bool isEqual(const DynTypedNode &LHS, const DynTypedNode &RHS) {
|
||||
auto Empty = ASTNodeKind::DenseMapInfo::getEmptyKey();
|
||||
auto TombStone = ASTNodeKind::DenseMapInfo::getTombstoneKey();
|
||||
return (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, Empty) &&
|
||||
ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, Empty)) ||
|
||||
(ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, TombStone) &&
|
||||
ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, TombStone)) ||
|
||||
LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief Takes care of converting from and to \c T.
|
||||
template <typename T, typename EnablerT = void> struct BaseConverter;
|
||||
@ -286,18 +371,18 @@ class DynTypedNode {
|
||||
template <typename T, typename BaseT> struct DynCastPtrConverter {
|
||||
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))
|
||||
return cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
|
||||
return &getUnchecked(NodeKind, Storage);
|
||||
return nullptr;
|
||||
}
|
||||
static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind));
|
||||
return *cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
|
||||
return *cast<T>(static_cast<const BaseT *>(
|
||||
*reinterpret_cast<const void *const *>(Storage)));
|
||||
}
|
||||
static DynTypedNode create(const BaseT &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.NodeKind = ASTNodeKind::getFromNode(Node);
|
||||
Result.MemoizationData = &Node;
|
||||
new (Result.Storage.buffer) const BaseT * (&Node);
|
||||
new (Result.Storage.buffer) const void *(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
@ -306,18 +391,18 @@ class DynTypedNode {
|
||||
template <typename T> struct PtrConverter {
|
||||
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
|
||||
return *reinterpret_cast<T *const *>(Storage);
|
||||
return &getUnchecked(NodeKind, Storage);
|
||||
return nullptr;
|
||||
}
|
||||
static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind));
|
||||
return **reinterpret_cast<T *const *>(Storage);
|
||||
return *static_cast<const T *>(
|
||||
*reinterpret_cast<const void *const *>(Storage));
|
||||
}
|
||||
static DynTypedNode create(const T &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
|
||||
Result.MemoizationData = &Node;
|
||||
new (Result.Storage.buffer) const T * (&Node);
|
||||
new (Result.Storage.buffer) const void *(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
@ -336,14 +421,12 @@ class DynTypedNode {
|
||||
static DynTypedNode create(const T &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
|
||||
Result.MemoizationData = nullptr;
|
||||
new (Result.Storage.buffer) T(Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
|
||||
ASTNodeKind NodeKind;
|
||||
const void *MemoizationData;
|
||||
|
||||
/// \brief Stores the data of the node.
|
||||
///
|
||||
@ -353,12 +436,9 @@ class DynTypedNode {
|
||||
/// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and
|
||||
/// \c TemplateArguments on the other hand do not have storage or unique
|
||||
/// pointers and thus need to be stored by value.
|
||||
typedef llvm::AlignedCharArrayUnion<
|
||||
Decl *, Stmt *, Type *, NestedNameSpecifier *, CXXCtorInitializer *>
|
||||
KindsByPointer;
|
||||
llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
|
||||
NestedNameSpecifierLoc, QualType, TypeLoc>
|
||||
Storage;
|
||||
llvm::AlignedCharArrayUnion<const void *, TemplateArgument,
|
||||
NestedNameSpecifierLoc, QualType,
|
||||
TypeLoc> Storage;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -420,6 +500,10 @@ template <>
|
||||
struct DenseMapInfo<clang::ast_type_traits::ASTNodeKind>
|
||||
: clang::ast_type_traits::ASTNodeKind::DenseMapInfo {};
|
||||
|
||||
template <>
|
||||
struct DenseMapInfo<clang::ast_type_traits::DynTypedNode>
|
||||
: clang::ast_type_traits::DynTypedNode::DenseMapInfo {};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -56,21 +56,21 @@ class Attr {
|
||||
bool IsLateParsed : 1;
|
||||
bool DuplicatesAllowed : 1;
|
||||
|
||||
void* operator new(size_t bytes) throw() {
|
||||
void *operator new(size_t bytes) LLVM_NOEXCEPT {
|
||||
llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
|
||||
}
|
||||
void operator delete(void* data) throw() {
|
||||
void operator delete(void *data) LLVM_NOEXCEPT {
|
||||
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 = 8) throw() {
|
||||
void *operator new(size_t Bytes, ASTContext &C,
|
||||
size_t Alignment = 8) LLVM_NOEXCEPT {
|
||||
return ::operator new(Bytes, C, Alignment);
|
||||
}
|
||||
void operator delete(void *Ptr, ASTContext &C,
|
||||
size_t Alignment) throw() {
|
||||
size_t Alignment) LLVM_NOEXCEPT {
|
||||
return ::operator delete(Ptr, C, Alignment);
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,12 @@ BUILTIN_TYPE(OCLImage1dArray, OCLImage1dArrayTy)
|
||||
BUILTIN_TYPE(OCLImage1dBuffer, OCLImage1dBufferTy)
|
||||
BUILTIN_TYPE(OCLImage2d, OCLImage2dTy)
|
||||
BUILTIN_TYPE(OCLImage2dArray, OCLImage2dArrayTy)
|
||||
BUILTIN_TYPE(OCLImage2dDepth, OCLImage2dDepthTy)
|
||||
BUILTIN_TYPE(OCLImage2dArrayDepth, OCLImage2dArrayDepthTy)
|
||||
BUILTIN_TYPE(OCLImage2dMSAA, OCLImage2dMSAATy)
|
||||
BUILTIN_TYPE(OCLImage2dArrayMSAA, OCLImage2dArrayMSAATy)
|
||||
BUILTIN_TYPE(OCLImage2dMSAADepth, OCLImage2dMSAADepthTy)
|
||||
BUILTIN_TYPE(OCLImage2dArrayMSAADepth, OCLImage2dArrayMSAADepthTy)
|
||||
BUILTIN_TYPE(OCLImage3d, OCLImage3dTy)
|
||||
|
||||
// OpenCL sampler_t.
|
||||
@ -168,6 +174,18 @@ BUILTIN_TYPE(OCLSampler, OCLSamplerTy)
|
||||
// OpenCL event_t.
|
||||
BUILTIN_TYPE(OCLEvent, OCLEventTy)
|
||||
|
||||
// OpenCL clk_event_t.
|
||||
BUILTIN_TYPE(OCLClkEvent, OCLClkEventTy)
|
||||
|
||||
// OpenCL queue_t.
|
||||
BUILTIN_TYPE(OCLQueue, OCLQueueTy)
|
||||
|
||||
// OpenCL ndrange_t.
|
||||
BUILTIN_TYPE(OCLNDRange, OCLNDRangeTy)
|
||||
|
||||
// OpenCL reserve_id_t.
|
||||
BUILTIN_TYPE(OCLReserveID, OCLReserveIDTy)
|
||||
|
||||
// This represents the type of an expression whose type is
|
||||
// totally unknown, e.g. 'T::foo'. It is permitted for this to
|
||||
// appear in situations where the structure of the type is
|
||||
@ -227,8 +245,11 @@ PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
|
||||
// context.
|
||||
PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy)
|
||||
|
||||
// A placeholder type for OpenMP array sections.
|
||||
PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy)
|
||||
|
||||
#ifdef LAST_BUILTIN_TYPE
|
||||
LAST_BUILTIN_TYPE(ARCUnbridgedCast)
|
||||
LAST_BUILTIN_TYPE(OMPArraySection)
|
||||
#undef LAST_BUILTIN_TYPE
|
||||
#endif
|
||||
|
||||
|
@ -155,17 +155,16 @@ class CXXBasePaths {
|
||||
/// \brief Array of the declarations that have been found. This
|
||||
/// array is constructed only if needed, e.g., to iterate over the
|
||||
/// results within LookupResult.
|
||||
NamedDecl **DeclsFound;
|
||||
std::unique_ptr<NamedDecl *[]> DeclsFound;
|
||||
unsigned NumDeclsFound;
|
||||
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
void ComputeDeclsFound();
|
||||
|
||||
bool lookupInBases(ASTContext &Context,
|
||||
const CXXRecordDecl *Record,
|
||||
CXXRecordDecl::BaseMatchesCallback *BaseMatches,
|
||||
void *UserData);
|
||||
bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record,
|
||||
CXXRecordDecl::BaseMatchesCallback BaseMatches);
|
||||
|
||||
public:
|
||||
typedef std::list<CXXBasePath>::iterator paths_iterator;
|
||||
typedef std::list<CXXBasePath>::const_iterator const_paths_iterator;
|
||||
@ -173,15 +172,12 @@ class CXXBasePaths {
|
||||
|
||||
/// BasePaths - Construct a new BasePaths structure to record the
|
||||
/// paths for a derived-to-base search.
|
||||
explicit CXXBasePaths(bool FindAmbiguities = true,
|
||||
bool RecordPaths = true,
|
||||
explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true,
|
||||
bool DetectVirtual = true)
|
||||
: FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
|
||||
DetectVirtual(DetectVirtual), DetectedVirtual(nullptr),
|
||||
DeclsFound(nullptr), NumDeclsFound(0) { }
|
||||
|
||||
~CXXBasePaths() { delete [] DeclsFound; }
|
||||
|
||||
: FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
|
||||
DetectVirtual(DetectVirtual), DetectedVirtual(nullptr),
|
||||
NumDeclsFound(0) {}
|
||||
|
||||
paths_iterator begin() { return Paths.begin(); }
|
||||
paths_iterator end() { return Paths.end(); }
|
||||
const_paths_iterator begin() const { return Paths.begin(); }
|
||||
|
@ -130,6 +130,14 @@ namespace clang {
|
||||
return (Quantity & -Quantity) == Quantity;
|
||||
}
|
||||
|
||||
/// Test whether this is a multiple of the other value.
|
||||
///
|
||||
/// Among other things, this promises that
|
||||
/// self.RoundUpToAlignment(N) will just return self.
|
||||
bool isMultipleOf(CharUnits N) const {
|
||||
return (*this % N) == 0;
|
||||
}
|
||||
|
||||
// Arithmetic operators.
|
||||
CharUnits operator* (QuantityType N) const {
|
||||
return CharUnits(Quantity * N);
|
||||
@ -172,10 +180,20 @@ namespace clang {
|
||||
|
||||
/// Given that this is a non-zero alignment value, what is the
|
||||
/// alignment at the given offset?
|
||||
CharUnits alignmentAtOffset(CharUnits offset) {
|
||||
CharUnits alignmentAtOffset(CharUnits offset) const {
|
||||
assert(Quantity != 0 && "offsetting from unknown alignment?");
|
||||
return CharUnits(llvm::MinAlign(Quantity, offset.Quantity));
|
||||
}
|
||||
|
||||
/// Given that this is the alignment of the first element of an
|
||||
/// array, return the minimum alignment of any element in the array.
|
||||
CharUnits alignmentOfArrayElement(CharUnits elementSize) const {
|
||||
// Since we don't track offsetted alignments, the alignment of
|
||||
// the second element (or any odd element) will be minimally
|
||||
// aligned.
|
||||
return alignmentAtOffset(elementSize);
|
||||
}
|
||||
|
||||
|
||||
}; // class CharUnit
|
||||
} // namespace clang
|
||||
|
@ -79,12 +79,8 @@ class Sema {
|
||||
/// Returns a copy of array, owned by Sema's allocator.
|
||||
template<typename T>
|
||||
ArrayRef<T> copyArray(ArrayRef<T> Source) {
|
||||
size_t Size = Source.size();
|
||||
if (Size != 0) {
|
||||
T *Mem = Allocator.Allocate<T>(Size);
|
||||
std::uninitialized_copy(Source.begin(), Source.end(), Mem);
|
||||
return llvm::makeArrayRef(Mem, Size);
|
||||
}
|
||||
if (!Source.empty())
|
||||
return Source.copy(Allocator);
|
||||
return None;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,11 +21,13 @@
|
||||
#include "clang/AST/Redeclarable.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/Linkage.h"
|
||||
#include "clang/Basic/Module.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
|
||||
namespace clang {
|
||||
struct ASTTemplateArgumentListInfo;
|
||||
@ -37,7 +39,6 @@ class FunctionTemplateDecl;
|
||||
class FunctionTemplateSpecializationInfo;
|
||||
class LabelStmt;
|
||||
class MemberSpecializationInfo;
|
||||
class Module;
|
||||
class NestedNameSpecifier;
|
||||
class ParmVarDecl;
|
||||
class Stmt;
|
||||
@ -318,7 +319,8 @@ class NamedDecl : public Decl {
|
||||
NamedDecl *getUnderlyingDecl() {
|
||||
// Fast-path the common case.
|
||||
if (this->getKind() != UsingShadow &&
|
||||
this->getKind() != ObjCCompatibleAlias)
|
||||
this->getKind() != ObjCCompatibleAlias &&
|
||||
this->getKind() != NamespaceAlias)
|
||||
return this;
|
||||
|
||||
return getUnderlyingDeclImpl();
|
||||
@ -462,25 +464,15 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
||||
}
|
||||
|
||||
/// \brief Get the original (first) namespace declaration.
|
||||
NamespaceDecl *getOriginalNamespace() {
|
||||
if (isFirstDecl())
|
||||
return this;
|
||||
|
||||
return AnonOrFirstNamespaceAndInline.getPointer();
|
||||
}
|
||||
NamespaceDecl *getOriginalNamespace();
|
||||
|
||||
/// \brief Get the original (first) namespace declaration.
|
||||
const NamespaceDecl *getOriginalNamespace() const {
|
||||
if (isFirstDecl())
|
||||
return this;
|
||||
|
||||
return AnonOrFirstNamespaceAndInline.getPointer();
|
||||
}
|
||||
const NamespaceDecl *getOriginalNamespace() const;
|
||||
|
||||
/// \brief Return true if this declaration is an original (first) declaration
|
||||
/// of the namespace. This is false for non-original (subsequent) namespace
|
||||
/// declarations and anonymous namespaces.
|
||||
bool isOriginalNamespace() const { return isFirstDecl(); }
|
||||
bool isOriginalNamespace() const;
|
||||
|
||||
/// \brief Retrieve the anonymous namespace nested inside this namespace,
|
||||
/// if any.
|
||||
@ -572,8 +564,7 @@ struct QualifierInfo {
|
||||
/// setTemplateParameterListsInfo - Sets info about "outer" template
|
||||
/// parameter lists.
|
||||
void setTemplateParameterListsInfo(ASTContext &Context,
|
||||
unsigned NumTPLists,
|
||||
TemplateParameterList **TPLists);
|
||||
ArrayRef<TemplateParameterList *> TPLists);
|
||||
|
||||
private:
|
||||
// Copy constructor and copy assignment are disabled.
|
||||
@ -658,8 +649,8 @@ class DeclaratorDecl : public ValueDecl {
|
||||
assert(index < getNumTemplateParameterLists());
|
||||
return getExtInfo()->TemplParamLists[index];
|
||||
}
|
||||
void setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists,
|
||||
TemplateParameterList **TPLists);
|
||||
void setTemplateParameterListsInfo(ASTContext &Context,
|
||||
ArrayRef<TemplateParameterList *> TPLists);
|
||||
|
||||
SourceLocation getTypeSpecStartLoc() const;
|
||||
|
||||
@ -728,17 +719,14 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
};
|
||||
|
||||
protected:
|
||||
/// \brief Placeholder type used in Init to denote an unparsed C++ default
|
||||
/// argument.
|
||||
struct UnparsedDefaultArgument;
|
||||
|
||||
/// \brief Placeholder type used in Init to denote an uninstantiated C++
|
||||
/// default argument.
|
||||
struct UninstantiatedDefaultArgument;
|
||||
|
||||
typedef llvm::PointerUnion4<Stmt *, EvaluatedStmt *,
|
||||
UnparsedDefaultArgument *,
|
||||
UninstantiatedDefaultArgument *> InitType;
|
||||
// A pointer union of Stmt * and EvaluatedStmt *. When an EvaluatedStmt, we
|
||||
// have allocated the auxilliary struct of information there.
|
||||
//
|
||||
// TODO: It is a bit unfortunate to use a PointerUnion inside the VarDecl for
|
||||
// this as *many* VarDecls are ParmVarDecls that don't have default
|
||||
// arguments. We could save some space by moving this pointer union to be
|
||||
// allocated in trailing space when necessary.
|
||||
typedef llvm::PointerUnion<Stmt *, EvaluatedStmt *> InitType;
|
||||
|
||||
/// \brief The initializer for this variable or, for a ParmVarDecl, the
|
||||
/// C++ default argument.
|
||||
@ -762,6 +750,13 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
protected:
|
||||
enum { NumParameterIndexBits = 8 };
|
||||
|
||||
enum DefaultArgKind {
|
||||
DAK_None,
|
||||
DAK_Unparsed,
|
||||
DAK_Uninstantiated,
|
||||
DAK_Normal
|
||||
};
|
||||
|
||||
class ParmVarDeclBitfields {
|
||||
friend class ParmVarDecl;
|
||||
friend class ASTDeclReader;
|
||||
@ -772,6 +767,12 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// prior declaration.
|
||||
unsigned HasInheritedDefaultArg : 1;
|
||||
|
||||
/// Describes the kind of default argument for this parameter. By default
|
||||
/// this is none. If this is normal, then the default argument is stored in
|
||||
/// the \c VarDecl initalizer expression unless we were unble to parse
|
||||
/// (even an invalid) expression for the default argument.
|
||||
unsigned DefaultArgKind : 2;
|
||||
|
||||
/// Whether this parameter undergoes K&R argument promotion.
|
||||
unsigned IsKNRPromoted : 1;
|
||||
|
||||
@ -815,6 +816,9 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// \brief Whether this variable is (C++0x) constexpr.
|
||||
unsigned IsConstexpr : 1;
|
||||
|
||||
/// \brief Whether this variable is a (C++ Concepts TS) concept.
|
||||
unsigned IsConcept : 1;
|
||||
|
||||
/// \brief Whether this variable is the implicit variable for a lambda
|
||||
/// init-capture.
|
||||
unsigned IsInitCapture : 1;
|
||||
@ -1062,47 +1066,14 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// declaration it is attached to. Also get that declaration.
|
||||
const Expr *getAnyInitializer(const VarDecl *&D) const;
|
||||
|
||||
bool hasInit() const {
|
||||
return !Init.isNull() && (Init.is<Stmt *>() || Init.is<EvaluatedStmt *>());
|
||||
}
|
||||
bool hasInit() const;
|
||||
const Expr *getInit() const {
|
||||
if (Init.isNull())
|
||||
return nullptr;
|
||||
|
||||
const Stmt *S = Init.dyn_cast<Stmt *>();
|
||||
if (!S) {
|
||||
if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
|
||||
S = ES->Value;
|
||||
}
|
||||
return (const Expr*) S;
|
||||
}
|
||||
Expr *getInit() {
|
||||
if (Init.isNull())
|
||||
return nullptr;
|
||||
|
||||
Stmt *S = Init.dyn_cast<Stmt *>();
|
||||
if (!S) {
|
||||
if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
|
||||
S = ES->Value;
|
||||
}
|
||||
|
||||
return (Expr*) S;
|
||||
return const_cast<VarDecl *>(this)->getInit();
|
||||
}
|
||||
Expr *getInit();
|
||||
|
||||
/// \brief Retrieve the address of the initializer expression.
|
||||
Stmt **getInitAddress() {
|
||||
if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>())
|
||||
return &ES->Value;
|
||||
|
||||
// This union hack tip-toes around strict-aliasing rules.
|
||||
union {
|
||||
InitType *InitPtr;
|
||||
Stmt **StmtPtr;
|
||||
};
|
||||
|
||||
InitPtr = &Init;
|
||||
return StmtPtr;
|
||||
}
|
||||
Stmt **getInitAddress();
|
||||
|
||||
void setInit(Expr *I);
|
||||
|
||||
@ -1124,33 +1095,18 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// \brief Return the already-evaluated value of this variable's
|
||||
/// initializer, or NULL if the value is not yet known. Returns pointer
|
||||
/// to untyped APValue if the value could not be evaluated.
|
||||
APValue *getEvaluatedValue() const {
|
||||
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
|
||||
if (Eval->WasEvaluated)
|
||||
return &Eval->Evaluated;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
APValue *getEvaluatedValue() const;
|
||||
|
||||
/// \brief Determines whether it is already known whether the
|
||||
/// initializer is an integral constant expression or not.
|
||||
bool isInitKnownICE() const {
|
||||
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
|
||||
return Eval->CheckedICE;
|
||||
|
||||
return false;
|
||||
}
|
||||
bool isInitKnownICE() const;
|
||||
|
||||
/// \brief Determines whether the initializer is an integral constant
|
||||
/// expression, or in C++11, whether the initializer is a constant
|
||||
/// expression.
|
||||
///
|
||||
/// \pre isInitKnownICE()
|
||||
bool isInitICE() const {
|
||||
assert(isInitKnownICE() &&
|
||||
"Check whether we already know that the initializer is an ICE");
|
||||
return Init.get<EvaluatedStmt *>()->IsICE;
|
||||
}
|
||||
bool isInitICE() const;
|
||||
|
||||
/// \brief Determine whether the value of the initializer attached to this
|
||||
/// declaration is an integral constant expression.
|
||||
@ -1238,6 +1194,15 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
NonParmVarDeclBits.IsConstexpr = IC;
|
||||
}
|
||||
|
||||
/// Whether this variable is (C++ Concepts TS) concept.
|
||||
bool isConcept() const {
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsConcept;
|
||||
}
|
||||
void setConcept(bool IC) {
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.IsConcept = IC;
|
||||
}
|
||||
|
||||
/// Whether this variable is the implicit variable for a lambda init-capture.
|
||||
bool isInitCapture() const {
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsInitCapture;
|
||||
@ -1342,6 +1307,7 @@ class ParmVarDecl : public VarDecl {
|
||||
TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg)
|
||||
: VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) {
|
||||
assert(ParmVarDeclBits.HasInheritedDefaultArg == false);
|
||||
assert(ParmVarDeclBits.DefaultArgKind == DAK_None);
|
||||
assert(ParmVarDeclBits.IsKNRPromoted == false);
|
||||
assert(ParmVarDeclBits.IsObjCMethodParam == false);
|
||||
setDefaultArg(DefArg);
|
||||
@ -1416,29 +1382,20 @@ class ParmVarDecl : public VarDecl {
|
||||
return const_cast<ParmVarDecl *>(this)->getDefaultArg();
|
||||
}
|
||||
|
||||
void setDefaultArg(Expr *defarg) {
|
||||
Init = reinterpret_cast<Stmt *>(defarg);
|
||||
}
|
||||
void setDefaultArg(Expr *defarg);
|
||||
|
||||
/// \brief Retrieve the source range that covers the entire default
|
||||
/// argument.
|
||||
SourceRange getDefaultArgRange() const;
|
||||
void setUninstantiatedDefaultArg(Expr *arg) {
|
||||
Init = reinterpret_cast<UninstantiatedDefaultArgument *>(arg);
|
||||
}
|
||||
Expr *getUninstantiatedDefaultArg() {
|
||||
return (Expr *)Init.get<UninstantiatedDefaultArgument *>();
|
||||
}
|
||||
void setUninstantiatedDefaultArg(Expr *arg);
|
||||
Expr *getUninstantiatedDefaultArg();
|
||||
const Expr *getUninstantiatedDefaultArg() const {
|
||||
return (const Expr *)Init.get<UninstantiatedDefaultArgument *>();
|
||||
return const_cast<ParmVarDecl *>(this)->getUninstantiatedDefaultArg();
|
||||
}
|
||||
|
||||
/// hasDefaultArg - Determines whether this parameter has a default argument,
|
||||
/// either parsed or not.
|
||||
bool hasDefaultArg() const {
|
||||
return getInit() || hasUnparsedDefaultArg() ||
|
||||
hasUninstantiatedDefaultArg();
|
||||
}
|
||||
bool hasDefaultArg() const;
|
||||
|
||||
/// hasUnparsedDefaultArg - Determines whether this parameter has a
|
||||
/// default argument that has not yet been parsed. This will occur
|
||||
@ -1451,11 +1408,11 @@ class ParmVarDecl : public VarDecl {
|
||||
/// }; // x has a regular default argument now
|
||||
/// @endcode
|
||||
bool hasUnparsedDefaultArg() const {
|
||||
return Init.is<UnparsedDefaultArgument*>();
|
||||
return ParmVarDeclBits.DefaultArgKind == DAK_Unparsed;
|
||||
}
|
||||
|
||||
bool hasUninstantiatedDefaultArg() const {
|
||||
return Init.is<UninstantiatedDefaultArgument*>();
|
||||
return ParmVarDeclBits.DefaultArgKind == DAK_Uninstantiated;
|
||||
}
|
||||
|
||||
/// setUnparsedDefaultArg - Specify that this parameter has an
|
||||
@ -1463,7 +1420,9 @@ class ParmVarDecl : public VarDecl {
|
||||
/// real default argument via setDefaultArg when the class
|
||||
/// definition enclosing the function declaration that owns this
|
||||
/// default argument is completed.
|
||||
void setUnparsedDefaultArg() { Init = (UnparsedDefaultArgument *)nullptr; }
|
||||
void setUnparsedDefaultArg() {
|
||||
ParmVarDeclBits.DefaultArgKind = DAK_Unparsed;
|
||||
}
|
||||
|
||||
bool hasInheritedDefaultArg() const {
|
||||
return ParmVarDeclBits.HasInheritedDefaultArg;
|
||||
@ -1546,25 +1505,25 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
|
||||
LazyDeclStmtPtr Body;
|
||||
|
||||
// FIXME: This can be packed into the bitfields in Decl.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
|
||||
// FIXME: This can be packed into the bitfields in DeclContext.
|
||||
// NOTE: VC++ packs bitfields poorly if the types differ.
|
||||
unsigned SClass : 2;
|
||||
bool IsInline : 1;
|
||||
bool IsInlineSpecified : 1;
|
||||
bool IsVirtualAsWritten : 1;
|
||||
bool IsPure : 1;
|
||||
bool HasInheritedPrototype : 1;
|
||||
bool HasWrittenPrototype : 1;
|
||||
bool IsDeleted : 1;
|
||||
bool IsTrivial : 1; // sunk from CXXMethodDecl
|
||||
bool IsDefaulted : 1; // sunk from CXXMethoDecl
|
||||
bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
|
||||
bool HasImplicitReturnZero : 1;
|
||||
bool IsLateTemplateParsed : 1;
|
||||
bool IsConstexpr : 1;
|
||||
unsigned IsInline : 1;
|
||||
unsigned IsInlineSpecified : 1;
|
||||
unsigned IsVirtualAsWritten : 1;
|
||||
unsigned IsPure : 1;
|
||||
unsigned HasInheritedPrototype : 1;
|
||||
unsigned HasWrittenPrototype : 1;
|
||||
unsigned IsDeleted : 1;
|
||||
unsigned IsTrivial : 1; // sunk from CXXMethodDecl
|
||||
unsigned IsDefaulted : 1; // sunk from CXXMethoDecl
|
||||
unsigned IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
|
||||
unsigned HasImplicitReturnZero : 1;
|
||||
unsigned IsLateTemplateParsed : 1;
|
||||
unsigned IsConstexpr : 1;
|
||||
|
||||
/// \brief Indicates if the function uses __try.
|
||||
bool UsesSEHTry : 1;
|
||||
unsigned UsesSEHTry : 1;
|
||||
|
||||
/// \brief Indicates if the function was a definition but its body was
|
||||
/// skipped.
|
||||
@ -1835,7 +1794,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool isConstexpr() const { return IsConstexpr; }
|
||||
void setConstexpr(bool IC) { IsConstexpr = IC; }
|
||||
|
||||
/// Whether this is a (C++11) constexpr function or constexpr constructor.
|
||||
/// \brief Indicates the function uses __try.
|
||||
bool usesSEHTry() const { return UsesSEHTry; }
|
||||
void setUsesSEHTry(bool UST) { UsesSEHTry = UST; }
|
||||
|
||||
@ -2084,9 +2043,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// \brief If this function is an instantiation of a member function of a
|
||||
/// class template specialization, retrieves the member specialization
|
||||
/// information.
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const {
|
||||
return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
|
||||
}
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const;
|
||||
|
||||
/// \brief Specify that this record is an instantiation of the
|
||||
/// member function FD.
|
||||
@ -2107,13 +2064,9 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// FunctionDecl that describes the function template,
|
||||
/// getDescribedFunctionTemplate() retrieves the
|
||||
/// FunctionTemplateDecl from a FunctionDecl.
|
||||
FunctionTemplateDecl *getDescribedFunctionTemplate() const {
|
||||
return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl*>();
|
||||
}
|
||||
FunctionTemplateDecl *getDescribedFunctionTemplate() const;
|
||||
|
||||
void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
|
||||
TemplateOrSpecialization = Template;
|
||||
}
|
||||
void setDescribedFunctionTemplate(FunctionTemplateDecl *Template);
|
||||
|
||||
/// \brief Determine whether this function is a function template
|
||||
/// specialization.
|
||||
@ -2128,10 +2081,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// \brief If this function is actually a function template specialization,
|
||||
/// retrieve information about this function template specialization.
|
||||
/// Otherwise, returns NULL.
|
||||
FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const {
|
||||
return TemplateOrSpecialization.
|
||||
dyn_cast<FunctionTemplateSpecializationInfo*>();
|
||||
}
|
||||
FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const;
|
||||
|
||||
/// \brief Determines whether this function is a function template
|
||||
/// specialization or a member of a class template specialization that can
|
||||
@ -2208,10 +2158,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
const TemplateArgumentListInfo &TemplateArgs);
|
||||
|
||||
DependentFunctionTemplateSpecializationInfo *
|
||||
getDependentSpecializationInfo() const {
|
||||
return TemplateOrSpecialization.
|
||||
dyn_cast<DependentFunctionTemplateSpecializationInfo*>();
|
||||
}
|
||||
getDependentSpecializationInfo() const;
|
||||
|
||||
/// \brief Determine what kind of template instantiation this function
|
||||
/// represents.
|
||||
@ -2487,7 +2434,8 @@ class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> {
|
||||
/// IndirectFieldDecl - An instance of this class is created to represent a
|
||||
/// field injected from an anonymous union/struct into the parent scope.
|
||||
/// IndirectFieldDecl are always implicit.
|
||||
class IndirectFieldDecl : public ValueDecl {
|
||||
class IndirectFieldDecl : public ValueDecl,
|
||||
public Mergeable<IndirectFieldDecl> {
|
||||
void anchor() override;
|
||||
NamedDecl **Chaining;
|
||||
unsigned ChainingSize;
|
||||
@ -2525,6 +2473,9 @@ class IndirectFieldDecl : public ValueDecl {
|
||||
return dyn_cast<VarDecl>(*chain_begin());
|
||||
}
|
||||
|
||||
IndirectFieldDecl *getCanonicalDecl() override { return getFirstDecl(); }
|
||||
const IndirectFieldDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == IndirectField; }
|
||||
@ -2762,12 +2713,12 @@ class TagDecl
|
||||
/// declaration specifier for variables, it points to the first VarDecl (used
|
||||
/// for mangling);
|
||||
/// otherwise, it is a null (TypedefNameDecl) pointer.
|
||||
llvm::PointerUnion<NamedDecl *, ExtInfo *> NamedDeclOrQualifier;
|
||||
llvm::PointerUnion<TypedefNameDecl *, ExtInfo *> TypedefNameDeclOrQualifier;
|
||||
|
||||
bool hasExtInfo() const { return NamedDeclOrQualifier.is<ExtInfo *>(); }
|
||||
ExtInfo *getExtInfo() { return NamedDeclOrQualifier.get<ExtInfo *>(); }
|
||||
bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo *>(); }
|
||||
ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo *>(); }
|
||||
const ExtInfo *getExtInfo() const {
|
||||
return NamedDeclOrQualifier.get<ExtInfo *>();
|
||||
return TypedefNameDeclOrQualifier.get<ExtInfo *>();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -2778,7 +2729,7 @@ class TagDecl
|
||||
TagDeclKind(TK), IsCompleteDefinition(false), IsBeingDefined(false),
|
||||
IsEmbeddedInDeclarator(false), IsFreeStanding(false),
|
||||
IsCompleteDefinitionRequired(false),
|
||||
NamedDeclOrQualifier((NamedDecl *)nullptr) {
|
||||
TypedefNameDeclOrQualifier((TypedefNameDecl *)nullptr) {
|
||||
assert((DK != Enum || TK == TTK_Enum) &&
|
||||
"EnumDecl not matched with TTK_Enum");
|
||||
setPreviousDecl(PrevDecl);
|
||||
@ -2925,22 +2876,11 @@ class TagDecl
|
||||
return (getDeclName() || getTypedefNameForAnonDecl());
|
||||
}
|
||||
|
||||
bool hasDeclaratorForAnonDecl() const {
|
||||
return dyn_cast_or_null<DeclaratorDecl>(
|
||||
NamedDeclOrQualifier.get<NamedDecl *>());
|
||||
}
|
||||
DeclaratorDecl *getDeclaratorForAnonDecl() const {
|
||||
return hasExtInfo() ? nullptr : dyn_cast_or_null<DeclaratorDecl>(
|
||||
NamedDeclOrQualifier.get<NamedDecl *>());
|
||||
}
|
||||
|
||||
TypedefNameDecl *getTypedefNameForAnonDecl() const {
|
||||
return hasExtInfo() ? nullptr : dyn_cast_or_null<TypedefNameDecl>(
|
||||
NamedDeclOrQualifier.get<NamedDecl *>());
|
||||
return hasExtInfo() ? nullptr
|
||||
: TypedefNameDeclOrQualifier.get<TypedefNameDecl *>();
|
||||
}
|
||||
|
||||
void setDeclaratorForAnonDecl(DeclaratorDecl *DD) { NamedDeclOrQualifier = DD; }
|
||||
|
||||
void setTypedefNameForAnonDecl(TypedefNameDecl *TDD);
|
||||
|
||||
/// \brief Retrieve the nested-name-specifier that qualifies the name of this
|
||||
@ -2967,8 +2907,8 @@ class TagDecl
|
||||
assert(i < getNumTemplateParameterLists());
|
||||
return getExtInfo()->TemplParamLists[i];
|
||||
}
|
||||
void setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists,
|
||||
TemplateParameterList **TPLists);
|
||||
void setTemplateParameterListsInfo(ASTContext &Context,
|
||||
ArrayRef<TemplateParameterList *> TPLists);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
@ -3301,7 +3241,14 @@ class RecordDecl : public TagDecl {
|
||||
|
||||
bool hasVolatileMember() const { return HasVolatileMember; }
|
||||
void setHasVolatileMember (bool val) { HasVolatileMember = val; }
|
||||
|
||||
|
||||
bool hasLoadedFieldsFromExternalStorage() const {
|
||||
return LoadedFieldsFromExternalStorage;
|
||||
}
|
||||
void setHasLoadedFieldsFromExternalStorage(bool val) {
|
||||
LoadedFieldsFromExternalStorage = val;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this declaration represents the
|
||||
/// injected class name.
|
||||
///
|
||||
@ -3475,7 +3422,7 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
Stmt *Body;
|
||||
TypeSourceInfo *SignatureAsWritten;
|
||||
|
||||
Capture *Captures;
|
||||
const Capture *Captures;
|
||||
unsigned NumCaptures;
|
||||
|
||||
unsigned ManglingNumber;
|
||||
@ -3581,10 +3528,8 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
|
||||
bool capturesVariable(const VarDecl *var) const;
|
||||
|
||||
void setCaptures(ASTContext &Context,
|
||||
const Capture *begin,
|
||||
const Capture *end,
|
||||
bool capturesCXXThis);
|
||||
void setCaptures(ASTContext &Context, ArrayRef<Capture> Captures,
|
||||
bool CapturesCXXThis);
|
||||
|
||||
unsigned getBlockManglingNumber() const {
|
||||
return ManglingNumber;
|
||||
@ -3613,7 +3558,15 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
|
||||
/// \brief This represents the body of a CapturedStmt, and serves as its
|
||||
/// DeclContext.
|
||||
class CapturedDecl : public Decl, public DeclContext {
|
||||
class CapturedDecl final
|
||||
: public Decl,
|
||||
public DeclContext,
|
||||
private llvm::TrailingObjects<CapturedDecl, ImplicitParamDecl *> {
|
||||
protected:
|
||||
size_t numTrailingObjects(OverloadToken<ImplicitParamDecl>) {
|
||||
return NumParams;
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief The number of parameters to the outlined function.
|
||||
unsigned NumParams;
|
||||
@ -3622,13 +3575,14 @@ class CapturedDecl : public Decl, public DeclContext {
|
||||
/// \brief The body of the outlined function.
|
||||
llvm::PointerIntPair<Stmt *, 1, bool> BodyAndNothrow;
|
||||
|
||||
explicit CapturedDecl(DeclContext *DC, unsigned NumParams)
|
||||
: Decl(Captured, DC, SourceLocation()), DeclContext(Captured),
|
||||
NumParams(NumParams), ContextParam(0), BodyAndNothrow(nullptr, false) { }
|
||||
explicit CapturedDecl(DeclContext *DC, unsigned NumParams);
|
||||
|
||||
ImplicitParamDecl **getParams() const {
|
||||
return reinterpret_cast<ImplicitParamDecl **>(
|
||||
const_cast<CapturedDecl *>(this) + 1);
|
||||
ImplicitParamDecl *const *getParams() const {
|
||||
return getTrailingObjects<ImplicitParamDecl *>();
|
||||
}
|
||||
|
||||
ImplicitParamDecl **getParams() {
|
||||
return getTrailingObjects<ImplicitParamDecl *>();
|
||||
}
|
||||
|
||||
public:
|
||||
@ -3637,11 +3591,11 @@ class CapturedDecl : public Decl, public DeclContext {
|
||||
static CapturedDecl *CreateDeserialized(ASTContext &C, unsigned ID,
|
||||
unsigned NumParams);
|
||||
|
||||
Stmt *getBody() const override { return BodyAndNothrow.getPointer(); }
|
||||
void setBody(Stmt *B) { BodyAndNothrow.setPointer(B); }
|
||||
Stmt *getBody() const override;
|
||||
void setBody(Stmt *B);
|
||||
|
||||
bool isNothrow() const { return BodyAndNothrow.getInt(); }
|
||||
void setNothrow(bool Nothrow = true) { BodyAndNothrow.setInt(Nothrow); }
|
||||
bool isNothrow() const;
|
||||
void setNothrow(bool Nothrow = true);
|
||||
|
||||
unsigned getNumParams() const { return NumParams; }
|
||||
|
||||
@ -3666,7 +3620,7 @@ class CapturedDecl : public Decl, public DeclContext {
|
||||
}
|
||||
unsigned getContextParamPosition() const { return ContextParam; }
|
||||
|
||||
typedef ImplicitParamDecl **param_iterator;
|
||||
typedef ImplicitParamDecl *const *param_iterator;
|
||||
typedef llvm::iterator_range<param_iterator> param_range;
|
||||
|
||||
/// \brief Retrieve an iterator pointing to the first parameter decl.
|
||||
@ -3689,6 +3643,7 @@ class CapturedDecl : public Decl, public DeclContext {
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
/// \brief Describes a module import declaration, which makes the contents
|
||||
@ -3701,7 +3656,8 @@ class CapturedDecl : public Decl, public DeclContext {
|
||||
///
|
||||
/// Import declarations can also be implicitly generated from
|
||||
/// \#include/\#import directives.
|
||||
class ImportDecl : public Decl {
|
||||
class ImportDecl final : public Decl,
|
||||
llvm::TrailingObjects<ImportDecl, SourceLocation> {
|
||||
/// \brief The imported module, along with a bit that indicates whether
|
||||
/// we have source-location information for each identifier in the module
|
||||
/// name.
|
||||
@ -3717,7 +3673,8 @@ class ImportDecl : public Decl {
|
||||
friend class ASTReader;
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTContext;
|
||||
|
||||
friend TrailingObjects;
|
||||
|
||||
ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported,
|
||||
ArrayRef<SourceLocation> IdentifierLocs);
|
||||
|
||||
|
@ -70,8 +70,15 @@ namespace clang {
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
///
|
||||
/// Note: There are objects tacked on before the *beginning* of Decl
|
||||
/// (and its subclasses) in its Decl::operator new(). Proper alignment
|
||||
/// of all subclasses (not requiring more than DeclObjAlignment) is
|
||||
/// asserted in DeclBase.cpp.
|
||||
class Decl {
|
||||
public:
|
||||
/// \brief Alignment guaranteed when allocating Decl and any subtypes.
|
||||
enum { DeclObjAlignment = llvm::AlignOf<uint64_t>::Alignment };
|
||||
|
||||
/// \brief Lists the kind of concrete classes of Decl.
|
||||
enum Kind {
|
||||
#define DECL(DERIVED, BASE) DERIVED,
|
||||
@ -468,8 +475,7 @@ class Decl {
|
||||
|
||||
template <typename T>
|
||||
llvm::iterator_range<specific_attr_iterator<T>> specific_attrs() const {
|
||||
return llvm::iterator_range<specific_attr_iterator<T>>(
|
||||
specific_attr_begin<T>(), specific_attr_end<T>());
|
||||
return llvm::make_range(specific_attr_begin<T>(), specific_attr_end<T>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -721,6 +727,15 @@ class Decl {
|
||||
return getParentFunctionOrMethod() == nullptr;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this declaration lexically is inside a function.
|
||||
/// It recognizes non-defining declarations as well as members of local
|
||||
/// classes:
|
||||
/// \code
|
||||
/// void foo() { void bar(); }
|
||||
/// void foo2() { class ABC { void bar(); }; }
|
||||
/// \endcode
|
||||
bool isLexicallyWithinFunctionOrMethod() const;
|
||||
|
||||
/// \brief If this decl is defined inside a function/method/block it returns
|
||||
/// the corresponding DeclContext, otherwise it returns null.
|
||||
const DeclContext *getParentFunctionOrMethod() const;
|
||||
@ -1126,6 +1141,11 @@ class DeclContext {
|
||||
/// that are missing from the lookup table.
|
||||
mutable bool HasLazyExternalLexicalLookups : 1;
|
||||
|
||||
/// \brief If \c true, lookups should only return identifier from
|
||||
/// DeclContext scope (for example TranslationUnit). Used in
|
||||
/// LookupQualifiedName()
|
||||
mutable bool UseQualifiedLookup : 1;
|
||||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context (or a DependentStoredDeclsMap if this is a
|
||||
/// dependent context). We maintain the invariant that, if the map
|
||||
@ -1160,6 +1180,7 @@ class DeclContext {
|
||||
ExternalVisibleStorage(false),
|
||||
NeedToReconcileExternalVisibleStorage(false),
|
||||
HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false),
|
||||
UseQualifiedLookup(false),
|
||||
LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {}
|
||||
|
||||
public:
|
||||
@ -1740,6 +1761,16 @@ class DeclContext {
|
||||
D == LastDecl);
|
||||
}
|
||||
|
||||
bool setUseQualifiedLookup(bool use = true) {
|
||||
bool old_value = UseQualifiedLookup;
|
||||
UseQualifiedLookup = use;
|
||||
return old_value;
|
||||
}
|
||||
|
||||
bool shouldUseQualifiedLookup() const {
|
||||
return UseQualifiedLookup;
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D);
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
|
||||
|
@ -1344,9 +1344,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \brief If this class is an instantiation of a member class of a
|
||||
/// class template specialization, retrieves the member specialization
|
||||
/// information.
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const {
|
||||
return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
|
||||
}
|
||||
MemberSpecializationInfo *getMemberSpecializationInfo() const;
|
||||
|
||||
/// \brief Specify that this record is an instantiation of the
|
||||
/// member class \p RD.
|
||||
@ -1364,13 +1362,9 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// CXXRecordDecl that from a ClassTemplateDecl, while
|
||||
/// getDescribedClassTemplate() retrieves the ClassTemplateDecl from
|
||||
/// a CXXRecordDecl.
|
||||
ClassTemplateDecl *getDescribedClassTemplate() const {
|
||||
return TemplateOrInstantiation.dyn_cast<ClassTemplateDecl*>();
|
||||
}
|
||||
ClassTemplateDecl *getDescribedClassTemplate() const;
|
||||
|
||||
void setDescribedClassTemplate(ClassTemplateDecl *Template) {
|
||||
TemplateOrInstantiation = Template;
|
||||
}
|
||||
void setDescribedClassTemplate(ClassTemplateDecl *Template);
|
||||
|
||||
/// \brief Determine whether this particular class is a specialization or
|
||||
/// instantiation of a class template or member class of a class template,
|
||||
@ -1468,8 +1462,8 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \param BaseDefinition the definition of the base class
|
||||
///
|
||||
/// \returns true if this base matched the search criteria
|
||||
typedef bool ForallBasesCallback(const CXXRecordDecl *BaseDefinition,
|
||||
void *UserData);
|
||||
typedef llvm::function_ref<bool(const CXXRecordDecl *BaseDefinition)>
|
||||
ForallBasesCallback;
|
||||
|
||||
/// \brief Determines if the given callback holds for all the direct
|
||||
/// or indirect base classes of this type.
|
||||
@ -1481,13 +1475,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// class of this type, or if \p AllowShortCircuit is true then until a call
|
||||
/// returns false.
|
||||
///
|
||||
/// \param UserData Passed as the second argument of every call to
|
||||
/// \p BaseMatches.
|
||||
///
|
||||
/// \param AllowShortCircuit if false, forces the callback to be called
|
||||
/// for every base class, even if a dependent or non-matching base was
|
||||
/// found.
|
||||
bool forallBases(ForallBasesCallback *BaseMatches, void *UserData,
|
||||
bool forallBases(ForallBasesCallback BaseMatches,
|
||||
bool AllowShortCircuit = true) const;
|
||||
|
||||
/// \brief Function type used by lookupInBases() to determine whether a
|
||||
@ -1499,13 +1490,9 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \param Path the current path, from the most-derived class down to the
|
||||
/// base named by the \p Specifier.
|
||||
///
|
||||
/// \param UserData a single pointer to user-specified data, provided to
|
||||
/// lookupInBases().
|
||||
///
|
||||
/// \returns true if this base matched the search criteria, false otherwise.
|
||||
typedef bool BaseMatchesCallback(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path,
|
||||
void *UserData);
|
||||
typedef llvm::function_ref<bool(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path)> BaseMatchesCallback;
|
||||
|
||||
/// \brief Look for entities within the base classes of this C++ class,
|
||||
/// transitively searching all base class subobjects.
|
||||
@ -1520,14 +1507,12 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \param BaseMatches callback function used to determine whether a given
|
||||
/// base matches the user-defined search criteria.
|
||||
///
|
||||
/// \param UserData user data pointer that will be provided to \p BaseMatches.
|
||||
///
|
||||
/// \param Paths used to record the paths from this class to its base class
|
||||
/// subobjects that match the search criteria.
|
||||
///
|
||||
/// \returns true if there exists any path from this class to a base class
|
||||
/// subobject that matches the search criteria.
|
||||
bool lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData,
|
||||
bool lookupInBases(BaseMatchesCallback BaseMatches,
|
||||
CXXBasePaths &Paths) const;
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether the given
|
||||
@ -1535,10 +1520,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
///
|
||||
/// This callback can be used with \c lookupInBases() to determine whether
|
||||
/// a given derived class has is a base class subobject of a particular type.
|
||||
/// The user data pointer should refer to the canonical CXXRecordDecl of the
|
||||
/// The base record pointer should refer to the canonical CXXRecordDecl of the
|
||||
/// base class that we are searching for.
|
||||
static bool FindBaseClass(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path, void *BaseRecord);
|
||||
CXXBasePath &Path, const CXXRecordDecl *BaseRecord);
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether the
|
||||
/// given base class specifier refers to a specific class
|
||||
@ -1546,39 +1531,38 @@ class CXXRecordDecl : public RecordDecl {
|
||||
///
|
||||
/// This callback can be used with \c lookupInBases() to determine
|
||||
/// whether a given derived class has is a virtual base class
|
||||
/// subobject of a particular type. The user data pointer should
|
||||
/// subobject of a particular type. The base record pointer should
|
||||
/// refer to the canonical CXXRecordDecl of the base class that we
|
||||
/// are searching for.
|
||||
static bool FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path, void *BaseRecord);
|
||||
CXXBasePath &Path,
|
||||
const CXXRecordDecl *BaseRecord);
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether there exists
|
||||
/// a tag with the given name.
|
||||
///
|
||||
/// This callback can be used with \c lookupInBases() to find tag members
|
||||
/// of the given name within a C++ class hierarchy. The user data pointer
|
||||
/// is an opaque \c DeclarationName pointer.
|
||||
/// of the given name within a C++ class hierarchy.
|
||||
static bool FindTagMember(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path, void *Name);
|
||||
CXXBasePath &Path, DeclarationName Name);
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether there exists
|
||||
/// a member with the given name.
|
||||
///
|
||||
/// This callback can be used with \c lookupInBases() to find members
|
||||
/// of the given name within a C++ class hierarchy. The user data pointer
|
||||
/// is an opaque \c DeclarationName pointer.
|
||||
/// of the given name within a C++ class hierarchy.
|
||||
static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path, void *Name);
|
||||
CXXBasePath &Path, DeclarationName Name);
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether there exists
|
||||
/// a member with the given name that can be used in a nested-name-specifier.
|
||||
///
|
||||
/// This callback can be used with \c lookupInBases() to find membes of
|
||||
/// This callback can be used with \c lookupInBases() to find members of
|
||||
/// the given name within a C++ class hierarchy that can occur within
|
||||
/// nested-name-specifiers.
|
||||
static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path,
|
||||
void *UserData);
|
||||
DeclarationName Name);
|
||||
|
||||
/// \brief Retrieve the final overriders for each virtual member
|
||||
/// function in the class hierarchy where this class is the
|
||||
@ -1898,7 +1882,8 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
/// B(A& a) : A(a), f(3.14159) { }
|
||||
/// };
|
||||
/// \endcode
|
||||
class CXXCtorInitializer {
|
||||
class CXXCtorInitializer final
|
||||
: private llvm::TrailingObjects<CXXCtorInitializer, VarDecl *> {
|
||||
/// \brief Either the base class name/delegating constructor type (stored as
|
||||
/// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field
|
||||
/// (IndirectFieldDecl*) being initialized.
|
||||
@ -2114,24 +2099,26 @@ class CXXCtorInitializer {
|
||||
/// describe an array member initialization.
|
||||
VarDecl *getArrayIndex(unsigned I) {
|
||||
assert(I < getNumArrayIndices() && "Out of bounds member array index");
|
||||
return reinterpret_cast<VarDecl **>(this + 1)[I];
|
||||
return getTrailingObjects<VarDecl *>()[I];
|
||||
}
|
||||
const VarDecl *getArrayIndex(unsigned I) const {
|
||||
assert(I < getNumArrayIndices() && "Out of bounds member array index");
|
||||
return reinterpret_cast<const VarDecl * const *>(this + 1)[I];
|
||||
return getTrailingObjects<VarDecl *>()[I];
|
||||
}
|
||||
void setArrayIndex(unsigned I, VarDecl *Index) {
|
||||
assert(I < getNumArrayIndices() && "Out of bounds member array index");
|
||||
reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
|
||||
getTrailingObjects<VarDecl *>()[I] = Index;
|
||||
}
|
||||
ArrayRef<VarDecl *> getArrayIndexes() {
|
||||
assert(getNumArrayIndices() != 0 && "Getting indexes for non-array init");
|
||||
return llvm::makeArrayRef(reinterpret_cast<VarDecl **>(this + 1),
|
||||
return llvm::makeArrayRef(getTrailingObjects<VarDecl *>(),
|
||||
getNumArrayIndices());
|
||||
}
|
||||
|
||||
/// \brief Get the initializer.
|
||||
Expr *getInit() const { return static_cast<Expr*>(Init); }
|
||||
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
/// \brief Represents a C++ constructor within a class.
|
||||
@ -2289,14 +2276,14 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
}
|
||||
|
||||
/// \brief Determine whether this constructor is a move constructor
|
||||
/// (C++0x [class.copy]p3), which can be used to move values of the class.
|
||||
/// (C++11 [class.copy]p3), which can be used to move values of the class.
|
||||
///
|
||||
/// \param TypeQuals If this constructor is a move constructor, will be set
|
||||
/// to the type qualifiers on the referent of the first parameter's type.
|
||||
bool isMoveConstructor(unsigned &TypeQuals) const;
|
||||
|
||||
/// \brief Determine whether this constructor is a move constructor
|
||||
/// (C++0x [class.copy]p3), which can be used to move values of the class.
|
||||
/// (C++11 [class.copy]p3), which can be used to move values of the class.
|
||||
bool isMoveConstructor() const {
|
||||
unsigned TypeQuals = 0;
|
||||
return isMoveConstructor(TypeQuals);
|
||||
@ -2406,7 +2393,7 @@ class CXXConversionDecl : public CXXMethodDecl {
|
||||
void anchor() override;
|
||||
/// Whether this conversion function declaration is marked
|
||||
/// "explicit", meaning that it can only be applied when the user
|
||||
/// explicitly wrote a cast. This is a C++0x feature.
|
||||
/// explicitly wrote a cast. This is a C++11 feature.
|
||||
bool IsExplicitSpecified : 1;
|
||||
|
||||
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
|
@ -37,7 +37,9 @@ namespace clang {
|
||||
/// @endcode
|
||||
///
|
||||
/// The semantic context of a friend decl is its declaring class.
|
||||
class FriendDecl : public Decl {
|
||||
class FriendDecl final
|
||||
: public Decl,
|
||||
private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> {
|
||||
virtual void anchor();
|
||||
public:
|
||||
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
|
||||
@ -62,14 +64,6 @@ class FriendDecl : public Decl {
|
||||
// template <class T> friend class A<T>::B;
|
||||
unsigned NumTPLists : 31;
|
||||
|
||||
// The tail-allocated friend type template parameter lists (if any).
|
||||
TemplateParameterList* const *getTPLists() const {
|
||||
return reinterpret_cast<TemplateParameterList* const *>(this + 1);
|
||||
}
|
||||
TemplateParameterList **getTPLists() {
|
||||
return reinterpret_cast<TemplateParameterList**>(this + 1);
|
||||
}
|
||||
|
||||
friend class CXXRecordDecl::friend_iterator;
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
@ -83,7 +77,7 @@ class FriendDecl : public Decl {
|
||||
UnsupportedFriend(false),
|
||||
NumTPLists(FriendTypeTPLists.size()) {
|
||||
for (unsigned i = 0; i < NumTPLists; ++i)
|
||||
getTPLists()[i] = FriendTypeTPLists[i];
|
||||
getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i];
|
||||
}
|
||||
|
||||
FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
|
||||
@ -118,7 +112,7 @@ class FriendDecl : public Decl {
|
||||
}
|
||||
TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
|
||||
assert(N < NumTPLists);
|
||||
return getTPLists()[N];
|
||||
return getTrailingObjects<TemplateParameterList *>()[N];
|
||||
}
|
||||
|
||||
/// If this friend declaration doesn't name a type, return the inner
|
||||
@ -148,9 +142,10 @@ class FriendDecl : public Decl {
|
||||
return SourceRange(getFriendLoc(), ND->getLocEnd());
|
||||
}
|
||||
else if (TypeSourceInfo *TInfo = getFriendType()) {
|
||||
SourceLocation StartL = (NumTPLists == 0)
|
||||
? getFriendLoc()
|
||||
: getTPLists()[0]->getTemplateLoc();
|
||||
SourceLocation StartL =
|
||||
(NumTPLists == 0) ? getFriendLoc()
|
||||
: getTrailingObjects<TemplateParameterList *>()[0]
|
||||
->getTemplateLoc();
|
||||
return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc());
|
||||
}
|
||||
else
|
||||
@ -171,6 +166,7 @@ class FriendDecl : public Decl {
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
/// An iterator over the friend declarations of a class.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_CLANG_AST_DECLGROUP_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
@ -24,13 +25,9 @@ class Decl;
|
||||
class DeclGroup;
|
||||
class DeclGroupIterator;
|
||||
|
||||
class DeclGroup {
|
||||
class DeclGroup final : private llvm::TrailingObjects<DeclGroup, Decl *> {
|
||||
// FIXME: Include a TypeSpecifier object.
|
||||
union {
|
||||
unsigned NumDecls;
|
||||
|
||||
Decl *Aligner;
|
||||
};
|
||||
unsigned NumDecls;
|
||||
|
||||
private:
|
||||
DeclGroup() : NumDecls(0) {}
|
||||
@ -43,13 +40,15 @@ class DeclGroup {
|
||||
|
||||
Decl*& operator[](unsigned i) {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return ((Decl**) (this+1))[i];
|
||||
return getTrailingObjects<Decl *>()[i];
|
||||
}
|
||||
|
||||
Decl* const& operator[](unsigned i) const {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return ((Decl* const*) (this+1))[i];
|
||||
return getTrailingObjects<Decl *>()[i];
|
||||
}
|
||||
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
class DeclGroupRef {
|
||||
|
@ -612,7 +612,8 @@ class ObjCTypeParamDecl : public TypedefNameDecl {
|
||||
/// @interface NSArray<T> // stores the <T>
|
||||
/// @end
|
||||
/// \endcode
|
||||
class ObjCTypeParamList {
|
||||
class ObjCTypeParamList final
|
||||
: private llvm::TrailingObjects<ObjCTypeParamList, ObjCTypeParamDecl *> {
|
||||
/// Stores the components of a SourceRange as a POD.
|
||||
struct PODSourceRange {
|
||||
unsigned Begin;
|
||||
@ -644,7 +645,7 @@ class ObjCTypeParamList {
|
||||
/// Iterate through the type parameters in the list.
|
||||
typedef ObjCTypeParamDecl **iterator;
|
||||
|
||||
iterator begin() { return reinterpret_cast<ObjCTypeParamDecl **>(this + 1); }
|
||||
iterator begin() { return getTrailingObjects<ObjCTypeParamDecl *>(); }
|
||||
|
||||
iterator end() { return begin() + size(); }
|
||||
|
||||
@ -655,7 +656,7 @@ class ObjCTypeParamList {
|
||||
typedef ObjCTypeParamDecl * const *const_iterator;
|
||||
|
||||
const_iterator begin() const {
|
||||
return reinterpret_cast<ObjCTypeParamDecl * const *>(this + 1);
|
||||
return getTrailingObjects<ObjCTypeParamDecl *>();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
@ -685,6 +686,7 @@ class ObjCTypeParamList {
|
||||
/// Gather the default set of type arguments to be substituted for
|
||||
/// these type parameters when dealing with an unspecialized type.
|
||||
void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const;
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
/// ObjCContainerDecl - Represents a container for method declarations.
|
||||
@ -1202,13 +1204,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
// might bring in a definition.
|
||||
// Note: a null value indicates that we don't have a definition and that
|
||||
// modules are enabled.
|
||||
if (!Data.getOpaqueValue()) {
|
||||
if (IdentifierInfo *II = getIdentifier()) {
|
||||
if (II->isOutOfDate()) {
|
||||
updateOutOfDate(*II);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Data.getOpaqueValue())
|
||||
getMostRecentDecl();
|
||||
|
||||
return Data.getPointer();
|
||||
}
|
||||
@ -1851,13 +1848,8 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
|
||||
// might bring in a definition.
|
||||
// Note: a null value indicates that we don't have a definition and that
|
||||
// modules are enabled.
|
||||
if (!Data.getOpaqueValue()) {
|
||||
if (IdentifierInfo *II = getIdentifier()) {
|
||||
if (II->isOutOfDate()) {
|
||||
updateOutOfDate(*II);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Data.getOpaqueValue())
|
||||
getMostRecentDecl();
|
||||
|
||||
return Data.getPointer();
|
||||
}
|
||||
@ -2519,26 +2511,18 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
void setPropertyAttributes(PropertyAttributeKind PRVal) {
|
||||
PropertyAttributes |= PRVal;
|
||||
}
|
||||
void overwritePropertyAttributes(unsigned PRVal) {
|
||||
PropertyAttributes = PRVal;
|
||||
}
|
||||
|
||||
PropertyAttributeKind getPropertyAttributesAsWritten() const {
|
||||
return PropertyAttributeKind(PropertyAttributesAsWritten);
|
||||
}
|
||||
|
||||
bool hasWrittenStorageAttribute() const {
|
||||
return PropertyAttributesAsWritten & (OBJC_PR_assign | OBJC_PR_copy |
|
||||
OBJC_PR_unsafe_unretained | OBJC_PR_retain | OBJC_PR_strong |
|
||||
OBJC_PR_weak);
|
||||
}
|
||||
|
||||
void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) {
|
||||
PropertyAttributesAsWritten = PRVal;
|
||||
}
|
||||
|
||||
void makeitReadWriteAttribute() {
|
||||
PropertyAttributes &= ~OBJC_PR_readonly;
|
||||
PropertyAttributes |= OBJC_PR_readwrite;
|
||||
}
|
||||
|
||||
// Helper methods for accessing attributes.
|
||||
|
||||
/// isReadOnly - Return true iff the property has a setter.
|
||||
|
@ -33,8 +33,12 @@ class Expr;
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
class OMPThreadPrivateDecl : public Decl {
|
||||
class OMPThreadPrivateDecl final
|
||||
: public Decl,
|
||||
private llvm::TrailingObjects<OMPThreadPrivateDecl, Expr *> {
|
||||
friend class ASTDeclReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
unsigned NumVars;
|
||||
|
||||
virtual void anchor();
|
||||
@ -43,14 +47,11 @@ class OMPThreadPrivateDecl : public Decl {
|
||||
Decl(DK, DC, L), NumVars(0) { }
|
||||
|
||||
ArrayRef<const Expr *> getVars() const {
|
||||
return llvm::makeArrayRef(reinterpret_cast<const Expr * const *>(this + 1),
|
||||
NumVars);
|
||||
return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumVars);
|
||||
}
|
||||
|
||||
MutableArrayRef<Expr *> getVars() {
|
||||
return MutableArrayRef<Expr *>(
|
||||
reinterpret_cast<Expr **>(this + 1),
|
||||
NumVars);
|
||||
return MutableArrayRef<Expr *>(getTrailingObjects<Expr *>(), NumVars);
|
||||
}
|
||||
|
||||
void setVars(ArrayRef<Expr *> VL);
|
||||
|
@ -20,10 +20,12 @@
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include <limits>
|
||||
|
||||
namespace clang {
|
||||
|
||||
enum BuiltinTemplateKind : int;
|
||||
class TemplateParameterList;
|
||||
class TemplateDecl;
|
||||
class RedeclarableTemplateDecl;
|
||||
@ -43,7 +45,9 @@ typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
|
||||
|
||||
/// \brief Stores a list of template parameters for a TemplateDecl and its
|
||||
/// derived classes.
|
||||
class TemplateParameterList {
|
||||
class TemplateParameterList final
|
||||
: private llvm::TrailingObjects<TemplateParameterList, NamedDecl *> {
|
||||
|
||||
/// The location of the 'template' keyword.
|
||||
SourceLocation TemplateLoc;
|
||||
|
||||
@ -59,16 +63,18 @@ class TemplateParameterList {
|
||||
unsigned ContainsUnexpandedParameterPack : 1;
|
||||
|
||||
protected:
|
||||
size_t numTrailingObjects(OverloadToken<NamedDecl *>) const {
|
||||
return NumParams;
|
||||
}
|
||||
|
||||
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
|
||||
NamedDecl **Params, unsigned NumParams,
|
||||
SourceLocation RAngleLoc);
|
||||
ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc);
|
||||
|
||||
public:
|
||||
static TemplateParameterList *Create(const ASTContext &C,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
NamedDecl **Params,
|
||||
unsigned NumParams,
|
||||
ArrayRef<NamedDecl *> Params,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
/// \brief Iterates through the template parameters in this list.
|
||||
@ -77,10 +83,8 @@ class TemplateParameterList {
|
||||
/// \brief Iterates through the template parameters in this list.
|
||||
typedef NamedDecl* const* const_iterator;
|
||||
|
||||
iterator begin() { return reinterpret_cast<NamedDecl **>(this + 1); }
|
||||
const_iterator begin() const {
|
||||
return reinterpret_cast<NamedDecl * const *>(this + 1);
|
||||
}
|
||||
iterator begin() { return getTrailingObjects<NamedDecl *>(); }
|
||||
const_iterator begin() const { return getTrailingObjects<NamedDecl *>(); }
|
||||
iterator end() { return begin() + NumParams; }
|
||||
const_iterator end() const { return begin() + NumParams; }
|
||||
|
||||
@ -130,29 +134,45 @@ class TemplateParameterList {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(TemplateLoc, RAngleLoc);
|
||||
}
|
||||
|
||||
friend TrailingObjects;
|
||||
template <size_t N> friend class FixedSizeTemplateParameterListStorage;
|
||||
};
|
||||
|
||||
/// \brief Stores a list of template parameters for a TemplateDecl and its
|
||||
/// derived classes. Suitable for creating on the stack.
|
||||
template<size_t N>
|
||||
class FixedSizeTemplateParameterList : public TemplateParameterList {
|
||||
template <size_t N> class FixedSizeTemplateParameterListStorage {
|
||||
// This is kinda ugly: TemplateParameterList usually gets allocated
|
||||
// in a block of memory with NamedDecls appended to it. Here, to get
|
||||
// it stack allocated, we include the params as a separate
|
||||
// variable. After allocation, the TemplateParameterList object
|
||||
// treats them as part of itself.
|
||||
TemplateParameterList List;
|
||||
NamedDecl *Params[N];
|
||||
|
||||
public:
|
||||
FixedSizeTemplateParameterList(SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
NamedDecl **Params, SourceLocation RAngleLoc) :
|
||||
TemplateParameterList(TemplateLoc, LAngleLoc, Params, N, RAngleLoc) {
|
||||
FixedSizeTemplateParameterListStorage(SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ArrayRef<NamedDecl *> Params,
|
||||
SourceLocation RAngleLoc)
|
||||
: List(TemplateLoc, LAngleLoc, Params, RAngleLoc) {
|
||||
// Because we're doing an evil layout hack above, have some
|
||||
// asserts, just to double-check everything is laid out like
|
||||
// expected.
|
||||
assert(sizeof(*this) ==
|
||||
TemplateParameterList::totalSizeToAlloc<NamedDecl *>(N) &&
|
||||
"Object layout not as expected");
|
||||
assert(this->Params == List.getTrailingObjects<NamedDecl *>() &&
|
||||
"Object layout not as expected");
|
||||
}
|
||||
TemplateParameterList *get() { return &List; }
|
||||
};
|
||||
|
||||
/// \brief A template argument list.
|
||||
class TemplateArgumentList {
|
||||
class TemplateArgumentList final
|
||||
: private llvm::TrailingObjects<TemplateArgumentList, TemplateArgument> {
|
||||
/// \brief The template argument list.
|
||||
///
|
||||
/// The integer value will be non-zero to indicate that this
|
||||
/// template argument list does own the pointer.
|
||||
llvm::PointerIntPair<const TemplateArgument *, 1> Arguments;
|
||||
const TemplateArgument *Arguments;
|
||||
|
||||
/// \brief The number of template arguments in this template
|
||||
/// argument list.
|
||||
@ -161,9 +181,9 @@ class TemplateArgumentList {
|
||||
TemplateArgumentList(const TemplateArgumentList &Other) = delete;
|
||||
void operator=(const TemplateArgumentList &Other) = delete;
|
||||
|
||||
TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs,
|
||||
bool Owned)
|
||||
: Arguments(Args, Owned), NumArguments(NumArgs) { }
|
||||
// Constructs an instance with an internal Argument list, containing
|
||||
// a copy of the Args array. (Called by CreateCopy)
|
||||
TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs);
|
||||
|
||||
public:
|
||||
/// \brief Type used to indicate that the template argument list itself is a
|
||||
@ -180,9 +200,9 @@ class TemplateArgumentList {
|
||||
///
|
||||
/// The template argument list does not own the template arguments
|
||||
/// provided.
|
||||
explicit TemplateArgumentList(OnStackType,
|
||||
const TemplateArgument *Args, unsigned NumArgs)
|
||||
: Arguments(Args, false), NumArguments(NumArgs) { }
|
||||
explicit TemplateArgumentList(OnStackType, const TemplateArgument *Args,
|
||||
unsigned NumArgs)
|
||||
: Arguments(Args), NumArguments(NumArgs) {}
|
||||
|
||||
/// \brief Produces a shallow copy of the given template argument list.
|
||||
///
|
||||
@ -191,7 +211,7 @@ class TemplateArgumentList {
|
||||
/// constructor, since this really really isn't safe to use that
|
||||
/// way.
|
||||
explicit TemplateArgumentList(const TemplateArgumentList *Other)
|
||||
: Arguments(Other->data(), false), NumArguments(Other->size()) { }
|
||||
: Arguments(Other->data()), NumArguments(Other->size()) {}
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
const TemplateArgument &get(unsigned Idx) const {
|
||||
@ -212,9 +232,9 @@ class TemplateArgumentList {
|
||||
unsigned size() const { return NumArguments; }
|
||||
|
||||
/// \brief Retrieve a pointer to the template argument list.
|
||||
const TemplateArgument *data() const {
|
||||
return Arguments.getPointer();
|
||||
}
|
||||
const TemplateArgument *data() const { return Arguments; }
|
||||
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
void *allocateDefaultArgStorageChain(const ASTContext &C);
|
||||
@ -426,17 +446,8 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
/// explicit instantiation declaration, or explicit instantiation
|
||||
/// definition.
|
||||
bool isExplicitInstantiationOrSpecialization() const {
|
||||
switch (getTemplateSpecializationKind()) {
|
||||
case TSK_ExplicitSpecialization:
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
return true;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("bad template specialization kind");
|
||||
return isTemplateExplicitInstantiationOrSpecialization(
|
||||
getTemplateSpecializationKind());
|
||||
}
|
||||
|
||||
/// \brief Set the template specialization kind.
|
||||
@ -542,56 +553,52 @@ class MemberSpecializationInfo {
|
||||
/// friend void foo<>(T);
|
||||
/// };
|
||||
/// \endcode
|
||||
class DependentFunctionTemplateSpecializationInfo {
|
||||
struct CA {
|
||||
/// The number of potential template candidates.
|
||||
unsigned NumTemplates;
|
||||
class DependentFunctionTemplateSpecializationInfo final
|
||||
: private llvm::TrailingObjects<DependentFunctionTemplateSpecializationInfo,
|
||||
TemplateArgumentLoc,
|
||||
FunctionTemplateDecl *> {
|
||||
/// The number of potential template candidates.
|
||||
unsigned NumTemplates;
|
||||
|
||||
/// The number of template arguments.
|
||||
unsigned NumArgs;
|
||||
};
|
||||
|
||||
union {
|
||||
// Force sizeof to be a multiple of sizeof(void*) so that the
|
||||
// trailing data is aligned.
|
||||
void *Aligner;
|
||||
struct CA d;
|
||||
};
|
||||
/// The number of template arguments.
|
||||
unsigned NumArgs;
|
||||
|
||||
/// The locations of the left and right angle brackets.
|
||||
SourceRange AngleLocs;
|
||||
|
||||
FunctionTemplateDecl * const *getTemplates() const {
|
||||
return reinterpret_cast<FunctionTemplateDecl*const*>(this+1);
|
||||
size_t numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const {
|
||||
return NumArgs;
|
||||
}
|
||||
size_t numTrailingObjects(OverloadToken<FunctionTemplateDecl *>) const {
|
||||
return NumTemplates;
|
||||
}
|
||||
|
||||
public:
|
||||
DependentFunctionTemplateSpecializationInfo(
|
||||
const UnresolvedSetImpl &Templates,
|
||||
const TemplateArgumentListInfo &TemplateArgs);
|
||||
|
||||
public:
|
||||
static DependentFunctionTemplateSpecializationInfo *
|
||||
Create(ASTContext &Context, const UnresolvedSetImpl &Templates,
|
||||
const TemplateArgumentListInfo &TemplateArgs);
|
||||
|
||||
/// \brief Returns the number of function templates that this might
|
||||
/// be a specialization of.
|
||||
unsigned getNumTemplates() const {
|
||||
return d.NumTemplates;
|
||||
}
|
||||
unsigned getNumTemplates() const { return NumTemplates; }
|
||||
|
||||
/// \brief Returns the i'th template candidate.
|
||||
FunctionTemplateDecl *getTemplate(unsigned I) const {
|
||||
assert(I < getNumTemplates() && "template index out of range");
|
||||
return getTemplates()[I];
|
||||
return getTrailingObjects<FunctionTemplateDecl *>()[I];
|
||||
}
|
||||
|
||||
/// \brief Returns the explicit template arguments that were given.
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
return reinterpret_cast<const TemplateArgumentLoc*>(
|
||||
&getTemplates()[getNumTemplates()]);
|
||||
return getTrailingObjects<TemplateArgumentLoc>();
|
||||
}
|
||||
|
||||
/// \brief Returns the number of explicit template arguments that were given.
|
||||
unsigned getNumTemplateArgs() const {
|
||||
return d.NumArgs;
|
||||
}
|
||||
unsigned getNumTemplateArgs() const { return NumArgs; }
|
||||
|
||||
/// \brief Returns the nth template argument.
|
||||
const TemplateArgumentLoc &getTemplateArg(unsigned I) const {
|
||||
@ -606,6 +613,8 @@ class DependentFunctionTemplateSpecializationInfo {
|
||||
SourceLocation getRAngleLoc() const {
|
||||
return AngleLocs.getEnd();
|
||||
}
|
||||
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
/// Declaration of a redeclarable template.
|
||||
@ -926,7 +935,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
return const_cast<FunctionTemplateDecl*>(this)->getMostRecentDecl();
|
||||
}
|
||||
|
||||
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() const {
|
||||
return cast_or_null<FunctionTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
|
||||
}
|
||||
@ -1120,8 +1129,11 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// @code
|
||||
/// template<int Size> class array { };
|
||||
/// @endcode
|
||||
class NonTypeTemplateParmDecl
|
||||
: public DeclaratorDecl, protected TemplateParmPosition {
|
||||
class NonTypeTemplateParmDecl final
|
||||
: public DeclaratorDecl,
|
||||
protected TemplateParmPosition,
|
||||
private llvm::TrailingObjects<NonTypeTemplateParmDecl,
|
||||
std::pair<QualType, TypeSourceInfo *>> {
|
||||
/// \brief The default template argument, if any, and whether or not
|
||||
/// it was inherited.
|
||||
typedef DefaultArgStorage<NonTypeTemplateParmDecl, Expr*> DefArgStorage;
|
||||
@ -1141,6 +1153,11 @@ class NonTypeTemplateParmDecl
|
||||
/// \brief The number of types in an expanded parameter pack.
|
||||
unsigned NumExpandedTypes;
|
||||
|
||||
size_t numTrailingObjects(
|
||||
OverloadToken<std::pair<QualType, TypeSourceInfo *>>) const {
|
||||
return NumExpandedTypes;
|
||||
}
|
||||
|
||||
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, unsigned D, unsigned P,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
@ -1159,6 +1176,7 @@ class NonTypeTemplateParmDecl
|
||||
TypeSourceInfo **ExpandedTInfos);
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
public:
|
||||
static NonTypeTemplateParmDecl *
|
||||
@ -1274,16 +1292,18 @@ class NonTypeTemplateParmDecl
|
||||
/// pack.
|
||||
QualType getExpansionType(unsigned I) const {
|
||||
assert(I < NumExpandedTypes && "Out-of-range expansion type index");
|
||||
void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1);
|
||||
return QualType::getFromOpaquePtr(TypesAndInfos[2*I]);
|
||||
auto TypesAndInfos =
|
||||
getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
|
||||
return TypesAndInfos[I].first;
|
||||
}
|
||||
|
||||
/// \brief Retrieve a particular expansion type source info within an
|
||||
/// expanded parameter pack.
|
||||
TypeSourceInfo *getExpansionTypeSourceInfo(unsigned I) const {
|
||||
assert(I < NumExpandedTypes && "Out-of-range expansion type index");
|
||||
void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1);
|
||||
return static_cast<TypeSourceInfo *>(TypesAndInfos[2*I+1]);
|
||||
auto TypesAndInfos =
|
||||
getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
|
||||
return TypesAndInfos[I].second;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
@ -1298,9 +1318,11 @@ class NonTypeTemplateParmDecl
|
||||
/// @endcode
|
||||
/// A template template parameter is a TemplateDecl because it defines the
|
||||
/// name of a template and the template parameters allowable for substitution.
|
||||
class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
protected TemplateParmPosition
|
||||
{
|
||||
class TemplateTemplateParmDecl final
|
||||
: public TemplateDecl,
|
||||
protected TemplateParmPosition,
|
||||
private llvm::TrailingObjects<TemplateTemplateParmDecl,
|
||||
TemplateParameterList *> {
|
||||
void anchor() override;
|
||||
|
||||
/// \brief The default template argument, if any.
|
||||
@ -1404,7 +1426,7 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
/// pack.
|
||||
TemplateParameterList *getExpansionTemplateParameters(unsigned I) const {
|
||||
assert(I < NumExpandedParams && "Out-of-range expansion type index");
|
||||
return reinterpret_cast<TemplateParameterList *const *>(this + 1)[I];
|
||||
return getTrailingObjects<TemplateParameterList *>()[I];
|
||||
}
|
||||
|
||||
const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; }
|
||||
@ -1454,6 +1476,36 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
/// \brief Represents the builtin template declaration which is used to
|
||||
/// implement __make_integer_seq. It serves no real purpose beyond existing as
|
||||
/// a place to hold template parameters.
|
||||
class BuiltinTemplateDecl : public TemplateDecl {
|
||||
void anchor() override;
|
||||
|
||||
BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
|
||||
DeclarationName Name, BuiltinTemplateKind BTK);
|
||||
|
||||
BuiltinTemplateKind BTK;
|
||||
|
||||
public:
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == BuiltinTemplate; }
|
||||
|
||||
static BuiltinTemplateDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
DeclarationName Name,
|
||||
BuiltinTemplateKind BTK) {
|
||||
return new (C, DC) BuiltinTemplateDecl(C, DC, Name, BTK);
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange();
|
||||
}
|
||||
|
||||
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
|
||||
};
|
||||
|
||||
/// \brief Represents a class template specialization, which refers to
|
||||
@ -1580,17 +1632,8 @@ class ClassTemplateSpecializationDecl
|
||||
/// explicit instantiation declaration, or explicit instantiation
|
||||
/// definition.
|
||||
bool isExplicitInstantiationOrSpecialization() const {
|
||||
switch (getTemplateSpecializationKind()) {
|
||||
case TSK_ExplicitSpecialization:
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
return true;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("bad template specialization kind");
|
||||
return isTemplateExplicitInstantiationOrSpecialization(
|
||||
getTemplateSpecializationKind());
|
||||
}
|
||||
|
||||
void setSpecializationKind(TemplateSpecializationKind TSK) {
|
||||
@ -1819,8 +1862,8 @@ class ClassTemplatePartialSpecializationDecl
|
||||
/// template partial specialization \c Outer<T>::Inner<U*>. Given
|
||||
/// \c Outer<float>::Inner<U*>, this function would return
|
||||
/// \c Outer<T>::Inner<U*>.
|
||||
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
|
||||
ClassTemplatePartialSpecializationDecl *First =
|
||||
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() const {
|
||||
const ClassTemplatePartialSpecializationDecl *First =
|
||||
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
return First->InstantiatedFromMember.getPointer();
|
||||
}
|
||||
@ -2000,7 +2043,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
return const_cast<ClassTemplateDecl*>(this)->getMostRecentDecl();
|
||||
}
|
||||
|
||||
ClassTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
ClassTemplateDecl *getInstantiatedFromMemberTemplate() const {
|
||||
return cast_or_null<ClassTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
|
||||
}
|
||||
@ -2230,7 +2273,7 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() const {
|
||||
return cast_or_null<TypeAliasTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
|
||||
}
|
||||
@ -2435,17 +2478,8 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||
/// explicit instantiation declaration, or explicit instantiation
|
||||
/// definition.
|
||||
bool isExplicitInstantiationOrSpecialization() const {
|
||||
switch (getTemplateSpecializationKind()) {
|
||||
case TSK_ExplicitSpecialization:
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
return true;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("bad template specialization kind");
|
||||
return isTemplateExplicitInstantiationOrSpecialization(
|
||||
getTemplateSpecializationKind());
|
||||
}
|
||||
|
||||
void setSpecializationKind(TemplateSpecializationKind TSK) {
|
||||
@ -2668,8 +2702,8 @@ class VarTemplatePartialSpecializationDecl
|
||||
/// variable template partial specialization \c Outer<T>::Inner<U*>. Given
|
||||
/// \c Outer<float>::Inner<U*>, this function would return
|
||||
/// \c Outer<T>::Inner<U*>.
|
||||
VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
|
||||
VarTemplatePartialSpecializationDecl *First =
|
||||
VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() const {
|
||||
const VarTemplatePartialSpecializationDecl *First =
|
||||
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
return First->InstantiatedFromMember.getPointer();
|
||||
}
|
||||
@ -2833,7 +2867,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
return const_cast<VarTemplateDecl *>(this)->getMostRecentDecl();
|
||||
}
|
||||
|
||||
VarTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
VarTemplateDecl *getInstantiatedFromMemberTemplate() const {
|
||||
return cast_or_null<VarTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
|
||||
}
|
||||
|
@ -88,8 +88,8 @@ class EvaluatedExprVisitorBase : public StmtVisitorBase<Ptr, ImplClass, void> {
|
||||
|
||||
void VisitLambdaExpr(PTR(LambdaExpr) LE) {
|
||||
// Only visit the capture initializers, and not the body.
|
||||
for (LambdaExpr::capture_init_iterator I = LE->capture_init_begin(),
|
||||
E = LE->capture_init_end();
|
||||
for (LambdaExpr::const_capture_init_iterator I = LE->capture_init_begin(),
|
||||
E = LE->capture_init_end();
|
||||
I != E; ++I)
|
||||
if (*I)
|
||||
this->Visit(*I);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -82,7 +82,9 @@ class ObjCBoolLiteralExpr : public Expr {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCBoxedExpr - used for generalized expression boxing.
|
||||
@ -341,6 +343,8 @@ class ObjCDictionaryLiteral : public Expr {
|
||||
child_range children() {
|
||||
// Note: we're taking advantage of the layout of the KeyValuePair struct
|
||||
// here. If that struct changes, this code will need to change as well.
|
||||
static_assert(sizeof(KeyValuePair) == sizeof(Stmt *) * 2,
|
||||
"KeyValuePair is expected size");
|
||||
return child_range(reinterpret_cast<Stmt **>(this + 1),
|
||||
reinterpret_cast<Stmt **>(this + 1) + NumElements * 2);
|
||||
}
|
||||
@ -389,7 +393,9 @@ class ObjCEncodeExpr : public Expr {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCSelectorExpr used for \@selector in Objective-C.
|
||||
@ -424,7 +430,9 @@ class ObjCSelectorExpr : public Expr {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCProtocolExpr used for protocol expression in Objective-C.
|
||||
@ -464,7 +472,9 @@ class ObjCProtocolExpr : public Expr {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
@ -713,7 +723,7 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
Stmt **begin = reinterpret_cast<Stmt**>(&Receiver); // hack!
|
||||
return child_range(begin, begin+1);
|
||||
}
|
||||
return child_range();
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1350,6 +1360,14 @@ class ObjCMessageExpr : public Expr {
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
llvm::iterator_range<arg_iterator> arguments() {
|
||||
return llvm::make_range(arg_begin(), arg_end());
|
||||
}
|
||||
|
||||
llvm::iterator_range<const_arg_iterator> arguments() const {
|
||||
return llvm::make_range(arg_begin(), arg_end());
|
||||
}
|
||||
|
||||
arg_iterator arg_begin() { return reinterpret_cast<Stmt **>(getArgs()); }
|
||||
arg_iterator arg_end() {
|
||||
return reinterpret_cast<Stmt **>(getArgs() + NumArgs);
|
||||
@ -1503,11 +1521,15 @@ class ObjCIndirectCopyRestoreExpr : public Expr {
|
||||
/// \code
|
||||
/// NSString *str = (__bridge_transfer NSString *)CFCreateString();
|
||||
/// \endcode
|
||||
class ObjCBridgedCastExpr : public ExplicitCastExpr {
|
||||
class ObjCBridgedCastExpr final
|
||||
: public ExplicitCastExpr,
|
||||
private llvm::TrailingObjects<ObjCBridgedCastExpr, CXXBaseSpecifier *> {
|
||||
SourceLocation LParenLoc;
|
||||
SourceLocation BridgeKeywordLoc;
|
||||
unsigned Kind : 2;
|
||||
|
||||
|
||||
friend TrailingObjects;
|
||||
friend class CastExpr;
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
|
||||
|
129
include/clang/AST/ExprOpenMP.h
Normal file
129
include/clang/AST/ExprOpenMP.h
Normal file
@ -0,0 +1,129 @@
|
||||
//===--- ExprOpenMP.h - Classes for representing expressions ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the Expr interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_EXPROPENMP_H
|
||||
#define LLVM_CLANG_AST_EXPROPENMP_H
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
|
||||
namespace clang {
|
||||
/// \brief OpenMP 4.0 [2.4, Array Sections].
|
||||
/// To specify an array section in an OpenMP construct, array subscript
|
||||
/// expressions are extended with the following syntax:
|
||||
/// \code
|
||||
/// [ lower-bound : length ]
|
||||
/// [ lower-bound : ]
|
||||
/// [ : length ]
|
||||
/// [ : ]
|
||||
/// \endcode
|
||||
/// The array section must be a subset of the original array.
|
||||
/// Array sections are allowed on multidimensional arrays. Base language array
|
||||
/// subscript expressions can be used to specify length-one dimensions of
|
||||
/// multidimensional array sections.
|
||||
/// The lower-bound and length are integral type expressions. When evaluated
|
||||
/// they represent a set of integer values as follows:
|
||||
/// \code
|
||||
/// { lower-bound, lower-bound + 1, lower-bound + 2,... , lower-bound + length -
|
||||
/// 1 }
|
||||
/// \endcode
|
||||
/// The lower-bound and length must evaluate to non-negative integers.
|
||||
/// When the size of the array dimension is not known, the length must be
|
||||
/// specified explicitly.
|
||||
/// When the length is absent, it defaults to the size of the array dimension
|
||||
/// minus the lower-bound.
|
||||
/// When the lower-bound is absent it defaults to 0.
|
||||
class OMPArraySectionExpr : public Expr {
|
||||
enum { BASE, LOWER_BOUND, LENGTH, END_EXPR };
|
||||
Stmt *SubExprs[END_EXPR];
|
||||
SourceLocation ColonLoc;
|
||||
SourceLocation RBracketLoc;
|
||||
|
||||
public:
|
||||
OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, QualType Type,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation ColonLoc, SourceLocation RBracketLoc)
|
||||
: Expr(
|
||||
OMPArraySectionExprClass, Type, VK, OK,
|
||||
Base->isTypeDependent() ||
|
||||
(LowerBound && LowerBound->isTypeDependent()) ||
|
||||
(Length && Length->isTypeDependent()),
|
||||
Base->isValueDependent() ||
|
||||
(LowerBound && LowerBound->isValueDependent()) ||
|
||||
(Length && Length->isValueDependent()),
|
||||
Base->isInstantiationDependent() ||
|
||||
(LowerBound && LowerBound->isInstantiationDependent()) ||
|
||||
(Length && Length->isInstantiationDependent()),
|
||||
Base->containsUnexpandedParameterPack() ||
|
||||
(LowerBound && LowerBound->containsUnexpandedParameterPack()) ||
|
||||
(Length && Length->containsUnexpandedParameterPack())),
|
||||
ColonLoc(ColonLoc), RBracketLoc(RBracketLoc) {
|
||||
SubExprs[BASE] = Base;
|
||||
SubExprs[LOWER_BOUND] = LowerBound;
|
||||
SubExprs[LENGTH] = Length;
|
||||
}
|
||||
|
||||
/// \brief Create an empty array section expression.
|
||||
explicit OMPArraySectionExpr(EmptyShell Shell)
|
||||
: Expr(OMPArraySectionExprClass, Shell) {}
|
||||
|
||||
/// An array section can be written only as Base[LowerBound:Length].
|
||||
|
||||
/// \brief Get base of the array section.
|
||||
Expr *getBase() { return cast<Expr>(SubExprs[BASE]); }
|
||||
const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); }
|
||||
/// \brief Set base of the array section.
|
||||
void setBase(Expr *E) { SubExprs[BASE] = E; }
|
||||
|
||||
/// \brief Return original type of the base expression for array section.
|
||||
static QualType getBaseOriginalType(Expr *Base);
|
||||
|
||||
/// \brief Get lower bound of array section.
|
||||
Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); }
|
||||
const Expr *getLowerBound() const {
|
||||
return cast_or_null<Expr>(SubExprs[LOWER_BOUND]);
|
||||
}
|
||||
/// \brief Set lower bound of the array section.
|
||||
void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; }
|
||||
|
||||
/// \brief Get length of array section.
|
||||
Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); }
|
||||
const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); }
|
||||
/// \brief Set length of the array section.
|
||||
void setLength(Expr *E) { SubExprs[LENGTH] = E; }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return getBase()->getLocStart();
|
||||
}
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; }
|
||||
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
void setColonLoc(SourceLocation L) { ColonLoc = L; }
|
||||
|
||||
SourceLocation getRBracketLoc() const { return RBracketLoc; }
|
||||
void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
|
||||
|
||||
SourceLocation getExprLoc() const LLVM_READONLY {
|
||||
return getBase()->getExprLoc();
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == OMPArraySectionExprClass;
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]);
|
||||
}
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -33,20 +33,6 @@ 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 Abstract interface for external sources of AST nodes.
|
||||
///
|
||||
/// External AST sources provide AST nodes constructed from some
|
||||
@ -156,47 +142,50 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
|
||||
/// \brief Retrieve the module that corresponds to the given module ID.
|
||||
virtual Module *getModule(unsigned ID) { return nullptr; }
|
||||
|
||||
/// \brief Holds everything needed to generate debug info for an
|
||||
/// imported module or precompiled header file.
|
||||
struct ASTSourceDescriptor {
|
||||
std::string ModuleName;
|
||||
std::string Path;
|
||||
std::string ASTFile;
|
||||
uint64_t Signature;
|
||||
/// Abstracts clang modules and precompiled header files and holds
|
||||
/// everything needed to generate debug info for an imported module
|
||||
/// or PCH.
|
||||
class ASTSourceDescriptor {
|
||||
StringRef PCHModuleName;
|
||||
StringRef Path;
|
||||
StringRef ASTFile;
|
||||
uint64_t Signature = 0;
|
||||
const Module *ClangModule = nullptr;
|
||||
|
||||
public:
|
||||
ASTSourceDescriptor(){};
|
||||
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
|
||||
uint64_t Signature)
|
||||
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
|
||||
ASTFile(std::move(ASTFile)), Signature(Signature){};
|
||||
ASTSourceDescriptor(const Module &M);
|
||||
std::string getModuleName() const;
|
||||
StringRef getPath() const { return Path; }
|
||||
StringRef getASTFile() const { return ASTFile; }
|
||||
uint64_t getSignature() const { return Signature; }
|
||||
const Module *getModuleOrNull() const { return ClangModule; }
|
||||
};
|
||||
|
||||
/// \brief Return a descriptor for the corresponding module, if one exists.
|
||||
/// Return a descriptor for the corresponding module, if one exists.
|
||||
virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
|
||||
/// \brief Return a descriptor for the module.
|
||||
virtual ASTSourceDescriptor getSourceDescriptor(const Module &M);
|
||||
|
||||
/// \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.
|
||||
/// \param IsKindWeWant a predicate function that returns true if the passed
|
||||
/// declaration kind is one we are looking for.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
|
||||
bool (*isKindWeWant)(Decl::Kind),
|
||||
SmallVectorImpl<Decl*> &Result);
|
||||
virtual void
|
||||
FindExternalLexicalDecls(const DeclContext *DC,
|
||||
llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
|
||||
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, nullptr, Result);
|
||||
}
|
||||
|
||||
template <typename DeclTy>
|
||||
ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC,
|
||||
SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
|
||||
void FindExternalLexicalDecls(const DeclContext *DC,
|
||||
SmallVectorImpl<Decl *> &Result) {
|
||||
FindExternalLexicalDecls(DC, [](Decl::Kind) { return true; }, Result);
|
||||
}
|
||||
|
||||
/// \brief Get the decls that are contained in a file in the Offset/Length
|
||||
|
@ -144,9 +144,6 @@ class MangleContext {
|
||||
/// across translation units so it can be used with LTO.
|
||||
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
|
||||
|
||||
virtual void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
|
||||
raw_ostream &) = 0;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
|
@ -217,7 +217,8 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
|
||||
/// \brief Dump the nested name specifier to standard output to aid
|
||||
/// in debugging.
|
||||
void dump(const LangOptions &LO);
|
||||
void dump(const LangOptions &LO) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
/// \brief A C++ nested-name-specifier augmented with source location
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -334,7 +334,8 @@ enum UnaryOperatorKind {
|
||||
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.
|
||||
UO_Extension, // __extension__ marker.
|
||||
UO_Coawait // [C++ Coroutines] co_await operator
|
||||
};
|
||||
|
||||
/// \brief The kind of bridging performed by the Objective-C bridge cast.
|
||||
|
@ -42,7 +42,7 @@ struct PrintingPolicy {
|
||||
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
|
||||
Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false),
|
||||
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
|
||||
IncludeNewlines(true) { }
|
||||
IncludeNewlines(true), MSVCFormatting(false) { }
|
||||
|
||||
/// \brief What language we're printing.
|
||||
LangOptions LangOpts;
|
||||
@ -109,7 +109,7 @@ struct PrintingPolicy {
|
||||
/// \brief Whether we should print the sizes of constant array expressions
|
||||
/// as written in the sources.
|
||||
///
|
||||
/// This flag is determines whether arrays types declared as
|
||||
/// This flag determines whether array types declared as
|
||||
///
|
||||
/// \code
|
||||
/// int a[4+10*10];
|
||||
@ -163,6 +163,11 @@ struct PrintingPolicy {
|
||||
|
||||
/// \brief When true, include newlines after statements like "break", etc.
|
||||
unsigned IncludeNewlines : 1;
|
||||
|
||||
/// \brief Use whitespace and punctuation like MSVC does. In particular, this
|
||||
/// prints anonymous namespaces as `anonymous namespace' and does not insert
|
||||
/// spaces after template arguments.
|
||||
bool MSVCFormatting : 1;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
|
||||
#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
@ -24,6 +26,7 @@
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/ExprOpenMP.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
@ -42,7 +45,7 @@
|
||||
OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec) \
|
||||
OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus) \
|
||||
OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag) \
|
||||
OPERATOR(Extension)
|
||||
OPERATOR(Extension) OPERATOR(Coawait)
|
||||
|
||||
// All binary operators (excluding compound assign operators).
|
||||
#define BINOP_LIST() \
|
||||
@ -132,6 +135,12 @@ namespace clang {
|
||||
/// from which they were produced.
|
||||
template <typename Derived> class RecursiveASTVisitor {
|
||||
public:
|
||||
/// A queue used for performing data recursion over statements.
|
||||
/// Parameters involving this type are used to implement data
|
||||
/// recursion over Stmts and Exprs within this class, and should
|
||||
/// typically not be explicitly specified by derived classes.
|
||||
typedef SmallVectorImpl<Stmt *> DataRecursionQueue;
|
||||
|
||||
/// \brief Return a reference to the derived class.
|
||||
Derived &getDerived() { return *static_cast<Derived *>(this); }
|
||||
|
||||
@ -147,19 +156,12 @@ template <typename Derived> class RecursiveASTVisitor {
|
||||
/// code, e.g., implicit constructors and destructors.
|
||||
bool shouldVisitImplicitCode() const { return false; }
|
||||
|
||||
/// \brief Return whether \param S should be traversed using data recursion
|
||||
/// to avoid a stack overflow with extreme cases.
|
||||
bool shouldUseDataRecursionFor(Stmt *S) const {
|
||||
return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) ||
|
||||
isa<CaseStmt>(S) || isa<CXXOperatorCallExpr>(S);
|
||||
}
|
||||
|
||||
/// \brief Recursively visit a statement or expression, by
|
||||
/// dispatching to Traverse*() based on the argument's dynamic type.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true
|
||||
/// otherwise (including when the argument is NULL).
|
||||
bool TraverseStmt(Stmt *S);
|
||||
/// otherwise (including when the argument is nullptr).
|
||||
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr);
|
||||
|
||||
/// \brief Recursively visit a type, by dispatching to
|
||||
/// Traverse*Type() based on the argument's getTypeClass() property.
|
||||
@ -252,7 +254,14 @@ template <typename Derived> class RecursiveASTVisitor {
|
||||
/// \c LE->getBody().
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseLambdaBody(LambdaExpr *LE);
|
||||
bool TraverseLambdaBody(LambdaExpr *LE, DataRecursionQueue *Queue = nullptr);
|
||||
|
||||
/// \brief Recursively visit the syntactic or semantic form of an
|
||||
/// initialization list.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseSynOrSemInitListExpr(InitListExpr *S,
|
||||
DataRecursionQueue *Queue = nullptr);
|
||||
|
||||
// ---- Methods on Attrs ----
|
||||
|
||||
@ -266,9 +275,44 @@ template <typename Derived> class RecursiveASTVisitor {
|
||||
|
||||
// ---- Methods on Stmts ----
|
||||
|
||||
private:
|
||||
template<typename T, typename U>
|
||||
struct has_same_member_pointer_type : std::false_type {};
|
||||
template<typename T, typename U, typename R, typename... P>
|
||||
struct has_same_member_pointer_type<R (T::*)(P...), R (U::*)(P...)>
|
||||
: std::true_type {};
|
||||
|
||||
// Traverse the given statement. If the most-derived traverse function takes a
|
||||
// data recursion queue, pass it on; otherwise, discard it. Note that the
|
||||
// first branch of this conditional must compile whether or not the derived
|
||||
// class can take a queue, so if we're taking the second arm, make the first
|
||||
// arm call our function rather than the derived class version.
|
||||
#define TRAVERSE_STMT_BASE(NAME, CLASS, VAR, QUEUE) \
|
||||
(has_same_member_pointer_type<decltype( \
|
||||
&RecursiveASTVisitor::Traverse##NAME), \
|
||||
decltype(&Derived::Traverse##NAME)>::value \
|
||||
? static_cast<typename std::conditional< \
|
||||
has_same_member_pointer_type< \
|
||||
decltype(&RecursiveASTVisitor::Traverse##NAME), \
|
||||
decltype(&Derived::Traverse##NAME)>::value, \
|
||||
Derived &, RecursiveASTVisitor &>::type>(*this) \
|
||||
.Traverse##NAME(static_cast<CLASS *>(VAR), QUEUE) \
|
||||
: getDerived().Traverse##NAME(static_cast<CLASS *>(VAR)))
|
||||
|
||||
// Try to traverse the given statement, or enqueue it if we're performing data
|
||||
// recursion in the middle of traversing another statement. Can only be called
|
||||
// from within a DEF_TRAVERSE_STMT body or similar context.
|
||||
#define TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S) \
|
||||
do { \
|
||||
if (!TRAVERSE_STMT_BASE(Stmt, Stmt, S, Queue)) \
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
public:
|
||||
// Declare Traverse*() for all concrete Stmt classes.
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#define STMT(CLASS, PARENT) bool Traverse##CLASS(CLASS *S);
|
||||
#define STMT(CLASS, PARENT) \
|
||||
bool Traverse##CLASS(CLASS *S, DataRecursionQueue *Queue = nullptr);
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
// The above header #undefs ABSTRACT_STMT and STMT upon exit.
|
||||
|
||||
@ -288,9 +332,10 @@ template <typename Derived> class RecursiveASTVisitor {
|
||||
// operator methods. Unary operators are not classes in themselves
|
||||
// (they're all opcodes in UnaryOperator) but do have visitors.
|
||||
#define OPERATOR(NAME) \
|
||||
bool TraverseUnary##NAME(UnaryOperator *S) { \
|
||||
bool TraverseUnary##NAME(UnaryOperator *S, \
|
||||
DataRecursionQueue *Queue = nullptr) { \
|
||||
TRY_TO(WalkUpFromUnary##NAME(S)); \
|
||||
TRY_TO(TraverseStmt(S->getSubExpr())); \
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSubExpr()); \
|
||||
return true; \
|
||||
} \
|
||||
bool WalkUpFromUnary##NAME(UnaryOperator *S) { \
|
||||
@ -307,10 +352,10 @@ template <typename Derived> class RecursiveASTVisitor {
|
||||
// operator methods. Binary operators are not classes in themselves
|
||||
// (they're all opcodes in BinaryOperator) but do have visitors.
|
||||
#define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \
|
||||
bool TraverseBin##NAME(BINOP_TYPE *S) { \
|
||||
bool TraverseBin##NAME(BINOP_TYPE *S, DataRecursionQueue *Queue = nullptr) { \
|
||||
TRY_TO(WalkUpFromBin##NAME(S)); \
|
||||
TRY_TO(TraverseStmt(S->getLHS())); \
|
||||
TRY_TO(TraverseStmt(S->getRHS())); \
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLHS()); \
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRHS()); \
|
||||
return true; \
|
||||
} \
|
||||
bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \
|
||||
@ -436,129 +481,14 @@ template <typename Derived> class RecursiveASTVisitor {
|
||||
/// \brief Process clauses with list of variables.
|
||||
template <typename T> bool VisitOMPClauseList(T *Node);
|
||||
|
||||
struct EnqueueJob {
|
||||
Stmt *S;
|
||||
Stmt::child_iterator StmtIt;
|
||||
|
||||
EnqueueJob(Stmt *S) : S(S), StmtIt() {}
|
||||
};
|
||||
bool dataTraverse(Stmt *S);
|
||||
bool dataTraverseNode(Stmt *S, bool &EnqueueChildren);
|
||||
bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue);
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
|
||||
|
||||
SmallVector<EnqueueJob, 16> Queue;
|
||||
Queue.push_back(S);
|
||||
|
||||
while (!Queue.empty()) {
|
||||
EnqueueJob &job = Queue.back();
|
||||
Stmt *CurrS = job.S;
|
||||
if (!CurrS) {
|
||||
Queue.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getDerived().shouldUseDataRecursionFor(CurrS)) {
|
||||
if (job.StmtIt == Stmt::child_iterator()) {
|
||||
bool EnqueueChildren = true;
|
||||
if (!dataTraverseNode(CurrS, EnqueueChildren))
|
||||
return false;
|
||||
if (!EnqueueChildren) {
|
||||
Queue.pop_back();
|
||||
continue;
|
||||
}
|
||||
job.StmtIt = CurrS->child_begin();
|
||||
} else {
|
||||
++job.StmtIt;
|
||||
}
|
||||
|
||||
if (job.StmtIt != CurrS->child_end())
|
||||
Queue.push_back(*job.StmtIt);
|
||||
else
|
||||
Queue.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
Queue.pop_back();
|
||||
TRY_TO(TraverseStmt(CurrS));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
|
||||
bool &EnqueueChildren) {
|
||||
|
||||
// Dispatch to the corresponding WalkUpFrom* function only if the derived
|
||||
// class didn't override Traverse* (and thus the traversal is trivial).
|
||||
#define DISPATCH_WALK(NAME, CLASS, VAR) \
|
||||
{ \
|
||||
bool (Derived::*DerivedFn)(CLASS *) = &Derived::Traverse##NAME; \
|
||||
bool (Derived::*BaseFn)(CLASS *) = &RecursiveASTVisitor::Traverse##NAME; \
|
||||
if (DerivedFn == BaseFn) \
|
||||
return getDerived().WalkUpFrom##NAME(static_cast<CLASS *>(VAR)); \
|
||||
} \
|
||||
EnqueueChildren = false; \
|
||||
return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR));
|
||||
|
||||
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
#define OPERATOR(NAME) \
|
||||
case BO_##NAME: \
|
||||
DISPATCH_WALK(Bin##NAME, BinaryOperator, S);
|
||||
|
||||
BINOP_LIST()
|
||||
#undef OPERATOR
|
||||
|
||||
#define OPERATOR(NAME) \
|
||||
case BO_##NAME##Assign: \
|
||||
DISPATCH_WALK(Bin##NAME##Assign, CompoundAssignOperator, S);
|
||||
|
||||
CAO_LIST()
|
||||
#undef OPERATOR
|
||||
}
|
||||
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
|
||||
switch (UnOp->getOpcode()) {
|
||||
#define OPERATOR(NAME) \
|
||||
case UO_##NAME: \
|
||||
DISPATCH_WALK(Unary##NAME, UnaryOperator, S);
|
||||
|
||||
UNARYOP_LIST()
|
||||
#undef OPERATOR
|
||||
}
|
||||
}
|
||||
|
||||
// Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
|
||||
switch (S->getStmtClass()) {
|
||||
case Stmt::NoStmtClass:
|
||||
break;
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#define STMT(CLASS, PARENT) \
|
||||
case Stmt::CLASS##Class: \
|
||||
DISPATCH_WALK(CLASS, CLASS, S);
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
}
|
||||
|
||||
#undef DISPATCH_WALK
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DISPATCH(NAME, CLASS, VAR) \
|
||||
return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR))
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
|
||||
if (!S)
|
||||
return true;
|
||||
|
||||
#define DISPATCH_STMT(NAME, CLASS, VAR) DISPATCH(NAME, CLASS, VAR)
|
||||
|
||||
if (getDerived().shouldUseDataRecursionFor(S))
|
||||
return dataTraverse(S);
|
||||
DataRecursionQueue *Queue) {
|
||||
#define DISPATCH_STMT(NAME, CLASS, VAR) \
|
||||
return TRAVERSE_STMT_BASE(NAME, CLASS, VAR, Queue);
|
||||
|
||||
// If we have a binary expr, dispatch to the subcode of the binop. A smart
|
||||
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
|
||||
@ -609,6 +539,35 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
|
||||
|
||||
#undef DISPATCH_STMT
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S,
|
||||
DataRecursionQueue *Queue) {
|
||||
if (!S)
|
||||
return true;
|
||||
|
||||
if (Queue) {
|
||||
Queue->push_back(S);
|
||||
return true;
|
||||
}
|
||||
|
||||
SmallVector<Stmt *, 8> LocalQueue;
|
||||
LocalQueue.push_back(S);
|
||||
|
||||
while (!LocalQueue.empty()) {
|
||||
Stmt *CurrS = LocalQueue.pop_back_val();
|
||||
|
||||
size_t N = LocalQueue.size();
|
||||
TRY_TO(dataTraverseNode(CurrS, &LocalQueue));
|
||||
// Process new children in the order they were added.
|
||||
std::reverse(LocalQueue.begin() + N, LocalQueue.end());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DISPATCH(NAME, CLASS, VAR) \
|
||||
return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR))
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
|
||||
if (T.isNull())
|
||||
@ -863,8 +822,9 @@ RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE,
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
|
||||
TRY_TO(TraverseStmt(LE->getBody()));
|
||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(
|
||||
LambdaExpr *LE, DataRecursionQueue *Queue) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(LE->getBody());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1364,6 +1324,8 @@ DEF_TRAVERSE_DECL(
|
||||
DEF_TRAVERSE_DECL(ExternCContextDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
|
||||
|
||||
// We shouldn't traverse an aliased namespace, since it will be
|
||||
// defined (and, therefore, traversed) somewhere else.
|
||||
//
|
||||
@ -1596,6 +1558,10 @@ DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
|
||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(BuiltinTemplateDecl, {
|
||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
|
||||
// D is the "T" in something like "template<typename T> class vector;"
|
||||
if (D->getTypeForDecl())
|
||||
@ -1906,25 +1872,26 @@ DEF_TRAVERSE_DECL(ParmVarDecl, {
|
||||
// This macro makes available a variable S, the passed-in stmt.
|
||||
#define DEF_TRAVERSE_STMT(STMT, CODE) \
|
||||
template <typename Derived> \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##STMT(STMT *S) { \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##STMT( \
|
||||
STMT *S, DataRecursionQueue *Queue) { \
|
||||
TRY_TO(WalkUpFrom##STMT(S)); \
|
||||
{ CODE; } \
|
||||
for (Stmt *SubStmt : S->children()) { \
|
||||
TRY_TO(TraverseStmt(SubStmt)); \
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_STMT(GCCAsmStmt, {
|
||||
TRY_TO(TraverseStmt(S->getAsmString()));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAsmString());
|
||||
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
|
||||
TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I)));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInputConstraintLiteral(I));
|
||||
}
|
||||
for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) {
|
||||
TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I)));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOutputConstraintLiteral(I));
|
||||
}
|
||||
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
|
||||
TRY_TO(TraverseStmt(S->getClobberStringLiteral(I)));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getClobberStringLiteral(I));
|
||||
}
|
||||
// children() iterates over inputExpr and outputExpr.
|
||||
})
|
||||
@ -1977,9 +1944,9 @@ DEF_TRAVERSE_STMT(ObjCForCollectionStmt, {})
|
||||
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {})
|
||||
DEF_TRAVERSE_STMT(CXXForRangeStmt, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO(TraverseStmt(S->getLoopVarStmt()));
|
||||
TRY_TO(TraverseStmt(S->getRangeInit()));
|
||||
TRY_TO(TraverseStmt(S->getBody()));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLoopVarStmt());
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRangeInit());
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());
|
||||
// Visit everything else only if shouldVisitImplicitCode().
|
||||
return true;
|
||||
}
|
||||
@ -2012,9 +1979,8 @@ DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
S->getExplicitTemplateArgs().getTemplateArgs(),
|
||||
S->getNumTemplateArgs()));
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
|
||||
S->getNumTemplateArgs()));
|
||||
}
|
||||
})
|
||||
|
||||
@ -2055,64 +2021,60 @@ DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
|
||||
// InitListExpr is a tricky one, because we want to do all our work on
|
||||
// the syntactic form of the listexpr, but this method takes the
|
||||
// semantic form by default. We can't use the macro helper because it
|
||||
// calls WalkUp*() on the semantic form, before our code can convert
|
||||
// to the syntactic form.
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
|
||||
InitListExpr *Syn = S->isSemanticForm() ? S->getSyntacticForm() : S;
|
||||
if (Syn) {
|
||||
TRY_TO(WalkUpFromInitListExpr(Syn));
|
||||
bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
|
||||
InitListExpr *S, DataRecursionQueue *Queue) {
|
||||
if (S) {
|
||||
TRY_TO(WalkUpFromInitListExpr(S));
|
||||
// All we need are the default actions. FIXME: use a helper function.
|
||||
for (Stmt *SubStmt : Syn->children()) {
|
||||
TRY_TO(TraverseStmt(SubStmt));
|
||||
}
|
||||
}
|
||||
InitListExpr *Sem = S->isSemanticForm() ? S : S->getSemanticForm();
|
||||
if (Sem) {
|
||||
TRY_TO(WalkUpFromInitListExpr(Sem));
|
||||
for (Stmt *SubStmt : Sem->children()) {
|
||||
TRY_TO(TraverseStmt(SubStmt));
|
||||
for (Stmt *SubStmt : S->children()) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// This method is called once for each pair of syntactic and semantic
|
||||
// InitListExpr, and it traverses the subtrees defined by the two forms. This
|
||||
// may cause some of the children to be visited twice, if they appear both in
|
||||
// the syntactic and the semantic form.
|
||||
//
|
||||
// There is no guarantee about which form \p S takes when this method is called.
|
||||
DEF_TRAVERSE_STMT(InitListExpr, {
|
||||
TRY_TO(TraverseSynOrSemInitListExpr(
|
||||
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
|
||||
TRY_TO(TraverseSynOrSemInitListExpr(
|
||||
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
|
||||
return true;
|
||||
})
|
||||
|
||||
// GenericSelectionExpr is a special case because the types and expressions
|
||||
// are interleaved. We also need to watch out for null types (default
|
||||
// generic associations).
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseGenericSelectionExpr(
|
||||
GenericSelectionExpr *S) {
|
||||
TRY_TO(WalkUpFromGenericSelectionExpr(S));
|
||||
DEF_TRAVERSE_STMT(GenericSelectionExpr, {
|
||||
TRY_TO(TraverseStmt(S->getControllingExpr()));
|
||||
for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
|
||||
if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i))
|
||||
TRY_TO(TraverseTypeLoc(TS->getTypeLoc()));
|
||||
TRY_TO(TraverseStmt(S->getAssocExpr(i)));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAssocExpr(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
// PseudoObjectExpr is a special case because of the wierdness with
|
||||
// PseudoObjectExpr is a special case because of the weirdness with
|
||||
// syntactic expressions and opaque values.
|
||||
template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::TraversePseudoObjectExpr(PseudoObjectExpr *S) {
|
||||
TRY_TO(WalkUpFromPseudoObjectExpr(S));
|
||||
TRY_TO(TraverseStmt(S->getSyntacticForm()));
|
||||
DEF_TRAVERSE_STMT(PseudoObjectExpr, {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSyntacticForm());
|
||||
for (PseudoObjectExpr::semantics_iterator i = S->semantics_begin(),
|
||||
e = S->semantics_end();
|
||||
i != e; ++i) {
|
||||
Expr *sub = *i;
|
||||
if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
|
||||
sub = OVE->getSourceExpr();
|
||||
TRY_TO(TraverseStmt(sub));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(sub);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
|
||||
// This is called for code like 'return T()' where T is a built-in
|
||||
@ -2151,6 +2113,8 @@ DEF_TRAVERSE_STMT(MSPropertyRefExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(MSPropertySubscriptExpr, {})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXUuidofExpr, {
|
||||
// The child-iterator will pick up the arg if it's an expression,
|
||||
// but not if it's a type.
|
||||
@ -2168,7 +2132,7 @@ DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(ExpressionTraitExpr,
|
||||
{ TRY_TO(TraverseStmt(S->getQueriedExpression())); })
|
||||
{ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getQueriedExpression()); })
|
||||
|
||||
DEF_TRAVERSE_STMT(VAArgExpr, {
|
||||
// The child-iterator will pick up the expression argument.
|
||||
@ -2181,10 +2145,7 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
|
||||
})
|
||||
|
||||
// Walk only the visible parts of lambda expressions.
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
||||
TRY_TO(WalkUpFromLambdaExpr(S));
|
||||
|
||||
DEF_TRAVERSE_STMT(LambdaExpr, {
|
||||
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
|
||||
CEnd = S->explicit_capture_end();
|
||||
C != CEnd; ++C) {
|
||||
@ -2213,12 +2174,11 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
||||
}
|
||||
|
||||
if (Expr *NE = T->getNoexceptExpr())
|
||||
TRY_TO(TraverseStmt(NE));
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE);
|
||||
}
|
||||
|
||||
TRY_TO(TraverseLambdaBody(S));
|
||||
return true;
|
||||
}
|
||||
return TRAVERSE_STMT_BASE(LambdaBody, LambdaExpr, S, Queue);
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
|
||||
// This is called for code like 'T()', where T is a template argument.
|
||||
@ -2235,6 +2195,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {})
|
||||
// over the children.
|
||||
DEF_TRAVERSE_STMT(AddrLabelExpr, {})
|
||||
DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
|
||||
DEF_TRAVERSE_STMT(OMPArraySectionExpr, {})
|
||||
DEF_TRAVERSE_STMT(BlockExpr, {
|
||||
TRY_TO(TraverseDecl(S->getBlockDecl()));
|
||||
return true; // no child statements to loop through.
|
||||
@ -2336,6 +2297,34 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {})
|
||||
DEF_TRAVERSE_STMT(CXXFoldExpr, {})
|
||||
DEF_TRAVERSE_STMT(AtomicExpr, {})
|
||||
|
||||
// For coroutines expressions, traverse either the operand
|
||||
// as written or the implied calls, depending on what the
|
||||
// derived class requests.
|
||||
DEF_TRAVERSE_STMT(CoroutineBodyStmt, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());
|
||||
return true;
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_STMT(CoreturnStmt, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
|
||||
return true;
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_STMT(CoawaitExpr, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
|
||||
return true;
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_STMT(CoyieldExpr, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
|
||||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
// These literals (all of them) do not need any action.
|
||||
DEF_TRAVERSE_STMT(IntegerLiteral, {})
|
||||
DEF_TRAVERSE_STMT(CharacterLiteral, {})
|
||||
@ -2437,9 +2426,21 @@ DEF_TRAVERSE_STMT(OMPAtomicDirective,
|
||||
DEF_TRAVERSE_STMT(OMPTargetDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPTargetDataDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPTeamsDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPTaskLoopDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPTaskLoopSimdDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPDistributeDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
// OpenMP clauses.
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
|
||||
@ -2483,6 +2484,12 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSafelenClause(OMPSafelenClause *C) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPSimdlenClause(OMPSimdlenClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getSimdlen()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) {
|
||||
@ -2509,7 +2516,8 @@ RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *) {
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getNumForLoops()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2554,6 +2562,21 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPSIMDClause(OMPSIMDClause *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPNogroupClause(OMPNogroupClause *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
template <typename T>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
|
||||
@ -2615,6 +2638,9 @@ bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getStep()));
|
||||
TRY_TO(TraverseStmt(C->getCalcStep()));
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->privates()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->inits()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
@ -2671,6 +2697,9 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->privates()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->lhs_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
@ -2695,6 +2724,59 @@ bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPDeviceClause(OMPDeviceClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getDevice()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
|
||||
OMPNumTeamsClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getNumTeams()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause(
|
||||
OMPThreadLimitClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getThreadLimit()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPPriorityClause(
|
||||
OMPPriorityClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getPriority()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPGrainsizeClause(
|
||||
OMPGrainsizeClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getGrainsize()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPNumTasksClause(
|
||||
OMPNumTasksClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getNumTasks()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPHintClause(OMPHintClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getHint()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: look at the following tricky-seeming exprs to see if we
|
||||
// need to recurse on anything. These are ones that have methods
|
||||
// returning decls or qualtypes or nestednamespecifier -- though I'm
|
||||
@ -2713,6 +2795,8 @@ bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) {
|
||||
// Every class that has getQualifier.
|
||||
|
||||
#undef DEF_TRAVERSE_STMT
|
||||
#undef TRAVERSE_STMT
|
||||
#undef TRAVERSE_STMT_BASE
|
||||
|
||||
#undef TRY_TO
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <iterator>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
|
||||
/// \brief Provides common interface for the Decls that can be redeclared.
|
||||
template<typename decl_type>
|
||||
@ -32,7 +33,11 @@ class Redeclarable {
|
||||
&ExternalASTSource::CompleteRedeclChain>
|
||||
KnownLatest;
|
||||
|
||||
typedef const ASTContext *UninitializedLatest;
|
||||
/// We store a pointer to the ASTContext in the UninitializedLatest
|
||||
/// pointer, but to avoid circular type dependencies when we steal the low
|
||||
/// bits of this pointer, we use a raw void* here.
|
||||
typedef const void *UninitializedLatest;
|
||||
|
||||
typedef Decl *Previous;
|
||||
|
||||
/// A pointer to either an uninitialized latest declaration (where either
|
||||
@ -47,7 +52,7 @@ class Redeclarable {
|
||||
enum LatestTag { LatestLink };
|
||||
|
||||
DeclLink(LatestTag, const ASTContext &Ctx)
|
||||
: Next(NotKnownLatest(&Ctx)) {}
|
||||
: Next(NotKnownLatest(reinterpret_cast<UninitializedLatest>(&Ctx))) {}
|
||||
DeclLink(PreviousTag, decl_type *D)
|
||||
: Next(NotKnownLatest(Previous(D))) {}
|
||||
|
||||
@ -67,7 +72,8 @@ class Redeclarable {
|
||||
return static_cast<decl_type*>(NKL.get<Previous>());
|
||||
|
||||
// Allocate the generational 'most recent' cache now, if needed.
|
||||
Next = KnownLatest(*NKL.get<UninitializedLatest>(),
|
||||
Next = KnownLatest(*reinterpret_cast<const ASTContext *>(
|
||||
NKL.get<UninitializedLatest>()),
|
||||
const_cast<decl_type *>(D));
|
||||
}
|
||||
|
||||
@ -83,7 +89,9 @@ class Redeclarable {
|
||||
assert(NextIsLatest() && "decl became canonical unexpectedly");
|
||||
if (Next.is<NotKnownLatest>()) {
|
||||
NotKnownLatest NKL = Next.get<NotKnownLatest>();
|
||||
Next = KnownLatest(*NKL.get<UninitializedLatest>(), D);
|
||||
Next = KnownLatest(*reinterpret_cast<const ASTContext *>(
|
||||
NKL.get<UninitializedLatest>()),
|
||||
D);
|
||||
} else {
|
||||
auto Latest = Next.get<KnownLatest>();
|
||||
Latest.set(D);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <string>
|
||||
@ -49,57 +50,6 @@ namespace clang {
|
||||
class Token;
|
||||
class VarDecl;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ExprIterator - Iterators for iterating over Stmt* arrays that contain
|
||||
// only Expr*. This is needed because AST nodes use Stmt* arrays to store
|
||||
// references to children (to be compatible with StmtIterator).
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class Stmt;
|
||||
class Expr;
|
||||
|
||||
class ExprIterator : public std::iterator<std::forward_iterator_tag,
|
||||
Expr *&, ptrdiff_t,
|
||||
Expr *&, Expr *&> {
|
||||
Stmt** I;
|
||||
public:
|
||||
ExprIterator(Stmt** i) : I(i) {}
|
||||
ExprIterator() : I(nullptr) {}
|
||||
ExprIterator& operator++() { ++I; return *this; }
|
||||
ExprIterator operator-(size_t i) { return I-i; }
|
||||
ExprIterator operator+(size_t i) { return I+i; }
|
||||
Expr* operator[](size_t idx);
|
||||
// FIXME: Verify that this will correctly return a signed distance.
|
||||
signed operator-(const ExprIterator& R) const { return I - R.I; }
|
||||
Expr* operator*() const;
|
||||
Expr* operator->() const;
|
||||
bool operator==(const ExprIterator& R) const { return I == R.I; }
|
||||
bool operator!=(const ExprIterator& R) const { return I != R.I; }
|
||||
bool operator>(const ExprIterator& R) const { return I > R.I; }
|
||||
bool operator>=(const ExprIterator& R) const { return I >= R.I; }
|
||||
};
|
||||
|
||||
class ConstExprIterator : public std::iterator<std::forward_iterator_tag,
|
||||
const Expr *&, ptrdiff_t,
|
||||
const Expr *&,
|
||||
const Expr *&> {
|
||||
const Stmt * const *I;
|
||||
public:
|
||||
ConstExprIterator(const Stmt * const *i) : I(i) {}
|
||||
ConstExprIterator() : I(nullptr) {}
|
||||
ConstExprIterator& operator++() { ++I; return *this; }
|
||||
ConstExprIterator operator+(size_t i) const { return I+i; }
|
||||
ConstExprIterator operator-(size_t i) const { return I-i; }
|
||||
const Expr * operator[](size_t idx) const;
|
||||
signed operator-(const ConstExprIterator& R) const { return I - R.I; }
|
||||
const Expr * operator*() const;
|
||||
const Expr * operator->() const;
|
||||
bool operator==(const ConstExprIterator& R) const { return I == R.I; }
|
||||
bool operator!=(const ConstExprIterator& R) const { return I != R.I; }
|
||||
bool operator>(const ConstExprIterator& R) const { return I > R.I; }
|
||||
bool operator>=(const ConstExprIterator& R) const { return I >= R.I; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AST classes for statements.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -121,10 +71,10 @@ class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt {
|
||||
|
||||
// Make vanilla 'new' and 'delete' illegal for Stmts.
|
||||
protected:
|
||||
void* operator new(size_t bytes) throw() {
|
||||
void *operator new(size_t bytes) LLVM_NOEXCEPT {
|
||||
llvm_unreachable("Stmts cannot be allocated with regular 'new'.");
|
||||
}
|
||||
void operator delete(void* data) throw() {
|
||||
void operator delete(void *data) LLVM_NOEXCEPT {
|
||||
llvm_unreachable("Stmts cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
@ -322,14 +272,12 @@ class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt {
|
||||
return operator new(bytes, *C, alignment);
|
||||
}
|
||||
|
||||
void* operator new(size_t bytes, void* mem) throw() {
|
||||
return mem;
|
||||
}
|
||||
void *operator new(size_t bytes, void *mem) LLVM_NOEXCEPT { return mem; }
|
||||
|
||||
void operator delete(void*, const ASTContext&, unsigned) throw() { }
|
||||
void operator delete(void*, const ASTContext*, unsigned) throw() { }
|
||||
void operator delete(void*, size_t) throw() { }
|
||||
void operator delete(void*, void*) throw() { }
|
||||
void operator delete(void *, const ASTContext &, unsigned) LLVM_NOEXCEPT {}
|
||||
void operator delete(void *, const ASTContext *, unsigned) LLVM_NOEXCEPT {}
|
||||
void operator delete(void *, size_t) LLVM_NOEXCEPT {}
|
||||
void operator delete(void *, void *) LLVM_NOEXCEPT {}
|
||||
|
||||
public:
|
||||
/// \brief A placeholder type used to construct an empty shell of a
|
||||
@ -337,6 +285,39 @@ class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt {
|
||||
/// de-serialization).
|
||||
struct EmptyShell { };
|
||||
|
||||
protected:
|
||||
/// Iterator for iterating over Stmt * arrays that contain only Expr *
|
||||
///
|
||||
/// This is needed because AST nodes use Stmt* arrays to store
|
||||
/// references to children (to be compatible with StmtIterator).
|
||||
struct ExprIterator
|
||||
: llvm::iterator_adaptor_base<ExprIterator, Stmt **,
|
||||
std::random_access_iterator_tag, Expr *> {
|
||||
ExprIterator() : iterator_adaptor_base(nullptr) {}
|
||||
ExprIterator(Stmt **I) : iterator_adaptor_base(I) {}
|
||||
|
||||
reference operator*() const {
|
||||
assert((*I)->getStmtClass() >= firstExprConstant &&
|
||||
(*I)->getStmtClass() <= lastExprConstant);
|
||||
return *reinterpret_cast<Expr **>(I);
|
||||
}
|
||||
};
|
||||
|
||||
/// Const iterator for iterating over Stmt * arrays that contain only Expr *
|
||||
struct ConstExprIterator
|
||||
: llvm::iterator_adaptor_base<ConstExprIterator, const Stmt *const *,
|
||||
std::random_access_iterator_tag,
|
||||
const Expr *const> {
|
||||
ConstExprIterator() : iterator_adaptor_base(nullptr) {}
|
||||
ConstExprIterator(const Stmt *const *I) : iterator_adaptor_base(I) {}
|
||||
|
||||
reference operator*() const {
|
||||
assert((*I)->getStmtClass() >= firstExprConstant &&
|
||||
(*I)->getStmtClass() <= lastExprConstant);
|
||||
return *reinterpret_cast<const Expr *const *>(I);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief Whether statistic collection is enabled.
|
||||
static bool StatisticsEnabled;
|
||||
@ -411,19 +392,20 @@ class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt {
|
||||
typedef StmtIterator child_iterator;
|
||||
typedef ConstStmtIterator const_child_iterator;
|
||||
|
||||
typedef StmtRange child_range;
|
||||
typedef ConstStmtRange const_child_range;
|
||||
typedef llvm::iterator_range<child_iterator> child_range;
|
||||
typedef llvm::iterator_range<const_child_iterator> const_child_range;
|
||||
|
||||
child_range children();
|
||||
const_child_range children() const {
|
||||
return const_cast<Stmt*>(this)->children();
|
||||
auto Children = const_cast<Stmt *>(this)->children();
|
||||
return const_child_range(Children.begin(), Children.end());
|
||||
}
|
||||
|
||||
child_iterator child_begin() { return children().first; }
|
||||
child_iterator child_end() { return children().second; }
|
||||
child_iterator child_begin() { return children().begin(); }
|
||||
child_iterator child_end() { return children().end(); }
|
||||
|
||||
const_child_iterator child_begin() const { return children().first; }
|
||||
const_child_iterator child_end() const { return children().second; }
|
||||
const_child_iterator child_begin() const { return children().begin(); }
|
||||
const_child_iterator child_end() const { return children().end(); }
|
||||
|
||||
/// \brief Produce a unique representation of the given statement.
|
||||
///
|
||||
@ -544,7 +526,9 @@ class NullStmt : public Stmt {
|
||||
return T->getStmtClass() == NullStmtClass;
|
||||
}
|
||||
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
@ -574,7 +558,7 @@ class CompoundStmt : public Stmt {
|
||||
CompoundStmtBits.NumStmts = 0;
|
||||
}
|
||||
|
||||
void setStmts(const ASTContext &C, Stmt **Stmts, unsigned NumStmts);
|
||||
void setStmts(const ASTContext &C, ArrayRef<Stmt *> Stmts);
|
||||
|
||||
bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
|
||||
unsigned size() const { return CompoundStmtBits.NumStmts; }
|
||||
@ -643,7 +627,8 @@ class CompoundStmt : public Stmt {
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
return child_range(Body, Body + CompoundStmtBits.NumStmts);
|
||||
return const_child_range(child_iterator(Body),
|
||||
child_iterator(Body + CompoundStmtBits.NumStmts));
|
||||
}
|
||||
};
|
||||
|
||||
@ -840,18 +825,20 @@ class AttributedStmt : public Stmt {
|
||||
AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt)
|
||||
: Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc),
|
||||
NumAttrs(Attrs.size()) {
|
||||
memcpy(getAttrArrayPtr(), Attrs.data(), Attrs.size() * sizeof(Attr *));
|
||||
std::copy(Attrs.begin(), Attrs.end(), getAttrArrayPtr());
|
||||
}
|
||||
|
||||
explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs)
|
||||
: Stmt(AttributedStmtClass, Empty), NumAttrs(NumAttrs) {
|
||||
memset(getAttrArrayPtr(), 0, NumAttrs * sizeof(Attr *));
|
||||
std::fill_n(getAttrArrayPtr(), NumAttrs, nullptr);
|
||||
}
|
||||
|
||||
Attr *const *getAttrArrayPtr() const {
|
||||
return reinterpret_cast<Attr *const *>(this + 1);
|
||||
const Attr *const *getAttrArrayPtr() const {
|
||||
return reinterpret_cast<const Attr *const *>(this + 1);
|
||||
}
|
||||
const Attr **getAttrArrayPtr() {
|
||||
return reinterpret_cast<const Attr **>(this + 1);
|
||||
}
|
||||
Attr **getAttrArrayPtr() { return reinterpret_cast<Attr **>(this + 1); }
|
||||
|
||||
public:
|
||||
static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
|
||||
@ -1239,7 +1226,9 @@ class GotoStmt : public Stmt {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// IndirectGotoStmt - This represents an indirect goto.
|
||||
@ -1307,7 +1296,9 @@ class ContinueStmt : public Stmt {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// BreakStmt - This represents a break.
|
||||
@ -1335,7 +1326,9 @@ class BreakStmt : public Stmt {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1390,7 +1383,7 @@ class ReturnStmt : public Stmt {
|
||||
// Iterators
|
||||
child_range children() {
|
||||
if (RetExpr) return child_range(&RetExpr, &RetExpr+1);
|
||||
return child_range();
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
@ -1974,7 +1967,9 @@ class SEHLeaveStmt : public Stmt {
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This captures a statement into a function. For example, the following
|
||||
@ -1993,6 +1988,7 @@ class CapturedStmt : public Stmt {
|
||||
enum VariableCaptureKind {
|
||||
VCK_This,
|
||||
VCK_ByRef,
|
||||
VCK_ByCopy,
|
||||
VCK_VLAType,
|
||||
};
|
||||
|
||||
@ -2012,24 +2008,10 @@ class CapturedStmt : public Stmt {
|
||||
/// \param Var The variable being captured, or null if capturing this.
|
||||
///
|
||||
Capture(SourceLocation Loc, VariableCaptureKind Kind,
|
||||
VarDecl *Var = nullptr)
|
||||
: VarAndKind(Var, Kind), Loc(Loc) {
|
||||
switch (Kind) {
|
||||
case VCK_This:
|
||||
assert(!Var && "'this' capture cannot have a variable!");
|
||||
break;
|
||||
case VCK_ByRef:
|
||||
assert(Var && "capturing by reference must have a variable!");
|
||||
break;
|
||||
case VCK_VLAType:
|
||||
assert(!Var &&
|
||||
"Variable-length array type capture cannot have a variable!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
VarDecl *Var = nullptr);
|
||||
|
||||
/// \brief Determine the kind of capture.
|
||||
VariableCaptureKind getCaptureKind() const { return VarAndKind.getInt(); }
|
||||
VariableCaptureKind getCaptureKind() const;
|
||||
|
||||
/// \brief Retrieve the source location at which the variable or 'this' was
|
||||
/// first used.
|
||||
@ -2038,9 +2020,14 @@ class CapturedStmt : public Stmt {
|
||||
/// \brief Determine whether this capture handles the C++ 'this' pointer.
|
||||
bool capturesThis() const { return getCaptureKind() == VCK_This; }
|
||||
|
||||
/// \brief Determine whether this capture handles a variable.
|
||||
/// \brief Determine whether this capture handles a variable (by reference).
|
||||
bool capturesVariable() const { return getCaptureKind() == VCK_ByRef; }
|
||||
|
||||
/// \brief Determine whether this capture handles a variable by copy.
|
||||
bool capturesVariableByCopy() const {
|
||||
return getCaptureKind() == VCK_ByCopy;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this capture handles a variable-length array
|
||||
/// type.
|
||||
bool capturesVariableArrayType() const {
|
||||
@ -2050,11 +2037,8 @@ class CapturedStmt : public Stmt {
|
||||
/// \brief Retrieve the declaration of the variable being captured.
|
||||
///
|
||||
/// This operation is only valid if this capture captures a variable.
|
||||
VarDecl *getCapturedVar() const {
|
||||
assert(capturesVariable() &&
|
||||
"No variable available for 'this' or VAT capture");
|
||||
return VarAndKind.getPointer();
|
||||
}
|
||||
VarDecl *getCapturedVar() const;
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
@ -2076,8 +2060,10 @@ class CapturedStmt : public Stmt {
|
||||
/// \brief Construct an empty captured statement.
|
||||
CapturedStmt(EmptyShell Empty, unsigned NumCaptures);
|
||||
|
||||
Stmt **getStoredStmts() const {
|
||||
return reinterpret_cast<Stmt **>(const_cast<CapturedStmt *>(this) + 1);
|
||||
Stmt **getStoredStmts() { return reinterpret_cast<Stmt **>(this + 1); }
|
||||
|
||||
Stmt *const *getStoredStmts() const {
|
||||
return reinterpret_cast<Stmt *const *>(this + 1);
|
||||
}
|
||||
|
||||
Capture *getStoredCaptures() const;
|
||||
@ -2096,31 +2082,20 @@ class CapturedStmt : public Stmt {
|
||||
|
||||
/// \brief Retrieve the statement being captured.
|
||||
Stmt *getCapturedStmt() { return getStoredStmts()[NumCaptures]; }
|
||||
const Stmt *getCapturedStmt() const {
|
||||
return const_cast<CapturedStmt *>(this)->getCapturedStmt();
|
||||
}
|
||||
const Stmt *getCapturedStmt() const { return getStoredStmts()[NumCaptures]; }
|
||||
|
||||
/// \brief Retrieve the outlined function declaration.
|
||||
CapturedDecl *getCapturedDecl() { return CapDeclAndKind.getPointer(); }
|
||||
const CapturedDecl *getCapturedDecl() const {
|
||||
return const_cast<CapturedStmt *>(this)->getCapturedDecl();
|
||||
}
|
||||
CapturedDecl *getCapturedDecl();
|
||||
const CapturedDecl *getCapturedDecl() const;
|
||||
|
||||
/// \brief Set the outlined function declaration.
|
||||
void setCapturedDecl(CapturedDecl *D) {
|
||||
assert(D && "null CapturedDecl");
|
||||
CapDeclAndKind.setPointer(D);
|
||||
}
|
||||
void setCapturedDecl(CapturedDecl *D);
|
||||
|
||||
/// \brief Retrieve the captured region kind.
|
||||
CapturedRegionKind getCapturedRegionKind() const {
|
||||
return CapDeclAndKind.getInt();
|
||||
}
|
||||
CapturedRegionKind getCapturedRegionKind() const;
|
||||
|
||||
/// \brief Set the captured region kind.
|
||||
void setCapturedRegionKind(CapturedRegionKind Kind) {
|
||||
CapDeclAndKind.setInt(Kind);
|
||||
}
|
||||
void setCapturedRegionKind(CapturedRegionKind Kind);
|
||||
|
||||
/// \brief Retrieve the record declaration for captured variables.
|
||||
const RecordDecl *getCapturedRecordDecl() const { return TheRecordDecl; }
|
||||
@ -2164,18 +2139,36 @@ class CapturedStmt : public Stmt {
|
||||
typedef Expr **capture_init_iterator;
|
||||
typedef llvm::iterator_range<capture_init_iterator> capture_init_range;
|
||||
|
||||
capture_init_range capture_inits() const {
|
||||
/// \brief Const iterator that walks over the capture initialization
|
||||
/// arguments.
|
||||
typedef Expr *const *const_capture_init_iterator;
|
||||
typedef llvm::iterator_range<const_capture_init_iterator>
|
||||
const_capture_init_range;
|
||||
|
||||
capture_init_range capture_inits() {
|
||||
return capture_init_range(capture_init_begin(), capture_init_end());
|
||||
}
|
||||
|
||||
const_capture_init_range capture_inits() const {
|
||||
return const_capture_init_range(capture_init_begin(), capture_init_end());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the first initialization argument.
|
||||
capture_init_iterator capture_init_begin() const {
|
||||
capture_init_iterator capture_init_begin() {
|
||||
return reinterpret_cast<Expr **>(getStoredStmts());
|
||||
}
|
||||
|
||||
const_capture_init_iterator capture_init_begin() const {
|
||||
return reinterpret_cast<Expr *const *>(getStoredStmts());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the iterator pointing one past the last initialization
|
||||
/// argument.
|
||||
capture_init_iterator capture_init_end() const {
|
||||
capture_init_iterator capture_init_end() {
|
||||
return capture_init_begin() + NumCaptures;
|
||||
}
|
||||
|
||||
const_capture_init_iterator capture_init_end() const {
|
||||
return capture_init_begin() + NumCaptures;
|
||||
}
|
||||
|
||||
|
@ -131,12 +131,16 @@ class CXXForRangeStmt : public Stmt {
|
||||
// SubExprs[RANGE] is an expression or declstmt.
|
||||
// SubExprs[COND] and SubExprs[INC] are expressions.
|
||||
Stmt *SubExprs[END];
|
||||
SourceLocation CoawaitLoc;
|
||||
SourceLocation ColonLoc;
|
||||
SourceLocation RParenLoc;
|
||||
|
||||
friend class ASTStmtReader;
|
||||
public:
|
||||
CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd,
|
||||
Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
|
||||
SourceLocation FL, SourceLocation CL, SourceLocation RPL);
|
||||
SourceLocation FL, SourceLocation CAL, SourceLocation CL,
|
||||
SourceLocation RPL);
|
||||
CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { }
|
||||
|
||||
|
||||
@ -181,13 +185,10 @@ class CXXForRangeStmt : public Stmt {
|
||||
void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; }
|
||||
void setBody(Stmt *S) { SubExprs[BODY] = S; }
|
||||
|
||||
|
||||
SourceLocation getForLoc() const { return ForLoc; }
|
||||
void setForLoc(SourceLocation Loc) { ForLoc = Loc; }
|
||||
SourceLocation getCoawaitLoc() const { return CoawaitLoc; }
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
@ -287,6 +288,130 @@ class MSDependentExistsStmt : public Stmt {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents the body of a coroutine. This wraps the normal function
|
||||
/// body and holds the additional semantic context required to set up and tear
|
||||
/// down the coroutine frame.
|
||||
class CoroutineBodyStmt : public Stmt {
|
||||
enum SubStmt {
|
||||
Body, ///< The body of the coroutine.
|
||||
Promise, ///< The promise statement.
|
||||
InitSuspend, ///< The initial suspend statement, run before the body.
|
||||
FinalSuspend, ///< The final suspend statement, run after the body.
|
||||
OnException, ///< Handler for exceptions thrown in the body.
|
||||
OnFallthrough, ///< Handler for control flow falling off the body.
|
||||
ReturnValue, ///< Return value for thunk function.
|
||||
FirstParamMove ///< First offset for move construction of parameter copies.
|
||||
};
|
||||
Stmt *SubStmts[SubStmt::FirstParamMove];
|
||||
|
||||
friend class ASTStmtReader;
|
||||
public:
|
||||
CoroutineBodyStmt(Stmt *Body, Stmt *Promise, Stmt *InitSuspend,
|
||||
Stmt *FinalSuspend, Stmt *OnException, Stmt *OnFallthrough,
|
||||
Expr *ReturnValue, ArrayRef<Expr *> ParamMoves)
|
||||
: Stmt(CoroutineBodyStmtClass) {
|
||||
SubStmts[CoroutineBodyStmt::Body] = Body;
|
||||
SubStmts[CoroutineBodyStmt::Promise] = Promise;
|
||||
SubStmts[CoroutineBodyStmt::InitSuspend] = InitSuspend;
|
||||
SubStmts[CoroutineBodyStmt::FinalSuspend] = FinalSuspend;
|
||||
SubStmts[CoroutineBodyStmt::OnException] = OnException;
|
||||
SubStmts[CoroutineBodyStmt::OnFallthrough] = OnFallthrough;
|
||||
SubStmts[CoroutineBodyStmt::ReturnValue] = ReturnValue;
|
||||
// FIXME: Tail-allocate space for parameter move expressions and store them.
|
||||
assert(ParamMoves.empty() && "not implemented yet");
|
||||
}
|
||||
|
||||
/// \brief Retrieve the body of the coroutine as written. This will be either
|
||||
/// a CompoundStmt or a TryStmt.
|
||||
Stmt *getBody() const {
|
||||
return SubStmts[SubStmt::Body];
|
||||
}
|
||||
|
||||
Stmt *getPromiseDeclStmt() const { return SubStmts[SubStmt::Promise]; }
|
||||
VarDecl *getPromiseDecl() const {
|
||||
return cast<VarDecl>(cast<DeclStmt>(getPromiseDeclStmt())->getSingleDecl());
|
||||
}
|
||||
|
||||
Stmt *getInitSuspendStmt() const { return SubStmts[SubStmt::InitSuspend]; }
|
||||
Stmt *getFinalSuspendStmt() const { return SubStmts[SubStmt::FinalSuspend]; }
|
||||
|
||||
Stmt *getExceptionHandler() const { return SubStmts[SubStmt::OnException]; }
|
||||
Stmt *getFallthroughHandler() const {
|
||||
return SubStmts[SubStmt::OnFallthrough];
|
||||
}
|
||||
|
||||
Expr *getReturnValueInit() const {
|
||||
return cast<Expr>(SubStmts[SubStmt::ReturnValue]);
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return getBody()->getLocStart();
|
||||
}
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
return getBody()->getLocEnd();
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(SubStmts, SubStmts + SubStmt::FirstParamMove);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CoroutineBodyStmtClass;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a 'co_return' statement in the C++ Coroutines TS.
|
||||
///
|
||||
/// This statament models the initialization of the coroutine promise
|
||||
/// (encapsulating the eventual notional return value) from an expression
|
||||
/// (or braced-init-list), followed by termination of the coroutine.
|
||||
///
|
||||
/// This initialization is modeled by the evaluation of the operand
|
||||
/// followed by a call to one of:
|
||||
/// <promise>.return_value(<operand>)
|
||||
/// <promise>.return_void()
|
||||
/// which we name the "promise call".
|
||||
class CoreturnStmt : public Stmt {
|
||||
SourceLocation CoreturnLoc;
|
||||
|
||||
enum SubStmt { Operand, PromiseCall, Count };
|
||||
Stmt *SubStmts[SubStmt::Count];
|
||||
|
||||
friend class ASTStmtReader;
|
||||
public:
|
||||
CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall)
|
||||
: Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc) {
|
||||
SubStmts[SubStmt::Operand] = Operand;
|
||||
SubStmts[SubStmt::PromiseCall] = PromiseCall;
|
||||
}
|
||||
|
||||
SourceLocation getKeywordLoc() const { return CoreturnLoc; }
|
||||
|
||||
/// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr
|
||||
/// if none was specified.
|
||||
Expr *getOperand() const { return static_cast<Expr*>(SubStmts[Operand]); }
|
||||
|
||||
/// \brief Retrieve the promise call that results from this 'co_return'
|
||||
/// statement. Will be nullptr if either the coroutine has not yet been
|
||||
/// finalized or the coroutine has no eventual return type.
|
||||
Expr *getPromiseCall() const {
|
||||
return static_cast<Expr*>(SubStmts[PromiseCall]);
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
return getOperand()->getLocEnd();
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(SubStmts, SubStmts + SubStmt::Count);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CoreturnStmtClass;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -139,86 +139,6 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
|
||||
};
|
||||
|
||||
/// A range of statement iterators.
|
||||
///
|
||||
/// This class provides some extra functionality beyond std::pair
|
||||
/// in order to allow the following idiom:
|
||||
/// for (StmtRange range = stmt->children(); range; ++range)
|
||||
struct StmtRange : std::pair<StmtIterator,StmtIterator> {
|
||||
StmtRange() {}
|
||||
StmtRange(const StmtIterator &begin, const StmtIterator &end)
|
||||
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
explicit operator bool() const { return !empty(); }
|
||||
|
||||
Stmt *operator->() const { return first.operator->(); }
|
||||
Stmt *&operator*() const { return first.operator*(); }
|
||||
|
||||
StmtRange &operator++() {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
++first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
StmtRange operator++(int) {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
StmtRange copy = *this;
|
||||
++first;
|
||||
return copy;
|
||||
}
|
||||
|
||||
friend const StmtIterator &begin(const StmtRange &range) {
|
||||
return range.first;
|
||||
}
|
||||
friend const StmtIterator &end(const StmtRange &range) {
|
||||
return range.second;
|
||||
}
|
||||
};
|
||||
|
||||
/// A range of const statement iterators.
|
||||
///
|
||||
/// This class provides some extra functionality beyond std::pair
|
||||
/// in order to allow the following idiom:
|
||||
/// for (ConstStmtRange range = stmt->children(); range; ++range)
|
||||
struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
|
||||
ConstStmtRange() {}
|
||||
ConstStmtRange(const ConstStmtIterator &begin,
|
||||
const ConstStmtIterator &end)
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||
ConstStmtRange(const StmtRange &range)
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(range.first, range.second)
|
||||
{}
|
||||
ConstStmtRange(const StmtIterator &begin, const StmtIterator &end)
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
explicit operator bool() const { return !empty(); }
|
||||
|
||||
const Stmt *operator->() const { return first.operator->(); }
|
||||
const Stmt *operator*() const { return first.operator*(); }
|
||||
|
||||
ConstStmtRange &operator++() {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
++first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConstStmtRange operator++(int) {
|
||||
assert(!empty() && "incrementing on empty range");
|
||||
ConstStmtRange copy = *this;
|
||||
++first;
|
||||
return copy;
|
||||
}
|
||||
|
||||
friend const ConstStmtIterator &begin(const ConstStmtRange &range) {
|
||||
return range.first;
|
||||
}
|
||||
friend const ConstStmtIterator &end(const ConstStmtRange &range) {
|
||||
return range.second;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
||||
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/ExprOpenMP.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/AST/StmtOpenMP.h"
|
||||
@ -93,6 +94,7 @@ class StmtVisitorBase {
|
||||
case UO_Real: DISPATCH(UnaryReal, UnaryOperator);
|
||||
case UO_Imag: DISPATCH(UnaryImag, UnaryOperator);
|
||||
case UO_Extension: DISPATCH(UnaryExtension, UnaryOperator);
|
||||
case UO_Coawait: DISPATCH(UnaryCoawait, UnaryOperator);
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,7 +159,7 @@ class StmtVisitorBase {
|
||||
UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
|
||||
UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
|
||||
UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
|
||||
UNARYOP_FALLBACK(Extension)
|
||||
UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(Coawait)
|
||||
#undef UNARYOP_FALLBACK
|
||||
|
||||
// Base case, ignore it. :)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
|
||||
namespace llvm {
|
||||
class FoldingSetNodeID;
|
||||
@ -198,22 +199,19 @@ class TemplateArgument {
|
||||
///
|
||||
/// We assume that storage for the template arguments provided
|
||||
/// outlives the TemplateArgument itself.
|
||||
TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) {
|
||||
explicit TemplateArgument(ArrayRef<TemplateArgument> Args) {
|
||||
this->Args.Kind = Pack;
|
||||
this->Args.Args = Args;
|
||||
this->Args.NumArgs = NumArgs;
|
||||
this->Args.Args = Args.data();
|
||||
this->Args.NumArgs = Args.size();
|
||||
}
|
||||
|
||||
static TemplateArgument getEmptyPack() {
|
||||
return TemplateArgument((TemplateArgument*)nullptr, 0);
|
||||
}
|
||||
static TemplateArgument getEmptyPack() { return TemplateArgument(None); }
|
||||
|
||||
/// \brief Create a new template argument pack by copying the given set of
|
||||
/// template arguments.
|
||||
static TemplateArgument CreatePackCopy(ASTContext &Context,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs);
|
||||
|
||||
ArrayRef<TemplateArgument> Args);
|
||||
|
||||
/// \brief Return the kind of stored template argument.
|
||||
ArgKind getKind() const { return (ArgKind)TypeOrValue.Kind; }
|
||||
|
||||
@ -523,7 +521,7 @@ class TemplateArgumentListInfo {
|
||||
|
||||
// This can leak if used in an AST node, use ASTTemplateArgumentListInfo
|
||||
// instead.
|
||||
void* operator new(size_t bytes, ASTContext& C);
|
||||
void *operator new(size_t bytes, ASTContext &C) = delete;
|
||||
|
||||
public:
|
||||
TemplateArgumentListInfo() {}
|
||||
@ -544,6 +542,10 @@ class TemplateArgumentListInfo {
|
||||
return Arguments.data();
|
||||
}
|
||||
|
||||
llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
|
||||
return Arguments;
|
||||
}
|
||||
|
||||
const TemplateArgumentLoc &operator[](unsigned I) const {
|
||||
return Arguments[I];
|
||||
}
|
||||
@ -561,84 +563,72 @@ class TemplateArgumentListInfo {
|
||||
/// the "<int>" in "sort<int>".
|
||||
/// This is safe to be used inside an AST node, in contrast with
|
||||
/// TemplateArgumentListInfo.
|
||||
struct ASTTemplateArgumentListInfo {
|
||||
struct ASTTemplateArgumentListInfo final
|
||||
: private llvm::TrailingObjects<ASTTemplateArgumentListInfo,
|
||||
TemplateArgumentLoc> {
|
||||
private:
|
||||
friend TrailingObjects;
|
||||
|
||||
ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
|
||||
|
||||
public:
|
||||
/// \brief The source location of the left angle bracket ('<').
|
||||
SourceLocation LAngleLoc;
|
||||
|
||||
|
||||
/// \brief The source location of the right angle bracket ('>').
|
||||
SourceLocation RAngleLoc;
|
||||
|
||||
union {
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
/// The actual template arguments (if any) are stored after the
|
||||
/// ExplicitTemplateArgumentList structure.
|
||||
unsigned NumTemplateArgs;
|
||||
|
||||
/// Force ASTTemplateArgumentListInfo to the right alignment
|
||||
/// for the following array of TemplateArgumentLocs.
|
||||
llvm::AlignedCharArray<
|
||||
llvm::AlignOf<TemplateArgumentLoc>::Alignment, 1> Aligner;
|
||||
};
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
unsigned NumTemplateArgs;
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
TemplateArgumentLoc *getTemplateArgs() {
|
||||
return reinterpret_cast<TemplateArgumentLoc *> (this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
return reinterpret_cast<const TemplateArgumentLoc *> (this + 1);
|
||||
return getTrailingObjects<TemplateArgumentLoc>();
|
||||
}
|
||||
|
||||
const TemplateArgumentLoc &operator[](unsigned I) const {
|
||||
return getTemplateArgs()[I];
|
||||
}
|
||||
|
||||
static const ASTTemplateArgumentListInfo *Create(ASTContext &C,
|
||||
const TemplateArgumentListInfo &List);
|
||||
|
||||
void initializeFrom(const TemplateArgumentListInfo &List);
|
||||
void initializeFrom(const TemplateArgumentListInfo &List,
|
||||
bool &Dependent, bool &InstantiationDependent,
|
||||
bool &ContainsUnexpandedParameterPack);
|
||||
void copyInto(TemplateArgumentListInfo &List) const;
|
||||
static std::size_t sizeFor(unsigned NumTemplateArgs);
|
||||
static const ASTTemplateArgumentListInfo *
|
||||
Create(ASTContext &C, const TemplateArgumentListInfo &List);
|
||||
};
|
||||
|
||||
/// \brief Extends ASTTemplateArgumentListInfo with the source location
|
||||
/// information for the template keyword; this is used as part of the
|
||||
/// representation of qualified identifiers, such as S<T>::template apply<T>.
|
||||
struct ASTTemplateKWAndArgsInfo : public ASTTemplateArgumentListInfo {
|
||||
typedef ASTTemplateArgumentListInfo Base;
|
||||
/// \brief Represents an explicit template argument list in C++, e.g.,
|
||||
/// the "<int>" in "sort<int>".
|
||||
///
|
||||
/// It is intended to be used as a trailing object on AST nodes, and
|
||||
/// as such, doesn't contain the array of TemplateArgumentLoc itself,
|
||||
/// but expects the containing object to also provide storage for
|
||||
/// that.
|
||||
struct LLVM_ALIGNAS(LLVM_PTR_SIZE) ASTTemplateKWAndArgsInfo {
|
||||
/// \brief The source location of the left angle bracket ('<').
|
||||
SourceLocation LAngleLoc;
|
||||
|
||||
// NOTE: the source location of the (optional) template keyword is
|
||||
// stored after all template arguments.
|
||||
/// \brief The source location of the right angle bracket ('>').
|
||||
SourceLocation RAngleLoc;
|
||||
|
||||
/// \brief Get the source location of the template keyword.
|
||||
SourceLocation getTemplateKeywordLoc() const {
|
||||
return *reinterpret_cast<const SourceLocation*>
|
||||
(getTemplateArgs() + NumTemplateArgs);
|
||||
}
|
||||
/// \brief The source location of the template keyword; this is used
|
||||
/// as part of the representation of qualified identifiers, such as
|
||||
/// S<T>::template apply<T>. Will be empty if this expression does
|
||||
/// not have a template keyword.
|
||||
SourceLocation TemplateKWLoc;
|
||||
|
||||
/// \brief Sets the source location of the template keyword.
|
||||
void setTemplateKeywordLoc(SourceLocation TemplateKWLoc) {
|
||||
*reinterpret_cast<SourceLocation*>
|
||||
(getTemplateArgs() + NumTemplateArgs) = TemplateKWLoc;
|
||||
}
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
unsigned NumTemplateArgs;
|
||||
|
||||
static const ASTTemplateKWAndArgsInfo*
|
||||
Create(ASTContext &C, SourceLocation TemplateKWLoc,
|
||||
const TemplateArgumentListInfo &List);
|
||||
|
||||
void initializeFrom(SourceLocation TemplateKWLoc,
|
||||
const TemplateArgumentListInfo &List);
|
||||
void initializeFrom(SourceLocation TemplateKWLoc,
|
||||
const TemplateArgumentListInfo &List,
|
||||
bool &Dependent, bool &InstantiationDependent,
|
||||
TemplateArgumentLoc *OutArgArray);
|
||||
void initializeFrom(SourceLocation TemplateKWLoc,
|
||||
const TemplateArgumentListInfo &List,
|
||||
TemplateArgumentLoc *OutArgArray, bool &Dependent,
|
||||
bool &InstantiationDependent,
|
||||
bool &ContainsUnexpandedParameterPack);
|
||||
void initializeFrom(SourceLocation TemplateKWLoc);
|
||||
|
||||
static std::size_t sizeFor(unsigned NumTemplateArgs);
|
||||
void copyInto(const TemplateArgumentLoc *ArgArray,
|
||||
TemplateArgumentListInfo &List) const;
|
||||
};
|
||||
|
||||
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
|
@ -180,9 +180,7 @@ class TemplateName {
|
||||
|
||||
StorageType Storage;
|
||||
|
||||
explicit TemplateName(void *Ptr) {
|
||||
Storage = StorageType::getFromOpaqueValue(Ptr);
|
||||
}
|
||||
explicit TemplateName(void *Ptr);
|
||||
|
||||
public:
|
||||
// \brief Kind of name that is actually stored.
|
||||
@ -207,17 +205,15 @@ class TemplateName {
|
||||
};
|
||||
|
||||
TemplateName() : Storage() { }
|
||||
explicit TemplateName(TemplateDecl *Template) : Storage(Template) { }
|
||||
explicit TemplateName(OverloadedTemplateStorage *Storage)
|
||||
: Storage(Storage) { }
|
||||
explicit TemplateName(TemplateDecl *Template);
|
||||
explicit TemplateName(OverloadedTemplateStorage *Storage);
|
||||
explicit TemplateName(SubstTemplateTemplateParmStorage *Storage);
|
||||
explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
|
||||
: Storage(Storage) { }
|
||||
explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { }
|
||||
explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { }
|
||||
explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage);
|
||||
explicit TemplateName(QualifiedTemplateName *Qual);
|
||||
explicit TemplateName(DependentTemplateName *Dep);
|
||||
|
||||
/// \brief Determine whether this template name is NULL.
|
||||
bool isNull() const { return Storage.isNull(); }
|
||||
bool isNull() const;
|
||||
|
||||
// \brief Get the kind of name that is actually stored.
|
||||
NameKind getKind() const;
|
||||
@ -238,26 +234,14 @@ class TemplateName {
|
||||
/// name refers to, if known. If the template name does not refer to a
|
||||
/// specific set of function templates because it is a dependent name or
|
||||
/// refers to a single template, returns NULL.
|
||||
OverloadedTemplateStorage *getAsOverloadedTemplate() const {
|
||||
if (UncommonTemplateNameStorage *Uncommon =
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return Uncommon->getAsOverloadedStorage();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
OverloadedTemplateStorage *getAsOverloadedTemplate() const;
|
||||
|
||||
/// \brief Retrieve the substituted template template parameter, if
|
||||
/// known.
|
||||
///
|
||||
/// \returns The storage for the substituted template template parameter,
|
||||
/// if known. Otherwise, returns NULL.
|
||||
SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const {
|
||||
if (UncommonTemplateNameStorage *uncommon =
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return uncommon->getAsSubstTemplateTemplateParm();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const;
|
||||
|
||||
/// \brief Retrieve the substituted template template parameter pack, if
|
||||
/// known.
|
||||
@ -265,25 +249,15 @@ class TemplateName {
|
||||
/// \returns The storage for the substituted template template parameter pack,
|
||||
/// if known. Otherwise, returns NULL.
|
||||
SubstTemplateTemplateParmPackStorage *
|
||||
getAsSubstTemplateTemplateParmPack() const {
|
||||
if (UncommonTemplateNameStorage *Uncommon =
|
||||
Storage.dyn_cast<UncommonTemplateNameStorage *>())
|
||||
return Uncommon->getAsSubstTemplateTemplateParmPack();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
getAsSubstTemplateTemplateParmPack() const;
|
||||
|
||||
/// \brief Retrieve the underlying qualified template name
|
||||
/// structure, if any.
|
||||
QualifiedTemplateName *getAsQualifiedTemplateName() const {
|
||||
return Storage.dyn_cast<QualifiedTemplateName *>();
|
||||
}
|
||||
QualifiedTemplateName *getAsQualifiedTemplateName() const;
|
||||
|
||||
/// \brief Retrieve the underlying dependent template name
|
||||
/// structure, if any.
|
||||
DependentTemplateName *getAsDependentTemplateName() const {
|
||||
return Storage.dyn_cast<DependentTemplateName *>();
|
||||
}
|
||||
DependentTemplateName *getAsDependentTemplateName() const;
|
||||
|
||||
TemplateName getUnderlying() const;
|
||||
|
||||
@ -359,9 +333,6 @@ class SubstTemplateTemplateParmStorage
|
||||
TemplateName replacement);
|
||||
};
|
||||
|
||||
inline TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
|
||||
: Storage(Storage) { }
|
||||
|
||||
inline TemplateName TemplateName::getUnderlying() const {
|
||||
if (SubstTemplateTemplateParmStorage *subst
|
||||
= getAsSubstTemplateTemplateParm())
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -151,6 +151,14 @@ class TypeLoc {
|
||||
|
||||
TypeLoc IgnoreParens() const;
|
||||
|
||||
/// \brief Find a type with the location of an explicit type qualifier.
|
||||
///
|
||||
/// The result, if non-null, will be one of:
|
||||
/// QualifiedTypeLoc
|
||||
/// AtomicTypeLoc
|
||||
/// AttributedTypeLoc, for those type attributes that behave as qualifiers
|
||||
TypeLoc findExplicitQualifierLoc() const;
|
||||
|
||||
/// \brief Initializes this to state that every location in this
|
||||
/// type is the given location.
|
||||
///
|
||||
@ -162,19 +170,18 @@ class TypeLoc {
|
||||
|
||||
/// \brief Initializes this by copying its information from another
|
||||
/// TypeLoc of the same type.
|
||||
void initializeFullCopy(TypeLoc Other) const {
|
||||
void initializeFullCopy(TypeLoc Other) {
|
||||
assert(getType() == Other.getType());
|
||||
size_t Size = getFullDataSize();
|
||||
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
|
||||
copy(Other);
|
||||
}
|
||||
|
||||
/// \brief Initializes this by copying its information from another
|
||||
/// TypeLoc of the same type. The given size must be the full data
|
||||
/// size.
|
||||
void initializeFullCopy(TypeLoc Other, unsigned Size) const {
|
||||
void initializeFullCopy(TypeLoc Other, unsigned Size) {
|
||||
assert(getType() == Other.getType());
|
||||
assert(getFullDataSize() == Size);
|
||||
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
|
||||
copy(Other);
|
||||
}
|
||||
|
||||
/// Copies the other type loc into this one.
|
||||
@ -206,6 +213,7 @@ class TypeLoc {
|
||||
|
||||
/// \brief Return the TypeLoc for a type source info.
|
||||
inline TypeLoc TypeSourceInfo::getTypeLoc() const {
|
||||
// TODO: is this alignment already sufficient?
|
||||
return TypeLoc(Ty, const_cast<void*>(static_cast<const void*>(this + 1)));
|
||||
}
|
||||
|
||||
@ -736,6 +744,10 @@ class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
return hasAttrExprOperand() || hasAttrEnumOperand();
|
||||
}
|
||||
|
||||
bool isQualifier() const {
|
||||
return getTypePtr()->isQualifier();
|
||||
}
|
||||
|
||||
/// The modified type, which is generally canonically different from
|
||||
/// the attribute type.
|
||||
/// int main(int, char**) __attribute__((noreturn))
|
||||
|
@ -51,7 +51,7 @@ class VTableComponent {
|
||||
CK_UnusedFunctionPointer
|
||||
};
|
||||
|
||||
VTableComponent() { }
|
||||
VTableComponent() = default;
|
||||
|
||||
static VTableComponent MakeVCallOffset(CharUnits Offset) {
|
||||
return VTableComponent(CK_VCallOffset, Offset);
|
||||
@ -122,31 +122,56 @@ class VTableComponent {
|
||||
}
|
||||
|
||||
const CXXRecordDecl *getRTTIDecl() const {
|
||||
assert(getKind() == CK_RTTI && "Invalid component kind!");
|
||||
|
||||
assert(isRTTIKind() && "Invalid component kind!");
|
||||
return reinterpret_cast<CXXRecordDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXMethodDecl *getFunctionDecl() const {
|
||||
assert(getKind() == CK_FunctionPointer);
|
||||
|
||||
assert(isFunctionPointerKind() && "Invalid component kind!");
|
||||
if (isDestructorKind())
|
||||
return getDestructorDecl();
|
||||
return reinterpret_cast<CXXMethodDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXDestructorDecl *getDestructorDecl() const {
|
||||
assert((getKind() == CK_CompleteDtorPointer ||
|
||||
getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
|
||||
|
||||
assert(isDestructorKind() && "Invalid component kind!");
|
||||
return reinterpret_cast<CXXDestructorDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXMethodDecl *getUnusedFunctionDecl() const {
|
||||
assert(getKind() == CK_UnusedFunctionPointer);
|
||||
|
||||
assert(getKind() == CK_UnusedFunctionPointer && "Invalid component kind!");
|
||||
return reinterpret_cast<CXXMethodDecl *>(getPointer());
|
||||
}
|
||||
|
||||
bool isDestructorKind() const { return isDestructorKind(getKind()); }
|
||||
|
||||
bool isUsedFunctionPointerKind() const {
|
||||
return isUsedFunctionPointerKind(getKind());
|
||||
}
|
||||
|
||||
bool isFunctionPointerKind() const {
|
||||
return isFunctionPointerKind(getKind());
|
||||
}
|
||||
|
||||
bool isRTTIKind() const { return isRTTIKind(getKind()); }
|
||||
|
||||
private:
|
||||
static bool isFunctionPointerKind(Kind ComponentKind) {
|
||||
return isUsedFunctionPointerKind(ComponentKind) ||
|
||||
ComponentKind == CK_UnusedFunctionPointer;
|
||||
}
|
||||
static bool isUsedFunctionPointerKind(Kind ComponentKind) {
|
||||
return ComponentKind == CK_FunctionPointer ||
|
||||
isDestructorKind(ComponentKind);
|
||||
}
|
||||
static bool isDestructorKind(Kind ComponentKind) {
|
||||
return ComponentKind == CK_CompleteDtorPointer ||
|
||||
ComponentKind == CK_DeletingDtorPointer;
|
||||
}
|
||||
static bool isRTTIKind(Kind ComponentKind) {
|
||||
return ComponentKind == CK_RTTI;
|
||||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, CharUnits Offset) {
|
||||
assert((ComponentKind == CK_VCallOffset ||
|
||||
ComponentKind == CK_VBaseOffset ||
|
||||
@ -158,12 +183,8 @@ class VTableComponent {
|
||||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
|
||||
assert((ComponentKind == CK_RTTI ||
|
||||
ComponentKind == CK_FunctionPointer ||
|
||||
ComponentKind == CK_CompleteDtorPointer ||
|
||||
ComponentKind == CK_DeletingDtorPointer ||
|
||||
ComponentKind == CK_UnusedFunctionPointer) &&
|
||||
"Invalid component kind!");
|
||||
assert((isRTTIKind(ComponentKind) || isFunctionPointerKind(ComponentKind)) &&
|
||||
"Invalid component kind!");
|
||||
|
||||
assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
|
||||
|
||||
@ -178,11 +199,7 @@ class VTableComponent {
|
||||
}
|
||||
|
||||
uintptr_t getPointer() const {
|
||||
assert((getKind() == CK_RTTI ||
|
||||
getKind() == CK_FunctionPointer ||
|
||||
getKind() == CK_CompleteDtorPointer ||
|
||||
getKind() == CK_DeletingDtorPointer ||
|
||||
getKind() == CK_UnusedFunctionPointer) &&
|
||||
assert((getKind() == CK_RTTI || isFunctionPointerKind()) &&
|
||||
"Invalid component kind!");
|
||||
|
||||
return static_cast<uintptr_t>(Value & ~7ULL);
|
||||
@ -205,8 +222,11 @@ class VTableLayout {
|
||||
|
||||
typedef const VTableComponent *vtable_component_iterator;
|
||||
typedef const VTableThunkTy *vtable_thunk_iterator;
|
||||
typedef llvm::iterator_range<vtable_component_iterator>
|
||||
vtable_component_range;
|
||||
|
||||
typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
|
||||
|
||||
private:
|
||||
uint64_t NumVTableComponents;
|
||||
std::unique_ptr<VTableComponent[]> VTableComponents;
|
||||
@ -233,6 +253,11 @@ class VTableLayout {
|
||||
return NumVTableComponents;
|
||||
}
|
||||
|
||||
vtable_component_range vtable_components() const {
|
||||
return vtable_component_range(vtable_component_begin(),
|
||||
vtable_component_end());
|
||||
}
|
||||
|
||||
vtable_component_iterator vtable_component_begin() const {
|
||||
return VTableComponents.get();
|
||||
}
|
||||
@ -376,10 +401,6 @@ struct VPtrInfo {
|
||||
VPtrInfo(const CXXRecordDecl *RD)
|
||||
: ReusingBase(RD), BaseWithVPtr(RD), NextBaseToMangle(RD) {}
|
||||
|
||||
// Copy constructor.
|
||||
// FIXME: Uncomment when we've moved to C++11.
|
||||
// VPtrInfo(const VPtrInfo &) = default;
|
||||
|
||||
/// The vtable will hold all of the virtual bases or virtual methods of
|
||||
/// ReusingBase. This may or may not be the same class as VPtrSubobject.Base.
|
||||
/// A derived class will reuse the vptr of the first non-virtual base
|
||||
|
@ -42,6 +42,7 @@
|
||||
#define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
|
||||
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
|
||||
@ -208,7 +209,7 @@ class MatchFinder {
|
||||
NestedNameSpecifierLoc;
|
||||
std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
|
||||
/// \brief All the callbacks in one container to simplify iteration.
|
||||
std::vector<MatchCallback *> AllCallbacks;
|
||||
llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
|
||||
};
|
||||
|
||||
private:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -188,8 +188,11 @@ class ASTMatchFinder;
|
||||
/// Used by the implementation of Matcher<T> and DynTypedMatcher.
|
||||
/// In general, implement MatcherInterface<T> or SingleNodeMatcherInterface<T>
|
||||
/// instead.
|
||||
class DynMatcherInterface : public RefCountedBaseVPTR {
|
||||
class DynMatcherInterface
|
||||
: public llvm::ThreadSafeRefCountedBase<DynMatcherInterface> {
|
||||
public:
|
||||
virtual ~DynMatcherInterface() {}
|
||||
|
||||
/// \brief Returns true if \p DynNode can be matched.
|
||||
///
|
||||
/// May bind \p DynNode to an ID via \p Builder, or recurse into
|
||||
@ -209,8 +212,6 @@ class DynMatcherInterface : public RefCountedBaseVPTR {
|
||||
template <typename T>
|
||||
class MatcherInterface : public DynMatcherInterface {
|
||||
public:
|
||||
~MatcherInterface() override {}
|
||||
|
||||
/// \brief Returns true if 'Node' can be matched.
|
||||
///
|
||||
/// May bind 'Node' to an ID via 'Builder', or recurse into
|
||||
@ -281,6 +282,7 @@ class DynTypedMatcher {
|
||||
};
|
||||
static DynTypedMatcher
|
||||
constructVariadic(VariadicOperator Op,
|
||||
ast_type_traits::ASTNodeKind SupportedKind,
|
||||
std::vector<DynTypedMatcher> InnerMatchers);
|
||||
|
||||
/// \brief Get a "true" matcher for \p NodeKind.
|
||||
@ -556,22 +558,32 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Metafunction to determine if type T has a member called getDecl.
|
||||
// Metafunction to determine if type T has a member called
|
||||
// getDecl.
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1900) && !defined(__clang__)
|
||||
// For old versions of MSVC, we use a weird nonstandard __if_exists
|
||||
// statement, since before MSVC2015, it was not standards-conformant
|
||||
// enough to compile the usual code below.
|
||||
template <typename T> struct has_getDecl {
|
||||
struct Default { int getDecl; };
|
||||
struct Derived : T, Default { };
|
||||
|
||||
template<typename C, C> struct CheckT;
|
||||
|
||||
// If T::getDecl exists, an ambiguity arises and CheckT will
|
||||
// not be instantiable. This makes f(...) the only available
|
||||
// overload.
|
||||
template<typename C>
|
||||
static char (&f(CheckT<int Default::*, &C::getDecl>*))[1];
|
||||
template<typename C> static char (&f(...))[2];
|
||||
|
||||
static bool const value = sizeof(f<Derived>(nullptr)) == 2;
|
||||
__if_exists(T::getDecl) {
|
||||
enum { value = 1 };
|
||||
}
|
||||
__if_not_exists(T::getDecl) {
|
||||
enum { value = 0 };
|
||||
}
|
||||
};
|
||||
#else
|
||||
// There is a default template inheriting from "false_type". Then, a
|
||||
// partial specialization inherits from "true_type". However, this
|
||||
// specialization will only exist when the call to getDecl() isn't an
|
||||
// error -- it vanishes by SFINAE when the member doesn't exist.
|
||||
template <typename> struct type_sink_to_void { typedef void type; };
|
||||
template <typename T, typename = void> struct has_getDecl : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_getDecl<
|
||||
T, typename type_sink_to_void<decltype(std::declval<T>().getDecl())>::type>
|
||||
: std::true_type {};
|
||||
#endif
|
||||
|
||||
/// \brief Matches overloaded operators with a specific name.
|
||||
///
|
||||
@ -667,16 +679,30 @@ class HasDeclarationMatcher : public WrapperMatcherInterface<T> {
|
||||
return matchesDecl(Node.getDecl(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Extracts the CXXRecordDecl or EnumDecl of a QualType and returns
|
||||
/// whether the inner matcher matches on it.
|
||||
/// \brief Extracts the TagDecl of a QualType and returns whether the inner
|
||||
/// matcher matches on it.
|
||||
bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
/// FIXME: Add other ways to convert...
|
||||
if (Node.isNull())
|
||||
return false;
|
||||
if (const EnumType *AsEnum = dyn_cast<EnumType>(Node.getTypePtr()))
|
||||
return matchesDecl(AsEnum->getDecl(), Finder, Builder);
|
||||
return matchesDecl(Node->getAsCXXRecordDecl(), Finder, Builder);
|
||||
|
||||
if (auto *TD = Node->getAsTagDecl())
|
||||
return matchesDecl(TD, Finder, Builder);
|
||||
else if (auto *TT = Node->getAs<TypedefType>())
|
||||
return matchesDecl(TT->getDecl(), Finder, Builder);
|
||||
// Do not use getAs<TemplateTypeParmType> instead of the direct dyn_cast.
|
||||
// Calling getAs will return the canonical type, but that type does not
|
||||
// store a TemplateTypeParmDecl. We *need* the uncanonical type, if it is
|
||||
// available, and using dyn_cast ensures that.
|
||||
else if (auto *TTP = dyn_cast<TemplateTypeParmType>(Node.getTypePtr()))
|
||||
return matchesDecl(TTP->getDecl(), Finder, Builder);
|
||||
else if (auto *OCIT = Node->getAs<ObjCInterfaceType>())
|
||||
return matchesDecl(OCIT->getDecl(), Finder, Builder);
|
||||
else if (auto *UUT = Node->getAs<UnresolvedUsingType>())
|
||||
return matchesDecl(UUT->getDecl(), Finder, Builder);
|
||||
else if (auto *ICNT = Node->getAs<InjectedClassNameType>())
|
||||
return matchesDecl(ICNT->getDecl(), Finder, Builder);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Gets the TemplateDecl from a TemplateSpecializationType
|
||||
@ -753,7 +779,7 @@ const bool IsBaseType<T>::value;
|
||||
/// at least one ancestor matched.
|
||||
///
|
||||
/// FIXME: Currently we only allow Stmt and Decl nodes to start a traversal.
|
||||
/// In the future, we wan to implement this for all nodes for which it makes
|
||||
/// In the future, we want to implement this for all nodes for which it makes
|
||||
/// sense. In the case of matchesAncestorOf, we'll want to implement it for
|
||||
/// all nodes, as all nodes have ancestors.
|
||||
class ASTMatchFinder {
|
||||
@ -833,8 +859,10 @@ class ASTMatchFinder {
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
AncestorMatchMode MatchMode) {
|
||||
static_assert(std::is_base_of<Decl, T>::value ||
|
||||
std::is_base_of<Stmt, T>::value,
|
||||
"only Decl or Stmt allowed for recursive matching");
|
||||
std::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||
std::is_base_of<Stmt, T>::value ||
|
||||
std::is_base_of<TypeLoc, T>::value,
|
||||
"type not allowed for recursive matching");
|
||||
return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node),
|
||||
Matcher, Builder, MatchMode);
|
||||
}
|
||||
@ -1137,7 +1165,8 @@ template <typename... Ps> class VariadicOperatorMatcher {
|
||||
|
||||
template <typename T> operator Matcher<T>() const {
|
||||
return DynTypedMatcher::constructVariadic(
|
||||
Op, getMatchers<T>(llvm::index_sequence_for<Ps...>()))
|
||||
Op, ast_type_traits::ASTNodeKind::getFromNodeKind<T>(),
|
||||
getMatchers<T>(llvm::index_sequence_for<Ps...>()))
|
||||
.template unconditionalConvertTo<T>();
|
||||
}
|
||||
|
||||
@ -1191,8 +1220,10 @@ BindableMatcher<T> makeAllOfComposite(
|
||||
std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()),
|
||||
PI(InnerMatchers.end()));
|
||||
return BindableMatcher<T>(
|
||||
DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf,
|
||||
std::move(DynMatchers))
|
||||
DynTypedMatcher::constructVariadic(
|
||||
DynTypedMatcher::VO_AllOf,
|
||||
ast_type_traits::ASTNodeKind::getFromNodeKind<T>(),
|
||||
std::move(DynMatchers))
|
||||
.template unconditionalConvertTo<T>());
|
||||
}
|
||||
|
||||
|
@ -104,11 +104,11 @@ class Diagnostics {
|
||||
/// \brief About to call the constructor for a matcher.
|
||||
enum ConstructMatcherEnum { ConstructMatcher };
|
||||
Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName,
|
||||
const SourceRange &MatcherRange);
|
||||
SourceRange MatcherRange);
|
||||
/// \brief About to recurse into parsing one argument for a matcher.
|
||||
enum MatcherArgEnum { MatcherArg };
|
||||
Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName,
|
||||
const SourceRange &MatcherRange, unsigned ArgNumber);
|
||||
SourceRange MatcherRange, unsigned ArgNumber);
|
||||
~Context();
|
||||
|
||||
private:
|
||||
@ -137,7 +137,7 @@ class Diagnostics {
|
||||
/// All the context information will be kept on the error message.
|
||||
/// \return a helper class to allow the caller to pass the arguments for the
|
||||
/// error message, using the << operator.
|
||||
ArgStream addError(const SourceRange &Range, ErrorType Error);
|
||||
ArgStream addError(SourceRange Range, ErrorType Error);
|
||||
|
||||
/// \brief Information stored for one frame of the context.
|
||||
struct ContextFrame {
|
||||
|
@ -81,7 +81,7 @@ class Parser {
|
||||
/// matcher if an error occurred. In that case, \c Error will contain a
|
||||
/// description of the error.
|
||||
virtual VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
|
||||
const SourceRange &NameRange,
|
||||
SourceRange NameRange,
|
||||
StringRef BindID,
|
||||
ArrayRef<ParserValue> Args,
|
||||
Diagnostics *Error) = 0;
|
||||
@ -129,7 +129,7 @@ class Parser {
|
||||
lookupMatcherCtor(StringRef MatcherName) override;
|
||||
|
||||
VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
|
||||
const SourceRange &NameRange,
|
||||
SourceRange NameRange,
|
||||
StringRef BindID,
|
||||
ArrayRef<ParserValue> Args,
|
||||
Diagnostics *Error) override;
|
||||
|
@ -106,7 +106,7 @@ class Registry {
|
||||
/// the signature. In that case \c Error will contain the description of
|
||||
/// the error.
|
||||
static VariantMatcher constructMatcher(MatcherCtor Ctor,
|
||||
const SourceRange &NameRange,
|
||||
SourceRange NameRange,
|
||||
ArrayRef<ParserValue> Args,
|
||||
Diagnostics *Error);
|
||||
|
||||
@ -117,7 +117,7 @@ class Registry {
|
||||
/// If the matcher is not bindable, it sets an error in \c Error and returns
|
||||
/// a null matcher.
|
||||
static VariantMatcher constructBoundMatcher(MatcherCtor Ctor,
|
||||
const SourceRange &NameRange,
|
||||
SourceRange NameRange,
|
||||
StringRef BindID,
|
||||
ArrayRef<ParserValue> Args,
|
||||
Diagnostics *Error);
|
||||
|
@ -71,7 +71,7 @@ namespace consumed {
|
||||
virtual void warnParamReturnTypestateMismatch(SourceLocation Loc,
|
||||
StringRef VariableName,
|
||||
StringRef ExpectedState,
|
||||
StringRef ObservedState) {};
|
||||
StringRef ObservedState) {}
|
||||
|
||||
// FIXME: Add documentation.
|
||||
virtual void warnParamTypestateMismatch(SourceLocation LOC,
|
||||
@ -162,8 +162,8 @@ namespace consumed {
|
||||
ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const;
|
||||
|
||||
/// \brief Merge this state map with another map.
|
||||
void intersect(const ConsumedStateMap *Other);
|
||||
|
||||
void intersect(const ConsumedStateMap &Other);
|
||||
|
||||
void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack,
|
||||
const ConsumedStateMap *LoopBackStates,
|
||||
ConsumedWarningsHandlerBase &WarningsHandler);
|
||||
@ -196,15 +196,19 @@ namespace consumed {
|
||||
};
|
||||
|
||||
class ConsumedBlockInfo {
|
||||
std::vector<ConsumedStateMap*> StateMapsArray;
|
||||
std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray;
|
||||
std::vector<unsigned int> VisitOrder;
|
||||
|
||||
public:
|
||||
ConsumedBlockInfo() { }
|
||||
~ConsumedBlockInfo() { llvm::DeleteContainerPointers(StateMapsArray); }
|
||||
ConsumedBlockInfo() = default;
|
||||
ConsumedBlockInfo &operator=(ConsumedBlockInfo &&Other) {
|
||||
StateMapsArray = std::move(Other.StateMapsArray);
|
||||
VisitOrder = std::move(Other.VisitOrder);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph)
|
||||
: StateMapsArray(NumBlocks, nullptr), VisitOrder(NumBlocks, 0) {
|
||||
: StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) {
|
||||
unsigned int VisitOrderCounter = 0;
|
||||
for (PostOrderCFGView::iterator BI = SortedGraph->begin(),
|
||||
BE = SortedGraph->end(); BI != BE; ++BI) {
|
||||
@ -214,17 +218,18 @@ namespace consumed {
|
||||
|
||||
bool allBackEdgesVisited(const CFGBlock *CurrBlock,
|
||||
const CFGBlock *TargetBlock);
|
||||
|
||||
|
||||
void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap,
|
||||
bool &AlreadyOwned);
|
||||
void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap);
|
||||
|
||||
std::unique_ptr<ConsumedStateMap> &OwnedStateMap);
|
||||
void addInfo(const CFGBlock *Block,
|
||||
std::unique_ptr<ConsumedStateMap> StateMap);
|
||||
|
||||
ConsumedStateMap* borrowInfo(const CFGBlock *Block);
|
||||
|
||||
void discardInfo(const CFGBlock *Block);
|
||||
|
||||
ConsumedStateMap* getInfo(const CFGBlock *Block);
|
||||
|
||||
|
||||
std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block);
|
||||
|
||||
bool isBackEdge(const CFGBlock *From, const CFGBlock *To);
|
||||
bool isBackEdgeTarget(const CFGBlock *Block);
|
||||
};
|
||||
@ -233,13 +238,12 @@ namespace consumed {
|
||||
class ConsumedAnalyzer {
|
||||
|
||||
ConsumedBlockInfo BlockInfo;
|
||||
ConsumedStateMap *CurrStates;
|
||||
|
||||
std::unique_ptr<ConsumedStateMap> CurrStates;
|
||||
|
||||
ConsumedState ExpectedReturnState;
|
||||
|
||||
void determineExpectedReturnState(AnalysisDeclContext &AC,
|
||||
const FunctionDecl *D);
|
||||
bool hasConsumableAttributes(const CXXRecordDecl *RD);
|
||||
bool splitState(const CFGBlock *CurrBlock,
|
||||
const ConsumedStmtVisitor &Visitor);
|
||||
|
||||
|
@ -287,10 +287,12 @@ class CapabilityExpr {
|
||||
}
|
||||
|
||||
const ValueDecl* valueDecl() const {
|
||||
if (Negated)
|
||||
if (Negated || CapExpr == nullptr)
|
||||
return nullptr;
|
||||
if (auto *P = dyn_cast<til::Project>(CapExpr))
|
||||
return P->clangDecl();
|
||||
if (auto *P = dyn_cast<til::LiteralPtr>(CapExpr))
|
||||
return P->clangDecl();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1395,7 +1395,7 @@ class Goto : public Terminator {
|
||||
|
||||
/// Return the list of basic blocks that this terminator can branch to.
|
||||
ArrayRef<BasicBlock*> successors() {
|
||||
return ArrayRef<BasicBlock*>(&TargetBlock, 1);
|
||||
return TargetBlock;
|
||||
}
|
||||
|
||||
template <class V>
|
||||
@ -1445,7 +1445,7 @@ class Branch : public Terminator {
|
||||
|
||||
/// Return the list of basic blocks that this terminator can branch to.
|
||||
ArrayRef<BasicBlock*> successors() {
|
||||
return ArrayRef<BasicBlock*>(Branches, 2);
|
||||
return llvm::makeArrayRef(Branches);
|
||||
}
|
||||
|
||||
template <class V>
|
||||
@ -1479,7 +1479,7 @@ class Return : public Terminator {
|
||||
|
||||
/// Return an empty list.
|
||||
ArrayRef<BasicBlock*> successors() {
|
||||
return ArrayRef<BasicBlock*>();
|
||||
return None;
|
||||
}
|
||||
|
||||
SExpr *returnValue() { return Retval; }
|
||||
@ -1507,7 +1507,7 @@ inline ArrayRef<BasicBlock*> Terminator::successors() {
|
||||
case COP_Branch: return cast<Branch>(this)->successors();
|
||||
case COP_Return: return cast<Return>(this)->successors();
|
||||
default:
|
||||
return ArrayRef<BasicBlock*>();
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,7 +229,6 @@ class CFGDeleteDtor : public CFGImplicitDtor {
|
||||
return static_cast<CXXDeleteExpr *>(Data2.getPointer());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGDeleteDtor() {}
|
||||
@ -693,7 +692,7 @@ class CFGBlock {
|
||||
iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
|
||||
BumpVectorContext &C) {
|
||||
return iterator(Elements.insert(I.base(), Cnt,
|
||||
CFGAutomaticObjDtor(nullptr, 0), C));
|
||||
CFGAutomaticObjDtor(nullptr, nullptr), C));
|
||||
}
|
||||
iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
|
||||
*I = CFGAutomaticObjDtor(VD, S);
|
||||
@ -767,7 +766,7 @@ class CFG {
|
||||
/// (not a pointer to CFGBlock).
|
||||
class graph_iterator {
|
||||
public:
|
||||
typedef const CFGBlock value_type;
|
||||
typedef CFGBlock value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef BumpVector<CFGBlock*>::iterator ImplTy;
|
||||
@ -1110,4 +1109,5 @@ template <> struct GraphTraits<Inverse<const ::clang::CFG*> >
|
||||
}
|
||||
};
|
||||
} // end llvm namespace
|
||||
#endif
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_CFG_H
|
||||
|
@ -33,8 +33,31 @@ namespace clang {
|
||||
class AnalysisDeclContext;
|
||||
class FunctionDecl;
|
||||
class LocationContext;
|
||||
class ProgramPointTag;
|
||||
|
||||
/// ProgramPoints can be "tagged" as representing points specific to a given
|
||||
/// analysis entity. Tags are abstract annotations, with an associated
|
||||
/// description and potentially other information.
|
||||
class ProgramPointTag {
|
||||
public:
|
||||
ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {}
|
||||
virtual ~ProgramPointTag();
|
||||
virtual StringRef getTagDescription() const = 0;
|
||||
|
||||
protected:
|
||||
/// Used to implement 'isKind' in subclasses.
|
||||
const void *getTagKind() { return TagKind; }
|
||||
|
||||
private:
|
||||
const void *TagKind;
|
||||
};
|
||||
|
||||
class SimpleProgramPointTag : public ProgramPointTag {
|
||||
std::string Desc;
|
||||
public:
|
||||
SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg);
|
||||
StringRef getTagDescription() const override;
|
||||
};
|
||||
|
||||
class ProgramPoint {
|
||||
public:
|
||||
enum Kind { BlockEdgeKind,
|
||||
@ -643,30 +666,6 @@ class EpsilonPoint : public ProgramPoint {
|
||||
}
|
||||
};
|
||||
|
||||
/// ProgramPoints can be "tagged" as representing points specific to a given
|
||||
/// analysis entity. Tags are abstract annotations, with an associated
|
||||
/// description and potentially other information.
|
||||
class ProgramPointTag {
|
||||
public:
|
||||
ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {}
|
||||
virtual ~ProgramPointTag();
|
||||
virtual StringRef getTagDescription() const = 0;
|
||||
|
||||
protected:
|
||||
/// Used to implement 'isKind' in subclasses.
|
||||
const void *getTagKind() { return TagKind; }
|
||||
|
||||
private:
|
||||
const void *TagKind;
|
||||
};
|
||||
|
||||
class SimpleProgramPointTag : public ProgramPointTag {
|
||||
std::string Desc;
|
||||
public:
|
||||
SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg);
|
||||
StringRef getTagDescription() const override;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
|
@ -35,7 +35,12 @@ class BumpVectorContext {
|
||||
/// Construct a new BumpVectorContext that creates a new BumpPtrAllocator
|
||||
/// and destroys it when the BumpVectorContext object is destroyed.
|
||||
BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), 1) {}
|
||||
|
||||
|
||||
BumpVectorContext(BumpVectorContext &&Other) : Alloc(Other.Alloc) {
|
||||
Other.Alloc.setInt(false);
|
||||
Other.Alloc.setPointer(nullptr);
|
||||
}
|
||||
|
||||
/// Construct a new BumpVectorContext that reuses an existing
|
||||
/// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the
|
||||
/// BumpVectorContext object is destroyed.
|
||||
|
@ -113,7 +113,7 @@ def GlobalVar : SubsetSubject<Var,
|
||||
// the case of a SubsetSubject, there's no way to express it without this hack.
|
||||
def DeclBase : AttrSubject;
|
||||
def FunctionLike : SubsetSubject<DeclBase,
|
||||
[{S->getFunctionType(false) != NULL}]>;
|
||||
[{S->getFunctionType(false) != nullptr}]>;
|
||||
|
||||
def OpenCLKernelFunction : SubsetSubject<Function, [{
|
||||
S->hasAttr<OpenCLKernelAttr>()
|
||||
@ -123,15 +123,19 @@ def OpenCLKernelFunction : SubsetSubject<Function, [{
|
||||
// never be specified in a Subjects list along with FunctionLike (due to the
|
||||
// inclusive nature of subject testing).
|
||||
def HasFunctionProto : SubsetSubject<DeclBase,
|
||||
[{(S->getFunctionType(true) != NULL &&
|
||||
[{(S->getFunctionType(true) != nullptr &&
|
||||
isa<FunctionProtoType>(S->getFunctionType())) ||
|
||||
isa<ObjCMethodDecl>(S) ||
|
||||
isa<BlockDecl>(S)}]>;
|
||||
|
||||
// A single argument to an attribute
|
||||
class Argument<string name, bit optional> {
|
||||
class Argument<string name, bit optional, bit fake = 0> {
|
||||
string Name = name;
|
||||
bit Optional = optional;
|
||||
|
||||
/// A fake argument is used to store and serialize additional information
|
||||
/// in an attribute without actually changing its parsing or pretty-printing.
|
||||
bit Fake = fake;
|
||||
}
|
||||
|
||||
class BoolArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
@ -167,7 +171,8 @@ class DefaultIntArgument<string name, int default> : IntArgument<name, 1> {
|
||||
// This argument is more complex, it includes the enumerator type name,
|
||||
// a list of strings to accept, and a list of enumerators to map them to.
|
||||
class EnumArgument<string name, string type, list<string> values,
|
||||
list<string> enums, bit opt = 0> : Argument<name, opt> {
|
||||
list<string> enums, bit opt = 0, bit fake = 0>
|
||||
: Argument<name, opt, fake> {
|
||||
string Type = type;
|
||||
list<string> Values = values;
|
||||
list<string> Enums = enums;
|
||||
@ -241,14 +246,18 @@ def COnly : LangOpt<"CPlusPlus", 1>;
|
||||
class TargetArch<list<string> arches> {
|
||||
list<string> Arches = arches;
|
||||
list<string> OSes;
|
||||
list<string> CXXABIs;
|
||||
}
|
||||
def TargetARM : TargetArch<["arm", "thumb"]>;
|
||||
def TargetMips : TargetArch<["mips", "mipsel"]>;
|
||||
def TargetMSP430 : TargetArch<["msp430"]>;
|
||||
def TargetX86 : TargetArch<["x86"]>;
|
||||
def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
|
||||
let OSes = ["Win32"];
|
||||
}
|
||||
def TargetMips : TargetArch<["mips", "mipsel"]>;
|
||||
def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
|
||||
let CXXABIs = ["Microsoft"];
|
||||
}
|
||||
|
||||
class Attr {
|
||||
// The various ways in which an attribute can be spelled in source
|
||||
@ -286,6 +295,8 @@ class Attr {
|
||||
// attribute to be applicable. If empty, no language options are required.
|
||||
list<LangOpt> LangOpts = [];
|
||||
// Any additional text that should be included verbatim in the class.
|
||||
// Note: Any additional data members will leak and should be constructed
|
||||
// externally on the ASTContext.
|
||||
code AdditionalMembers = [{}];
|
||||
// Any documentation that should be associated with the attribute. Since an
|
||||
// attribute may be documented under multiple categories, more than one
|
||||
@ -415,8 +426,8 @@ def Annotate : InheritableParamAttr {
|
||||
}
|
||||
|
||||
def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
|
||||
// NOTE: If you add any additional spellings, MSP430Interrupt's spellings
|
||||
// must match.
|
||||
// NOTE: If you add any additional spellings, MSP430Interrupt's and
|
||||
// MipsInterrupt's spellings must match.
|
||||
let Spellings = [GNU<"interrupt">];
|
||||
let Args = [EnumArgument<"Interrupt", "InterruptType",
|
||||
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
|
||||
@ -445,8 +456,12 @@ def Availability : InheritableAttr {
|
||||
.Case("android", "Android")
|
||||
.Case("ios", "iOS")
|
||||
.Case("macosx", "OS X")
|
||||
.Case("tvos", "tvOS")
|
||||
.Case("watchos", "watchOS")
|
||||
.Case("ios_app_extension", "iOS (App Extension)")
|
||||
.Case("macosx_app_extension", "OS X (App Extension)")
|
||||
.Case("tvos_app_extension", "tvOS (App Extension)")
|
||||
.Case("watchos_app_extension", "watchOS (App Extension)")
|
||||
.Default(llvm::StringRef());
|
||||
} }];
|
||||
let HasCustomParsing = 1;
|
||||
@ -553,6 +568,11 @@ def CUDAConstant : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def CUDACudartBuiltin : IgnoredAttr {
|
||||
let Spellings = [GNU<"cudart_builtin">];
|
||||
let LangOpts = [CUDA];
|
||||
}
|
||||
|
||||
def CUDADevice : InheritableAttr {
|
||||
let Spellings = [GNU<"device">];
|
||||
let Subjects = SubjectList<[Function, Var]>;
|
||||
@ -560,6 +580,21 @@ def CUDADevice : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def CUDADeviceBuiltin : IgnoredAttr {
|
||||
let Spellings = [GNU<"device_builtin">];
|
||||
let LangOpts = [CUDA];
|
||||
}
|
||||
|
||||
def CUDADeviceBuiltinSurfaceType : IgnoredAttr {
|
||||
let Spellings = [GNU<"device_builtin_surface_type">];
|
||||
let LangOpts = [CUDA];
|
||||
}
|
||||
|
||||
def CUDADeviceBuiltinTextureType : IgnoredAttr {
|
||||
let Spellings = [GNU<"device_builtin_texture_type">];
|
||||
let LangOpts = [CUDA];
|
||||
}
|
||||
|
||||
def CUDAGlobal : InheritableAttr {
|
||||
let Spellings = [GNU<"global">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
@ -721,18 +756,6 @@ def FlagEnum : InheritableAttr {
|
||||
let Subjects = SubjectList<[Enum]>;
|
||||
let Documentation = [FlagEnumDocs];
|
||||
let LangOpts = [COnly];
|
||||
let AdditionalMembers = [{
|
||||
private:
|
||||
llvm::APInt FlagBits;
|
||||
public:
|
||||
llvm::APInt &getFlagBits() {
|
||||
return FlagBits;
|
||||
}
|
||||
|
||||
const llvm::APInt &getFlagBits() const {
|
||||
return FlagBits;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def Flatten : InheritableAttr {
|
||||
@ -746,7 +769,7 @@ def Format : InheritableAttr {
|
||||
let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">,
|
||||
IntArgument<"FirstArg">];
|
||||
let Subjects = SubjectList<[ObjCMethod, Block, HasFunctionProto], WarnDiag,
|
||||
"ExpectedFunction">;
|
||||
"ExpectedFunctionWithProtoType">;
|
||||
let Documentation = [FormatDocs];
|
||||
}
|
||||
|
||||
@ -754,7 +777,7 @@ def FormatArg : InheritableAttr {
|
||||
let Spellings = [GCC<"format_arg">];
|
||||
let Args = [IntArgument<"FormatIdx">];
|
||||
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto], WarnDiag,
|
||||
"ExpectedFunction">;
|
||||
"ExpectedFunctionWithProtoType">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
@ -822,8 +845,8 @@ def MSABI : InheritableAttr {
|
||||
}
|
||||
|
||||
def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
|
||||
// NOTE: If you add any additional spellings, ARMInterrupt's spellings must
|
||||
// match.
|
||||
// NOTE: If you add any additional spellings, ARMInterrupt's and
|
||||
// MipsInterrupt's spellings must match.
|
||||
let Spellings = [GNU<"interrupt">];
|
||||
let Args = [UnsignedArgument<"Number">];
|
||||
let ParseKind = "Interrupt";
|
||||
@ -837,6 +860,22 @@ def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
||||
// NOTE: If you add any additional spellings, ARMInterrupt's and
|
||||
// MSP430Interrupt's spellings must match.
|
||||
let Spellings = [GNU<"interrupt">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Args = [EnumArgument<"Interrupt", "InterruptType",
|
||||
["vector=sw0", "vector=sw1", "vector=hw0",
|
||||
"vector=hw1", "vector=hw2", "vector=hw3",
|
||||
"vector=hw4", "vector=hw5", "eic", ""],
|
||||
["sw0", "sw1", "hw0", "hw1", "hw2", "hw3",
|
||||
"hw4", "hw5", "eic", "eic"]
|
||||
>];
|
||||
let ParseKind = "Interrupt";
|
||||
let Documentation = [MipsInterruptDocs];
|
||||
}
|
||||
|
||||
def Mode : Attr {
|
||||
let Spellings = [GCC<"mode">];
|
||||
let Args = [IdentifierArgument<"Mode">];
|
||||
@ -867,6 +906,19 @@ def ReturnsTwice : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def DisableTailCalls : InheritableAttr {
|
||||
let Spellings = [GNU<"disable_tail_calls">,
|
||||
CXX11<"clang", "disable_tail_calls">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod]>;
|
||||
let Documentation = [DisableTailCallsDocs];
|
||||
}
|
||||
|
||||
def NoAlias : InheritableAttr {
|
||||
let Spellings = [Declspec<"noalias">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [NoAliasDocs];
|
||||
}
|
||||
|
||||
def NoCommon : InheritableAttr {
|
||||
let Spellings = [GCC<"nocommon">];
|
||||
let Subjects = SubjectList<[Var]>;
|
||||
@ -960,6 +1012,15 @@ def ReturnsNonNull : InheritableAttr {
|
||||
let Documentation = [ReturnsNonNullDocs];
|
||||
}
|
||||
|
||||
// pass_object_size(N) indicates that the parameter should have
|
||||
// __builtin_object_size with Type=N evaluated on the parameter at the callsite.
|
||||
def PassObjectSize : InheritableParamAttr {
|
||||
let Spellings = [GNU<"pass_object_size">];
|
||||
let Args = [IntArgument<"Type">];
|
||||
let Subjects = SubjectList<[ParmVar]>;
|
||||
let Documentation = [PassObjectSizeDocs];
|
||||
}
|
||||
|
||||
// Nullability type attributes.
|
||||
def TypeNonNull : TypeAttr {
|
||||
let Spellings = [Keyword<"_Nonnull">];
|
||||
@ -1000,11 +1061,22 @@ def NoInstrumentFunction : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def NotTailCalled : InheritableAttr {
|
||||
let Spellings = [GNU<"not_tail_called">, CXX11<"clang", "not_tail_called">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [NotTailCalledDocs];
|
||||
}
|
||||
|
||||
def NoThrow : InheritableAttr {
|
||||
let Spellings = [GCC<"nothrow">, Declspec<"nothrow">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def NvWeak : IgnoredAttr {
|
||||
let Spellings = [GNU<"nv_weak">];
|
||||
let LangOpts = [CUDA];
|
||||
}
|
||||
|
||||
def ObjCBridge : InheritableAttr {
|
||||
let Spellings = [GNU<"objc_bridge">];
|
||||
let Subjects = SubjectList<[Record, TypedefName], ErrorDiag,
|
||||
@ -1024,8 +1096,8 @@ def ObjCBridgeRelated : InheritableAttr {
|
||||
let Spellings = [GNU<"objc_bridge_related">];
|
||||
let Subjects = SubjectList<[Record], ErrorDiag>;
|
||||
let Args = [IdentifierArgument<"RelatedClass">,
|
||||
IdentifierArgument<"ClassMethod">,
|
||||
IdentifierArgument<"InstanceMethod">];
|
||||
IdentifierArgument<"ClassMethod", 1>,
|
||||
IdentifierArgument<"InstanceMethod", 1>];
|
||||
let HasCustomParsing = 1;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
@ -1169,7 +1241,8 @@ def Ownership : InheritableAttr {
|
||||
}
|
||||
}];
|
||||
let Args = [IdentifierArgument<"Module">, VariadicUnsignedArgument<"Args">];
|
||||
let Subjects = SubjectList<[HasFunctionProto], WarnDiag, "ExpectedFunction">;
|
||||
let Subjects = SubjectList<[HasFunctionProto], WarnDiag,
|
||||
"ExpectedFunctionWithProtoType">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
@ -1280,9 +1353,41 @@ def Pascal : InheritableAttr {
|
||||
|
||||
def Target : InheritableAttr {
|
||||
let Spellings = [GCC<"target">];
|
||||
let Args = [StringArgument<"features">];
|
||||
let Args = [StringArgument<"featuresStr">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [TargetDocs];
|
||||
let AdditionalMembers = [{
|
||||
typedef std::pair<std::vector<std::string>, StringRef> ParsedTargetAttr;
|
||||
ParsedTargetAttr parse() const {
|
||||
ParsedTargetAttr Ret;
|
||||
SmallVector<StringRef, 1> AttrFeatures;
|
||||
getFeaturesStr().split(AttrFeatures, ",");
|
||||
|
||||
// Grab the various features and prepend a "+" to turn on the feature to
|
||||
// the backend and add them to our existing set of features.
|
||||
for (auto &Feature : AttrFeatures) {
|
||||
// Go ahead and trim whitespace rather than either erroring or
|
||||
// accepting it weirdly.
|
||||
Feature = Feature.trim();
|
||||
|
||||
// We don't support cpu tuning this way currently.
|
||||
// TODO: Support the fpmath option. It will require checking
|
||||
// overall feature validity for the function with the rest of the
|
||||
// attributes on the function.
|
||||
if (Feature.startswith("fpmath=") || Feature.startswith("tune="))
|
||||
continue;
|
||||
|
||||
// While we're here iterating check for a different target cpu.
|
||||
if (Feature.startswith("arch="))
|
||||
Ret.second = Feature.split("=").second.trim();
|
||||
else if (Feature.startswith("no-"))
|
||||
Ret.first.push_back("-" + Feature.split("-").second.str());
|
||||
else
|
||||
Ret.first.push_back("+" + Feature.str());
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def TransparentUnion : InheritableAttr {
|
||||
@ -1293,7 +1398,15 @@ def TransparentUnion : InheritableAttr {
|
||||
|
||||
def Unavailable : InheritableAttr {
|
||||
let Spellings = [GNU<"unavailable">];
|
||||
let Args = [StringArgument<"Message", 1>];
|
||||
let Args = [StringArgument<"Message", 1>,
|
||||
EnumArgument<"ImplicitReason", "ImplicitReason",
|
||||
["", "", "", ""],
|
||||
["IR_None",
|
||||
"IR_ARCForbiddenType",
|
||||
"IR_ForbiddenWeak",
|
||||
"IR_ARCForbiddenConversion",
|
||||
"IR_ARCInitReturnsUnrelated",
|
||||
"IR_ARCFieldWithOwnership"], 1, /*fake*/ 1>];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
@ -1486,8 +1599,8 @@ def Capability : InheritableAttr {
|
||||
let Spellings = [GNU<"capability">, CXX11<"clang", "capability">,
|
||||
GNU<"shared_capability">,
|
||||
CXX11<"clang", "shared_capability">];
|
||||
let Subjects = SubjectList<[Struct, TypedefName], ErrorDiag,
|
||||
"ExpectedStructOrTypedef">;
|
||||
let Subjects = SubjectList<[Record, TypedefName], ErrorDiag,
|
||||
"ExpectedStructOrUnionOrTypedef">;
|
||||
let Args = [StringArgument<"Name">];
|
||||
let Accessors = [Accessor<"isShared",
|
||||
[GNU<"shared_capability">,
|
||||
@ -1814,7 +1927,7 @@ def TypeTagForDatatype : InheritableAttr {
|
||||
|
||||
// Microsoft-related attributes
|
||||
|
||||
def MSNoVTable : InheritableAttr {
|
||||
def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
|
||||
let Spellings = [Declspec<"novtable">];
|
||||
let Subjects = SubjectList<[CXXRecord]>;
|
||||
let Documentation = [MSNoVTableDocs];
|
||||
@ -1970,8 +2083,8 @@ def LoopHint : Attr {
|
||||
["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
|
||||
"Unroll", "UnrollCount"]>,
|
||||
EnumArgument<"State", "LoopHintState",
|
||||
["default", "enable", "disable", "assume_safety"],
|
||||
["Default", "Enable", "Disable", "AssumeSafety"]>,
|
||||
["enable", "disable", "numeric", "assume_safety", "full"],
|
||||
["Enable", "Disable", "Numeric", "AssumeSafety", "Full"]>,
|
||||
ExprArgument<"Value">];
|
||||
|
||||
let AdditionalMembers = [{
|
||||
@ -1991,17 +2104,15 @@ def LoopHint : Attr {
|
||||
unsigned SpellingIndex = getSpellingListIndex();
|
||||
// For "#pragma unroll" and "#pragma nounroll" the string "unroll" or
|
||||
// "nounroll" is already emitted as the pragma name.
|
||||
if (SpellingIndex == Pragma_nounroll) {
|
||||
OS << "\n";
|
||||
if (SpellingIndex == Pragma_nounroll)
|
||||
return;
|
||||
}
|
||||
else if (SpellingIndex == Pragma_unroll) {
|
||||
OS << getValueString(Policy) << "\n";
|
||||
OS << getValueString(Policy);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
|
||||
OS << getOptionName(option) << getValueString(Policy) << "\n";
|
||||
OS << getOptionName(option) << getValueString(Policy);
|
||||
}
|
||||
|
||||
// Return a string containing the loop hint argument including the
|
||||
@ -2010,13 +2121,12 @@ def LoopHint : Attr {
|
||||
std::string ValueName;
|
||||
llvm::raw_string_ostream OS(ValueName);
|
||||
OS << "(";
|
||||
if (option == VectorizeWidth || option == InterleaveCount ||
|
||||
option == UnrollCount)
|
||||
if (state == Numeric)
|
||||
value->printPretty(OS, nullptr, Policy);
|
||||
else if (state == Default)
|
||||
return "";
|
||||
else if (state == Enable)
|
||||
OS << (option == Unroll ? "full" : "enable");
|
||||
OS << "enable";
|
||||
else if (state == Full)
|
||||
OS << "full";
|
||||
else if (state == AssumeSafety)
|
||||
OS << "assume_safety";
|
||||
else
|
||||
@ -2031,7 +2141,7 @@ def LoopHint : Attr {
|
||||
if (SpellingIndex == Pragma_nounroll)
|
||||
return "#pragma nounroll";
|
||||
else if (SpellingIndex == Pragma_unroll)
|
||||
return "#pragma unroll" + getValueString(Policy);
|
||||
return "#pragma unroll" + (option == UnrollCount ? getValueString(Policy) : "");
|
||||
|
||||
assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
|
||||
return getOptionName(option) + getValueString(Policy);
|
||||
@ -2054,3 +2164,9 @@ def OMPThreadPrivateDecl : InheritableAttr {
|
||||
let SemaHandler = 0;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def InternalLinkage : InheritableAttr {
|
||||
let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
|
||||
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
|
||||
let Documentation = [InternalLinkageDocs];
|
||||
}
|
||||
|
@ -181,9 +181,9 @@ to enforce the provided alignment assumption.
|
||||
def EnableIfDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
.. Note:: Some features of this attribute are experimental. The meaning of
|
||||
multiple enable_if attributes on a single declaration is subject to change in
|
||||
a future version of clang. Also, the ABI is not standardized and the name
|
||||
.. Note:: Some features of this attribute are experimental. The meaning of
|
||||
multiple enable_if attributes on a single declaration is subject to change in
|
||||
a future version of clang. Also, the ABI is not standardized and the name
|
||||
mangling may change in future versions. To avoid that, use asm labels.
|
||||
|
||||
The ``enable_if`` attribute can be placed on function declarations to control
|
||||
@ -263,6 +263,103 @@ Query for this feature with ``__has_attribute(enable_if)``.
|
||||
}];
|
||||
}
|
||||
|
||||
def PassObjectSizeDocs : Documentation {
|
||||
let Category = DocCatVariable; // Technically it's a parameter doc, but eh.
|
||||
let Content = [{
|
||||
.. Note:: The mangling of functions with parameters that are annotated with
|
||||
``pass_object_size`` is subject to change. You can get around this by
|
||||
using ``__asm__("foo")`` to explicitly name your functions, thus preserving
|
||||
your ABI; also, non-overloadable C functions with ``pass_object_size`` are
|
||||
not mangled.
|
||||
|
||||
The ``pass_object_size(Type)`` attribute can be placed on function parameters to
|
||||
instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite
|
||||
of said function, and implicitly pass the result of this call in as an invisible
|
||||
argument of type ``size_t`` directly after the parameter annotated with
|
||||
``pass_object_size``. Clang will also replace any calls to
|
||||
``__builtin_object_size(param, Type)`` in the function by said implicit
|
||||
parameter.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int bzero1(char *const p __attribute__((pass_object_size(0))))
|
||||
__attribute__((noinline)) {
|
||||
int i = 0;
|
||||
for (/**/; i < (int)__builtin_object_size(p, 0); ++i) {
|
||||
p[i] = 0;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int main() {
|
||||
char chars[100];
|
||||
int n = bzero1(&chars[0]);
|
||||
assert(n == sizeof(chars));
|
||||
return 0;
|
||||
}
|
||||
|
||||
If successfully evaluating ``__builtin_object_size(param, Type)`` at the
|
||||
callsite is not possible, then the "failed" value is passed in. So, using the
|
||||
definition of ``bzero1`` from above, the following code would exit cleanly:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int main2(int argc, char *argv[]) {
|
||||
int n = bzero1(argv);
|
||||
assert(n == -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
``pass_object_size`` plays a part in overload resolution. If two overload
|
||||
candidates are otherwise equally good, then the overload with one or more
|
||||
parameters with ``pass_object_size`` is preferred. This implies that the choice
|
||||
between two identical overloads both with ``pass_object_size`` on one or more
|
||||
parameters will always be ambiguous; for this reason, having two such overloads
|
||||
is illegal. For example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#define PS(N) __attribute__((pass_object_size(N)))
|
||||
// OK
|
||||
void Foo(char *a, char *b); // Overload A
|
||||
// OK -- overload A has no parameters with pass_object_size.
|
||||
void Foo(char *a PS(0), char *b PS(0)); // Overload B
|
||||
// Error -- Same signature (sans pass_object_size) as overload B, and both
|
||||
// overloads have one or more parameters with the pass_object_size attribute.
|
||||
void Foo(void *a PS(0), void *b);
|
||||
|
||||
// OK
|
||||
void Bar(void *a PS(0)); // Overload C
|
||||
// OK
|
||||
void Bar(char *c PS(1)); // Overload D
|
||||
|
||||
void main() {
|
||||
char known[10], *unknown;
|
||||
Foo(unknown, unknown); // Calls overload B
|
||||
Foo(known, unknown); // Calls overload B
|
||||
Foo(unknown, known); // Calls overload B
|
||||
Foo(known, known); // Calls overload B
|
||||
|
||||
Bar(known); // Calls overload D
|
||||
Bar(unknown); // Calls overload D
|
||||
}
|
||||
|
||||
Currently, ``pass_object_size`` is a bit restricted in terms of its usage:
|
||||
|
||||
* Only one use of ``pass_object_size`` is allowed per parameter.
|
||||
|
||||
* It is an error to take the address of a function with ``pass_object_size`` on
|
||||
any of its parameters. If you wish to do this, you can create an overload
|
||||
without ``pass_object_size`` on any parameters.
|
||||
|
||||
* It is an error to apply the ``pass_object_size`` attribute to parameters that
|
||||
are not pointers. Additionally, any parameter that ``pass_object_size`` is
|
||||
applied to must be marked ``const`` at its function's definition.
|
||||
}];
|
||||
}
|
||||
|
||||
def OverloadableDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
@ -580,6 +677,14 @@ are:
|
||||
Apple's Mac OS X operating system. The minimum deployment target is
|
||||
specified by the ``-mmacosx-version-min=*version*`` command-line argument.
|
||||
|
||||
``tvos``
|
||||
Apple's tvOS operating system. The minimum deployment target is specified by
|
||||
the ``-mtvos-version-min=*version*`` command-line argument.
|
||||
|
||||
``watchos``
|
||||
Apple's watchOS operating system. The minimum deployment target is specified by
|
||||
the ``-mwatchos-version-min=*version*`` command-line argument.
|
||||
|
||||
A declaration can be used even when deploying back to a platform version prior
|
||||
to when the declaration was introduced. When this happens, the declaration is
|
||||
`weakly linked
|
||||
@ -706,6 +811,46 @@ The semantics are as follows:
|
||||
}];
|
||||
}
|
||||
|
||||
def MipsInterruptDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on
|
||||
MIPS targets. This attribute may be attached to a function definition and instructs
|
||||
the backend to generate appropriate function entry/exit code so that it can be used
|
||||
directly as an interrupt service routine.
|
||||
|
||||
By default, the compiler will produce a function prologue and epilogue suitable for
|
||||
an interrupt service routine that handles an External Interrupt Controller (eic)
|
||||
generated interrupt. This behaviour can be explicitly requested with the "eic"
|
||||
argument.
|
||||
|
||||
Otherwise, for use with vectored interrupt mode, the argument passed should be
|
||||
of the form "vector=LEVEL" where LEVEL is one of the following values:
|
||||
"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will
|
||||
then set the interrupt mask to the corresponding level which will mask all
|
||||
interrupts up to and including the argument.
|
||||
|
||||
The semantics are as follows:
|
||||
|
||||
- The prologue is modified so that the Exception Program Counter (EPC) and
|
||||
Status coprocessor registers are saved to the stack. The interrupt mask is
|
||||
set so that the function can only be interrupted by a higher priority
|
||||
interrupt. The epilogue will restore the previous values of EPC and Status.
|
||||
|
||||
- The prologue and epilogue are modified to save and restore all non-kernel
|
||||
registers as necessary.
|
||||
|
||||
- The FPU is disabled in the prologue, as the floating pointer registers are not
|
||||
spilled to the stack.
|
||||
|
||||
- The function return sequence is changed to use an exception return instruction.
|
||||
|
||||
- The parameter sets the interrupt mask for the function corresponding to the
|
||||
interrupt level specified. If no mask is specified the interrupt mask
|
||||
defaults to "eic".
|
||||
}];
|
||||
}
|
||||
|
||||
def TargetDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
@ -1328,7 +1473,7 @@ def MSNoVTableDocs : Documentation {
|
||||
let Content = [{
|
||||
This attribute can be added to a class declaration or definition to signal to
|
||||
the compiler that constructors and destructors will not reference the virtual
|
||||
function table.
|
||||
function table. It is only supported when using the Microsoft C++ ABI.
|
||||
}];
|
||||
}
|
||||
|
||||
@ -1371,7 +1516,9 @@ Loop unrolling optimization hints can be specified with ``#pragma unroll`` and
|
||||
do-while, or c++11 range-based for loop.
|
||||
|
||||
Specifying ``#pragma unroll`` without a parameter directs the loop unroller to
|
||||
attempt to fully unroll the loop if the trip count is known at compile time:
|
||||
attempt to fully unroll the loop if the trip count is known at compile time and
|
||||
attempt to partially unroll the loop if the trip count is not known at compile
|
||||
time:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
@ -1439,7 +1586,6 @@ More details can be found in the OpenCL C language Spec v2.0, Section 6.5.
|
||||
|
||||
def OpenCLAddressSpaceGenericDocs : Documentation {
|
||||
let Category = DocOpenCLAddressSpaces;
|
||||
let Heading = "__generic(generic)";
|
||||
let Content = [{
|
||||
The generic address space attribute is only available with OpenCL v2.0 and later.
|
||||
It can be used with pointer types. Variables in global and local scope and
|
||||
@ -1452,7 +1598,6 @@ spaces.
|
||||
|
||||
def OpenCLAddressSpaceConstantDocs : Documentation {
|
||||
let Category = DocOpenCLAddressSpaces;
|
||||
let Heading = "__constant(constant)";
|
||||
let Content = [{
|
||||
The constant address space attribute signals that an object is located in
|
||||
a constant (non-modifiable) memory region. It is available to all work items.
|
||||
@ -1464,7 +1609,6 @@ have an initializer.
|
||||
|
||||
def OpenCLAddressSpaceGlobalDocs : Documentation {
|
||||
let Category = DocOpenCLAddressSpaces;
|
||||
let Heading = "__global(global)";
|
||||
let Content = [{
|
||||
The global address space attribute specifies that an object is allocated in
|
||||
global memory, which is accessible by all work items. The content stored in this
|
||||
@ -1477,7 +1621,6 @@ scope) variables and static local variable as well.
|
||||
|
||||
def OpenCLAddressSpaceLocalDocs : Documentation {
|
||||
let Category = DocOpenCLAddressSpaces;
|
||||
let Heading = "__local(local)";
|
||||
let Content = [{
|
||||
The local address space specifies that an object is allocated in the local (work
|
||||
group) memory area, which is accessible to all work items in the same work
|
||||
@ -1490,7 +1633,6 @@ space are allowed. Local address space variables cannot have an initializer.
|
||||
|
||||
def OpenCLAddressSpacePrivateDocs : Documentation {
|
||||
let Category = DocOpenCLAddressSpaces;
|
||||
let Heading = "__private(private)";
|
||||
let Content = [{
|
||||
The private address space specifies that an object is allocated in the private
|
||||
(work item) memory. Other work items cannot access the same memory area and its
|
||||
@ -1534,7 +1676,6 @@ In Objective-C, there is an alternate spelling for the nullability qualifiers th
|
||||
|
||||
def TypeNonNullDocs : Documentation {
|
||||
let Category = NullabilityDocs;
|
||||
let Heading = "_Nonnull";
|
||||
let Content = [{
|
||||
The ``_Nonnull`` nullability qualifier indicates that null is not a meaningful value for a value of the ``_Nonnull`` pointer type. For example, given a declaration such as:
|
||||
|
||||
@ -1548,7 +1689,6 @@ a caller of ``fetch`` should not provide a null value, and the compiler will pro
|
||||
|
||||
def TypeNullableDocs : Documentation {
|
||||
let Category = NullabilityDocs;
|
||||
let Heading = "_Nullable";
|
||||
let Content = [{
|
||||
The ``_Nullable`` nullability qualifier indicates that a value of the ``_Nullable`` pointer type can be null. For example, given:
|
||||
|
||||
@ -1562,7 +1702,6 @@ a caller of ``fetch_or_zero`` can provide null.
|
||||
|
||||
def TypeNullUnspecifiedDocs : Documentation {
|
||||
let Category = NullabilityDocs;
|
||||
let Heading = "_Null_unspecified";
|
||||
let Content = [{
|
||||
The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_Nonnull`` nor ``_Nullable`` qualifiers make sense for a particular pointer type. It is used primarily to indicate that the role of null with specific pointers in a nullability-annotated header is unclear, e.g., due to overly-complex implementations or historical factors with a long-lived API.
|
||||
}];
|
||||
@ -1570,7 +1709,6 @@ The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_No
|
||||
|
||||
def NonNullDocs : Documentation {
|
||||
let Category = NullabilityDocs;
|
||||
let Heading = "nonnull";
|
||||
let Content = [{
|
||||
The ``nonnull`` attribute indicates that some function parameters must not be null, and can be used in several different ways. It's original usage (`from GCC <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes>`_) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. For example:
|
||||
|
||||
@ -1600,7 +1738,6 @@ Note that the ``nonnull`` attribute indicates that passing null to a non-null pa
|
||||
|
||||
def ReturnsNonNullDocs : Documentation {
|
||||
let Category = NullabilityDocs;
|
||||
let Heading = "returns_nonnull";
|
||||
let Content = [{
|
||||
The ``returns_nonnull`` attribute indicates that a particular function (or Objective-C method) always returns a non-null pointer. For example, a particular system ``malloc`` might be defined to terminate a process when memory is not available rather than returning a null pointer:
|
||||
|
||||
@ -1611,3 +1748,114 @@ The ``returns_nonnull`` attribute indicates that a particular function (or Objec
|
||||
The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable
|
||||
}];
|
||||
}
|
||||
|
||||
def NoAliasDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``noalias`` attribute indicates that the only memory accesses inside
|
||||
function are loads and stores from objects pointed to by its pointer-typed
|
||||
arguments, with arbitrary offsets.
|
||||
}];
|
||||
}
|
||||
|
||||
def NotTailCalledDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``.
|
||||
|
||||
For example, it prevents tail-call optimization in the following case:
|
||||
|
||||
.. code-block: c
|
||||
|
||||
int __attribute__((not_tail_called)) foo1(int);
|
||||
|
||||
int foo2(int a) {
|
||||
return foo1(a); // No tail-call optimization on direct calls.
|
||||
}
|
||||
|
||||
However, it doesn't prevent tail-call optimization in this case:
|
||||
|
||||
.. code-block: c
|
||||
|
||||
int __attribute__((not_tail_called)) foo1(int);
|
||||
|
||||
int foo2(int a) {
|
||||
int (*fn)(int) = &foo1;
|
||||
|
||||
// not_tail_called has no effect on an indirect call even if the call can be
|
||||
// resolved at compile time.
|
||||
return (*fn)(a);
|
||||
}
|
||||
|
||||
Marking virtual functions as ``not_tail_called`` is an error:
|
||||
|
||||
.. code-block: c++
|
||||
|
||||
class Base {
|
||||
public:
|
||||
// not_tail_called on a virtual function is an error.
|
||||
[[clang::not_tail_called]] virtual int foo1();
|
||||
|
||||
virtual int foo2();
|
||||
|
||||
// Non-virtual functions can be marked ``not_tail_called``.
|
||||
[[clang::not_tail_called]] int foo3();
|
||||
};
|
||||
|
||||
class Derived1 : public Base {
|
||||
public:
|
||||
int foo1() override;
|
||||
|
||||
// not_tail_called on a virtual function is an error.
|
||||
[[clang::not_tail_called]] int foo2() override;
|
||||
};
|
||||
}];
|
||||
}
|
||||
|
||||
def InternalLinkageDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``internal_linkage`` attribute changes the linkage type of the declaration to internal.
|
||||
This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition,
|
||||
this attribute affects all methods and static data members of that class.
|
||||
This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables.
|
||||
}];
|
||||
}
|
||||
|
||||
def DisableTailCallsDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int callee(int);
|
||||
|
||||
int foo(int a) __attribute__((disable_tail_calls)) {
|
||||
return callee(a); // This call is not tail-call optimized.
|
||||
}
|
||||
|
||||
Marking virtual functions as ``disable_tail_calls`` is legal.
|
||||
|
||||
.. code-block: c++
|
||||
|
||||
int callee(int);
|
||||
|
||||
class Base {
|
||||
public:
|
||||
[[clang::disable_tail_calls]] virtual int foo1() {
|
||||
return callee(); // This call is not tail-call optimized.
|
||||
}
|
||||
};
|
||||
|
||||
class Derived1 : public Base {
|
||||
public:
|
||||
int foo1() override {
|
||||
return callee(); // This call is tail-call optimized.
|
||||
}
|
||||
};
|
||||
|
||||
}];
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define LLVM_CLANG_BASIC_ATTRIBUTES_H
|
||||
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -31,7 +31,7 @@ enum class AttrSyntax {
|
||||
/// \brief Return the version number associated with the attribute if we
|
||||
/// recognize and implement the attribute specified by the given information.
|
||||
int hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
|
||||
const IdentifierInfo *Attr, const llvm::Triple &T,
|
||||
const IdentifierInfo *Attr, const TargetInfo &Target,
|
||||
const LangOptions &LangOpts);
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -357,25 +357,25 @@ BUILTIN(__builtin_ctanhf, "XfXf", "Fnc")
|
||||
BUILTIN(__builtin_ctanhl, "XLdXLd", "Fnc")
|
||||
|
||||
// FP Comparisons.
|
||||
BUILTIN(__builtin_isgreater , "i.", "nc")
|
||||
BUILTIN(__builtin_isgreaterequal, "i.", "nc")
|
||||
BUILTIN(__builtin_isless , "i.", "nc")
|
||||
BUILTIN(__builtin_islessequal , "i.", "nc")
|
||||
BUILTIN(__builtin_islessgreater , "i.", "nc")
|
||||
BUILTIN(__builtin_isunordered , "i.", "nc")
|
||||
BUILTIN(__builtin_isgreater , "i.", "Fnc")
|
||||
BUILTIN(__builtin_isgreaterequal, "i.", "Fnc")
|
||||
BUILTIN(__builtin_isless , "i.", "Fnc")
|
||||
BUILTIN(__builtin_islessequal , "i.", "Fnc")
|
||||
BUILTIN(__builtin_islessgreater , "i.", "Fnc")
|
||||
BUILTIN(__builtin_isunordered , "i.", "Fnc")
|
||||
|
||||
// Unary FP classification
|
||||
BUILTIN(__builtin_fpclassify, "iiiii.", "nc")
|
||||
BUILTIN(__builtin_isfinite, "i.", "nc")
|
||||
BUILTIN(__builtin_isinf, "i.", "nc")
|
||||
BUILTIN(__builtin_isinf_sign, "i.", "nc")
|
||||
BUILTIN(__builtin_isnan, "i.", "nc")
|
||||
BUILTIN(__builtin_isnormal, "i.", "nc")
|
||||
BUILTIN(__builtin_fpclassify, "iiiii.", "Fnc")
|
||||
BUILTIN(__builtin_isfinite, "i.", "Fnc")
|
||||
BUILTIN(__builtin_isinf, "i.", "Fnc")
|
||||
BUILTIN(__builtin_isinf_sign, "i.", "Fnc")
|
||||
BUILTIN(__builtin_isnan, "i.", "Fnc")
|
||||
BUILTIN(__builtin_isnormal, "i.", "Fnc")
|
||||
|
||||
// FP signbit builtins
|
||||
BUILTIN(__builtin_signbit, "id", "nc")
|
||||
BUILTIN(__builtin_signbitf, "if", "nc")
|
||||
BUILTIN(__builtin_signbitl, "iLd", "nc")
|
||||
BUILTIN(__builtin_signbit, "i.", "Fnc")
|
||||
BUILTIN(__builtin_signbitf, "if", "Fnc")
|
||||
BUILTIN(__builtin_signbitl, "iLd", "Fnc")
|
||||
|
||||
// Builtins for arithmetic.
|
||||
BUILTIN(__builtin_clzs , "iUs" , "nc")
|
||||
@ -388,9 +388,9 @@ BUILTIN(__builtin_ctz , "iUi" , "nc")
|
||||
BUILTIN(__builtin_ctzl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_ctzll, "iULLi", "nc")
|
||||
// TODO: int ctzimax(uintmax_t)
|
||||
BUILTIN(__builtin_ffs , "ii" , "nc")
|
||||
BUILTIN(__builtin_ffsl , "iLi" , "nc")
|
||||
BUILTIN(__builtin_ffsll, "iLLi", "nc")
|
||||
BUILTIN(__builtin_ffs , "ii" , "Fnc")
|
||||
BUILTIN(__builtin_ffsl , "iLi" , "Fnc")
|
||||
BUILTIN(__builtin_ffsll, "iLLi", "Fnc")
|
||||
BUILTIN(__builtin_parity , "iUi" , "nc")
|
||||
BUILTIN(__builtin_parityl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_parityll, "iULLi", "nc")
|
||||
@ -414,7 +414,7 @@ BUILTIN(__builtin_va_end, "vA", "n")
|
||||
BUILTIN(__builtin_va_copy, "vAA", "n")
|
||||
BUILTIN(__builtin_stdarg_start, "vA.", "n")
|
||||
BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc")
|
||||
BUILTIN(__builtin_bcmp, "iv*v*z", "n")
|
||||
BUILTIN(__builtin_bcmp, "iv*v*z", "Fn")
|
||||
BUILTIN(__builtin_bcopy, "vv*v*z", "n")
|
||||
BUILTIN(__builtin_bzero, "vv*z", "nF")
|
||||
BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:")
|
||||
@ -489,6 +489,7 @@ BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:")
|
||||
BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:")
|
||||
BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:")
|
||||
|
||||
BUILTIN(__builtin_unpredictable, "LiLi" , "nc")
|
||||
BUILTIN(__builtin_expect, "LiLiLi" , "nc")
|
||||
BUILTIN(__builtin_prefetch, "vvC*.", "nc")
|
||||
BUILTIN(__builtin_readcyclecounter, "ULLi", "n")
|
||||
@ -497,7 +498,7 @@ BUILTIN(__builtin_debugtrap, "v", "n")
|
||||
BUILTIN(__builtin_unreachable, "v", "nr")
|
||||
BUILTIN(__builtin_shufflevector, "v." , "nc")
|
||||
BUILTIN(__builtin_convertvector, "v." , "nct")
|
||||
BUILTIN(__builtin_alloca, "v*z" , "n")
|
||||
BUILTIN(__builtin_alloca, "v*z" , "Fn")
|
||||
BUILTIN(__builtin_call_with_static_chain, "v.", "nt")
|
||||
|
||||
// "Overloaded" Atomic operator builtins. These are overloaded to support data
|
||||
@ -1216,6 +1217,9 @@ BUILTIN(__builtin_subcl, "ULiULiCULiCULiCULi*", "n")
|
||||
BUILTIN(__builtin_subcll, "ULLiULLiCULLiCULLiCULLi*", "n")
|
||||
|
||||
// Checked Arithmetic Builtins for Security.
|
||||
BUILTIN(__builtin_add_overflow, "v.", "nt")
|
||||
BUILTIN(__builtin_sub_overflow, "v.", "nt")
|
||||
BUILTIN(__builtin_mul_overflow, "v.", "nt")
|
||||
BUILTIN(__builtin_uadd_overflow, "bUiCUiCUi*", "n")
|
||||
BUILTIN(__builtin_uaddl_overflow, "bULiCULiCULi*", "n")
|
||||
BUILTIN(__builtin_uaddll_overflow, "bULLiCULLiCULLi*", "n")
|
||||
@ -1244,6 +1248,10 @@ BUILTIN(__builtin_operator_delete, "vv*", "n")
|
||||
BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn")
|
||||
BUILTIN(__builtin___get_unsafe_stack_ptr, "v*", "Fn")
|
||||
|
||||
// Nontemporal loads/stores builtins
|
||||
BUILTIN(__builtin_nontemporal_store, "v.", "t")
|
||||
BUILTIN(__builtin_nontemporal_load, "v.", "t")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LIBBUILTIN
|
||||
#undef LANGBUILTIN
|
||||
|
@ -16,7 +16,7 @@
|
||||
#ifndef LLVM_CLANG_BASIC_BUILTINS_H
|
||||
#define LLVM_CLANG_BASIC_BUILTINS_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include <cstring>
|
||||
|
||||
// VC++ defines 'alloca' as an object-like macro, which interferes with our
|
||||
@ -24,22 +24,22 @@
|
||||
#undef alloca
|
||||
|
||||
namespace clang {
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
class LangOptions;
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
class LangOptions;
|
||||
|
||||
enum LanguageID {
|
||||
GNU_LANG = 0x1, // builtin requires GNU mode.
|
||||
C_LANG = 0x2, // builtin for c only.
|
||||
CXX_LANG = 0x4, // builtin for cplusplus only.
|
||||
OBJC_LANG = 0x8, // builtin for objective-c and objective-c++
|
||||
MS_LANG = 0x10, // builtin requires MS mode.
|
||||
ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages.
|
||||
ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode.
|
||||
ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode.
|
||||
};
|
||||
enum LanguageID {
|
||||
GNU_LANG = 0x1, // builtin requires GNU mode.
|
||||
C_LANG = 0x2, // builtin for c only.
|
||||
CXX_LANG = 0x4, // builtin for cplusplus only.
|
||||
OBJC_LANG = 0x8, // builtin for objective-c and objective-c++
|
||||
MS_LANG = 0x10, // builtin requires MS mode.
|
||||
ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages.
|
||||
ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode.
|
||||
ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode.
|
||||
};
|
||||
|
||||
namespace Builtin {
|
||||
enum ID {
|
||||
@ -51,112 +51,114 @@ enum ID {
|
||||
|
||||
struct Info {
|
||||
const char *Name, *Type, *Attributes, *HeaderName;
|
||||
LanguageID builtin_lang;
|
||||
|
||||
bool operator==(const Info &RHS) const {
|
||||
return !strcmp(Name, RHS.Name) &&
|
||||
!strcmp(Type, RHS.Type) &&
|
||||
!strcmp(Attributes, RHS.Attributes);
|
||||
}
|
||||
bool operator!=(const Info &RHS) const { return !(*this == RHS); }
|
||||
LanguageID Langs;
|
||||
const char *Features;
|
||||
};
|
||||
|
||||
/// \brief Holds information about both target-independent and
|
||||
/// target-specific builtins, allowing easy queries by clients.
|
||||
///
|
||||
/// Builtins from an optional auxiliary target are stored in
|
||||
/// AuxTSRecords. Their IDs are shifted up by TSRecords.size() and need to
|
||||
/// be translated back with getAuxBuiltinID() before use.
|
||||
class Context {
|
||||
const Info *TSRecords;
|
||||
unsigned NumTSRecords;
|
||||
llvm::ArrayRef<Info> TSRecords;
|
||||
llvm::ArrayRef<Info> AuxTSRecords;
|
||||
|
||||
public:
|
||||
Context();
|
||||
Context() {}
|
||||
|
||||
/// \brief Perform target-specific initialization
|
||||
void InitializeTarget(const TargetInfo &Target);
|
||||
|
||||
/// \param AuxTarget Target info to incorporate builtins from. May be nullptr.
|
||||
void InitializeTarget(const TargetInfo &Target, const TargetInfo *AuxTarget);
|
||||
|
||||
/// \brief Mark the identifiers for all the builtins with their
|
||||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
|
||||
/// such.
|
||||
void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts);
|
||||
|
||||
/// \brief Populate the vector with the names of all of the builtins.
|
||||
void GetBuiltinNames(SmallVectorImpl<const char *> &Names);
|
||||
void initializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts);
|
||||
|
||||
/// \brief Return the identifier name for the specified builtin,
|
||||
/// e.g. "__builtin_abs".
|
||||
const char *GetName(unsigned ID) const {
|
||||
return GetRecord(ID).Name;
|
||||
const char *getName(unsigned ID) const {
|
||||
return getRecord(ID).Name;
|
||||
}
|
||||
|
||||
/// \brief Get the type descriptor string for the specified builtin.
|
||||
const char *GetTypeString(unsigned ID) const {
|
||||
return GetRecord(ID).Type;
|
||||
const char *getTypeString(unsigned ID) const {
|
||||
return getRecord(ID).Type;
|
||||
}
|
||||
|
||||
/// \brief Return true if this function is a target-specific builtin
|
||||
bool isTSBuiltin(unsigned ID) const {
|
||||
return ID >= Builtin::FirstTSBuiltin;
|
||||
}
|
||||
|
||||
/// \brief Return true if this function has no side effects and doesn't
|
||||
/// read memory.
|
||||
bool isConst(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'c') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'c') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Return true if we know this builtin never throws an exception.
|
||||
bool isNoThrow(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'n') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'n') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Return true if we know this builtin never returns.
|
||||
bool isNoReturn(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'r') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'r') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Return true if we know this builtin can return twice.
|
||||
bool isReturnsTwice(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'j') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'j') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this builtin does not perform the side-effects
|
||||
/// of its arguments.
|
||||
bool isUnevaluated(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'u') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'u') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Return true if this is a builtin for a libc/libm function,
|
||||
/// with a "__builtin_" prefix (e.g. __builtin_abs).
|
||||
bool isLibFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'F') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'F') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this builtin is a predefined libc/libm
|
||||
/// function, such as "malloc", where we know the signature a
|
||||
/// priori.
|
||||
bool isPredefinedLibFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'f') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'f') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this builtin is a predefined compiler-rt/libgcc
|
||||
/// function, such as "__clear_cache", where we know the signature a
|
||||
/// priori.
|
||||
bool isPredefinedRuntimeFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'i') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'i') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this builtin has custom typechecking.
|
||||
bool hasCustomTypechecking(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 't') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 't') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this builtin has a result or any arguments which
|
||||
/// are pointer types.
|
||||
bool hasPtrArgsOrResult(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Type, '*') != nullptr;
|
||||
return strchr(getRecord(ID).Type, '*') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Completely forget that the given ID was ever considered a builtin,
|
||||
/// e.g., because the user provided a conflicting signature.
|
||||
void ForgetBuiltin(unsigned ID, IdentifierTable &Table);
|
||||
void forgetBuiltin(unsigned ID, IdentifierTable &Table);
|
||||
|
||||
/// \brief If this is a library function that comes from a specific
|
||||
/// header, retrieve that header name.
|
||||
const char *getHeaderName(unsigned ID) const {
|
||||
return GetRecord(ID).HeaderName;
|
||||
return getRecord(ID).HeaderName;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this builtin is like printf in its
|
||||
@ -174,14 +176,27 @@ class Context {
|
||||
///
|
||||
/// Such functions can be const when the MathErrno lang option is disabled.
|
||||
bool isConstWithoutErrno(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'e') != nullptr;
|
||||
return strchr(getRecord(ID).Attributes, 'e') != nullptr;
|
||||
}
|
||||
|
||||
const char *getRequiredFeatures(unsigned ID) const {
|
||||
return getRecord(ID).Features;
|
||||
}
|
||||
|
||||
/// \brief Return true if builtin ID belongs to AuxTarget.
|
||||
bool isAuxBuiltinID(unsigned ID) const {
|
||||
return ID >= (Builtin::FirstTSBuiltin + TSRecords.size());
|
||||
}
|
||||
|
||||
/// Return real buitin ID (i.e. ID it would have furing compilation
|
||||
/// for AuxTarget).
|
||||
unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSRecords.size(); }
|
||||
|
||||
private:
|
||||
const Info &GetRecord(unsigned ID) const;
|
||||
const Info &getRecord(unsigned ID) const;
|
||||
|
||||
/// \brief Is this builtin supported according to the given language options?
|
||||
bool BuiltinIsSupported(const Builtin::Info &BuiltinInfo,
|
||||
bool builtinIsSupported(const Builtin::Info &BuiltinInfo,
|
||||
const LangOptions &LangOpts);
|
||||
|
||||
/// \brief Helper function for isPrintfLike and isScanfLike.
|
||||
@ -190,5 +205,12 @@ class Context {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// \brief Kinds of BuiltinTemplateDecl.
|
||||
enum BuiltinTemplateKind : int {
|
||||
/// \brief This names the __make_integer_seq BuiltinTemplateDecl.
|
||||
BTK__make_integer_seq
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user