Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):
https://llvm.org/svn/llvm-project/cfe/branches/release_34@197841
This commit is contained in:
parent
6a0372513e
commit
bfef399519
1
.clang-format
Normal file
1
.clang-format
Normal file
@ -0,0 +1 @@
|
|||||||
|
BasedOnStyle: LLVM
|
154
CMakeLists.txt
154
CMakeLists.txt
@ -19,12 +19,14 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
if (EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
# Looking for bin/Debug/llvm-tblgen is a complete hack. How can we get
|
set (PATH_TO_LLVM_CONFIG "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
|
elseif (EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
|
# Looking for bin/Debug/llvm-config is a complete hack. How can we get
|
||||||
# around this?
|
# around this?
|
||||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
set (PATH_TO_LLVM_CONFIG "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
else()
|
||||||
endif()
|
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
|
||||||
@ -32,6 +34,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
|||||||
get_filename_component(PATH_TO_LLVM_BUILD ${CLANG_PATH_TO_LLVM_BUILD}
|
get_filename_component(PATH_TO_LLVM_BUILD ${CLANG_PATH_TO_LLVM_BUILD}
|
||||||
ABSOLUTE)
|
ABSOLUTE)
|
||||||
|
|
||||||
|
option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install' target." OFF)
|
||||||
|
|
||||||
include(AddLLVM)
|
include(AddLLVM)
|
||||||
include(TableGen)
|
include(TableGen)
|
||||||
include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
|
include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
|
||||||
@ -46,12 +50,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
|||||||
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
|
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
|
||||||
link_directories("${PATH_TO_LLVM_BUILD}/lib")
|
link_directories("${PATH_TO_LLVM_BUILD}/lib")
|
||||||
|
|
||||||
if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
exec_program("${PATH_TO_LLVM_CONFIG} --bindir" OUTPUT_VARIABLE LLVM_BINARY_DIR)
|
||||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
set(LLVM_TABLEGEN_EXE "${LLVM_BINARY_DIR}/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
else()
|
|
||||||
# FIXME: This is an utter hack.
|
|
||||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Define the default arguments to use with 'lit', and an option for the user
|
# Define the default arguments to use with 'lit', and an option for the user
|
||||||
# to override.
|
# to override.
|
||||||
@ -90,6 +90,16 @@ if( CLANG_VENDOR )
|
|||||||
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
|
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(CLANG_REPOSITORY_STRING "" CACHE STRING
|
||||||
|
"Vendor-specific text for showing the repository the source is taken from.")
|
||||||
|
|
||||||
|
if(CLANG_REPOSITORY_STRING)
|
||||||
|
add_definitions(-DCLANG_REPOSITORY_STRING="${CLANG_REPOSITORY_STRING}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CLANG_VENDOR_UTI "org.llvm.clang" CACHE STRING
|
||||||
|
"Vendor-specific uti.")
|
||||||
|
|
||||||
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
@ -151,7 +161,7 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
|
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
@ -189,6 +199,41 @@ function(clang_tablegen)
|
|||||||
endif()
|
endif()
|
||||||
endfunction(clang_tablegen)
|
endfunction(clang_tablegen)
|
||||||
|
|
||||||
|
# FIXME: Generalize and move to llvm.
|
||||||
|
function(add_clang_symbol_exports target_name export_file)
|
||||||
|
# Makefile.rules contains special cases for different platforms.
|
||||||
|
# We restrict ourselves to Darwin for the time being.
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
|
add_custom_command(OUTPUT symbol.exports
|
||||||
|
COMMAND sed -e "s/^/_/" < ${export_file} > symbol.exports
|
||||||
|
DEPENDS ${export_file}
|
||||||
|
VERBATIM
|
||||||
|
COMMENT "Creating export file for ${target_name}")
|
||||||
|
add_custom_target(${target_name}_exports DEPENDS symbol.exports)
|
||||||
|
set_property(DIRECTORY APPEND
|
||||||
|
PROPERTY ADDITIONAL_MAKE_CLEAN_FILES symbol.exports)
|
||||||
|
|
||||||
|
get_property(srcs TARGET ${target_name} PROPERTY SOURCES)
|
||||||
|
foreach(src ${srcs})
|
||||||
|
get_filename_component(extension ${src} EXT)
|
||||||
|
if(extension STREQUAL ".cpp")
|
||||||
|
set(first_source_file ${src})
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Force re-linking when the exports file changes. Actually, it
|
||||||
|
# forces recompilation of the source file. The LINK_DEPENDS target
|
||||||
|
# property only works for makefile-based generators.
|
||||||
|
set_property(SOURCE ${first_source_file} APPEND PROPERTY
|
||||||
|
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/symbol.exports)
|
||||||
|
|
||||||
|
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
|
||||||
|
LINK_FLAGS " -Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/symbol.exports")
|
||||||
|
add_dependencies(${target_name} ${target_name}_exports)
|
||||||
|
endif()
|
||||||
|
endfunction(add_clang_symbol_exports)
|
||||||
|
|
||||||
macro(add_clang_library name)
|
macro(add_clang_library name)
|
||||||
llvm_process_sources(srcs ${ARGN})
|
llvm_process_sources(srcs ${ARGN})
|
||||||
if(MSVC_IDE OR XCODE)
|
if(MSVC_IDE OR XCODE)
|
||||||
@ -228,11 +273,18 @@ macro(add_clang_library name)
|
|||||||
llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
|
llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
|
||||||
target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
|
target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
|
||||||
link_system_libs( ${name} )
|
link_system_libs( ${name} )
|
||||||
|
|
||||||
|
if (SHARED_LIBRARY AND EXPORTED_SYMBOL_FILE)
|
||||||
|
add_clang_symbol_exports( ${name} ${EXPORTED_SYMBOL_FILE} )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "libclang")
|
||||||
|
install(TARGETS ${name}
|
||||||
|
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||||
|
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||||
|
RUNTIME DESTINATION bin)
|
||||||
|
endif()
|
||||||
|
|
||||||
install(TARGETS ${name}
|
|
||||||
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
|
||||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
|
||||||
RUNTIME DESTINATION bin)
|
|
||||||
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
|
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
|
||||||
endmacro(add_clang_library)
|
endmacro(add_clang_library)
|
||||||
|
|
||||||
@ -246,26 +298,58 @@ include_directories(BEFORE
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
install(DIRECTORY include/
|
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||||
DESTINATION include
|
install(DIRECTORY include/
|
||||||
FILES_MATCHING
|
DESTINATION include
|
||||||
PATTERN "*.def"
|
FILES_MATCHING
|
||||||
PATTERN "*.h"
|
PATTERN "*.def"
|
||||||
PATTERN "config.h" EXCLUDE
|
PATTERN "*.h"
|
||||||
PATTERN ".svn" EXCLUDE
|
PATTERN "config.h" EXCLUDE
|
||||||
)
|
PATTERN ".svn" EXCLUDE
|
||||||
|
)
|
||||||
|
|
||||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING
|
||||||
|
PATTERN "CMakeFiles" EXCLUDE
|
||||||
|
PATTERN "*.inc"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(DIRECTORY include/clang-c
|
||||||
DESTINATION include
|
DESTINATION include
|
||||||
FILES_MATCHING
|
FILES_MATCHING
|
||||||
PATTERN "CMakeFiles" EXCLUDE
|
PATTERN "*.h"
|
||||||
PATTERN "*.inc"
|
PATTERN ".svn" EXCLUDE
|
||||||
)
|
)
|
||||||
|
|
||||||
add_definitions( -D_GNU_SOURCE )
|
add_definitions( -D_GNU_SOURCE )
|
||||||
|
|
||||||
# FIXME: They should be options.
|
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
|
||||||
add_definitions(-DCLANG_ENABLE_ARCMT -DCLANG_ENABLE_REWRITER -DCLANG_ENABLE_STATIC_ANALYZER)
|
option(CLANG_ENABLE_REWRITER "Build rewriter." ON)
|
||||||
|
option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
|
||||||
|
|
||||||
|
if (NOT CLANG_ENABLE_REWRITER AND CLANG_ENABLE_ARCMT)
|
||||||
|
message(FATAL_ERROR "Cannot disable rewriter while enabling ARCMT")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT CLANG_ENABLE_REWRITER AND CLANG_ENABLE_STATIC_ANALYZER)
|
||||||
|
message(FATAL_ERROR "Cannot disable rewriter while enabling static analyzer")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT CLANG_ENABLE_STATIC_ANALYZER AND CLANG_ENABLE_ARCMT)
|
||||||
|
message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CLANG_ENABLE_ARCMT)
|
||||||
|
add_definitions(-DCLANG_ENABLE_ARCMT)
|
||||||
|
endif()
|
||||||
|
if(CLANG_ENABLE_REWRITER)
|
||||||
|
add_definitions(-DCLANG_ENABLE_REWRITER)
|
||||||
|
endif()
|
||||||
|
if(CLANG_ENABLE_STATIC_ANALYZER)
|
||||||
|
add_definitions(-DCLANG_ENABLE_STATIC_ANALYZER)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Clang version information
|
# Clang version information
|
||||||
set(CLANG_EXECUTABLE_VERSION
|
set(CLANG_EXECUTABLE_VERSION
|
||||||
@ -290,13 +374,17 @@ option(CLANG_INCLUDE_TESTS
|
|||||||
"Generate build targets for the Clang unit tests."
|
"Generate build targets for the Clang unit tests."
|
||||||
${LLVM_INCLUDE_TESTS})
|
${LLVM_INCLUDE_TESTS})
|
||||||
|
|
||||||
# TODO: docs.
|
|
||||||
add_subdirectory(test)
|
|
||||||
|
|
||||||
if( CLANG_INCLUDE_TESTS )
|
if( CLANG_INCLUDE_TESTS )
|
||||||
|
add_subdirectory(test)
|
||||||
add_subdirectory(unittests)
|
add_subdirectory(unittests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(CLANG_INCLUDE_DOCS "Generate build targets for the Clang docs."
|
||||||
|
${LLVM_INCLUDE_DOCS})
|
||||||
|
if( CLANG_INCLUDE_DOCS )
|
||||||
|
add_subdirectory(docs)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Workaround for MSVS10 to avoid the Dialog Hell
|
# Workaround for MSVS10 to avoid the Dialog Hell
|
||||||
# FIXME: This could be removed with future version of CMake.
|
# FIXME: This could be removed with future version of CMake.
|
||||||
if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
|
if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
|
||||||
@ -309,3 +397,5 @@ endif()
|
|||||||
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
|
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
|
||||||
"Default URL where bug reports are to be submitted.")
|
"Default URL where bug reports are to be submitted.")
|
||||||
|
|
||||||
|
set(CLANG_ORDER_FILE "" CACHE FILEPATH
|
||||||
|
"Order file to use when compiling clang in order to improve startup time.")
|
||||||
|
@ -32,7 +32,7 @@ E: rjmccall@apple.com
|
|||||||
D: Clang LLVM IR generation
|
D: Clang LLVM IR generation
|
||||||
|
|
||||||
N: Chad Rosier
|
N: Chad Rosier
|
||||||
E: mcrosier@apple.com
|
E: mcrosier@codeaurora.org
|
||||||
D: MS-inline asm, and the compiler driver
|
D: MS-inline asm, and the compiler driver
|
||||||
|
|
||||||
N: Richard Smith
|
N: Richard Smith
|
||||||
|
@ -266,6 +266,29 @@ def __eq__(self, other):
|
|||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
def __contains__(self, other):
|
||||||
|
"""Useful to detect the Token/Lexer bug"""
|
||||||
|
if not isinstance(other, SourceLocation):
|
||||||
|
return False
|
||||||
|
if other.file is None and self.start.file is None:
|
||||||
|
pass
|
||||||
|
elif ( self.start.file.name != other.file.name or
|
||||||
|
other.file.name != self.end.file.name):
|
||||||
|
# same file name
|
||||||
|
return False
|
||||||
|
# same file, in between lines
|
||||||
|
if self.start.line < other.line < self.end.line:
|
||||||
|
return True
|
||||||
|
elif self.start.line == other.line:
|
||||||
|
# same file first line
|
||||||
|
if self.start.column <= other.column:
|
||||||
|
return True
|
||||||
|
elif other.line == self.end.line:
|
||||||
|
# same file last line
|
||||||
|
if other.column <= self.end.column:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<SourceRange start %r, end %r>" % (self.start, self.end)
|
return "<SourceRange start %r, end %r>" % (self.start, self.end)
|
||||||
|
|
||||||
@ -508,7 +531,7 @@ def name(self):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def from_id(id):
|
def from_id(id):
|
||||||
if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
|
if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
|
||||||
raise ValueError,'Unknown cursor kind'
|
raise ValueError,'Unknown cursor kind %d' % id
|
||||||
return CursorKind._kinds[id]
|
return CursorKind._kinds[id]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -721,10 +744,14 @@ def __repr__(self):
|
|||||||
# A reference to a labeled statement.
|
# A reference to a labeled statement.
|
||||||
CursorKind.LABEL_REF = CursorKind(48)
|
CursorKind.LABEL_REF = CursorKind(48)
|
||||||
|
|
||||||
# A reference toa a set of overloaded functions or function templates
|
# A reference to a set of overloaded functions or function templates
|
||||||
# that has not yet been resolved to a specific function or function template.
|
# that has not yet been resolved to a specific function or function template.
|
||||||
CursorKind.OVERLOADED_DECL_REF = CursorKind(49)
|
CursorKind.OVERLOADED_DECL_REF = CursorKind(49)
|
||||||
|
|
||||||
|
# A reference to a variable that occurs in some non-expression
|
||||||
|
# context, e.g., a C++ lambda capture list.
|
||||||
|
CursorKind.VARIABLE_REF = CursorKind(50)
|
||||||
|
|
||||||
###
|
###
|
||||||
# Invalid/Error Kinds
|
# Invalid/Error Kinds
|
||||||
|
|
||||||
@ -908,6 +935,26 @@ def __repr__(self):
|
|||||||
# pack.
|
# pack.
|
||||||
CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143)
|
CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143)
|
||||||
|
|
||||||
|
# Represents a C++ lambda expression that produces a local function
|
||||||
|
# object.
|
||||||
|
#
|
||||||
|
# \code
|
||||||
|
# void abssort(float *x, unsigned N) {
|
||||||
|
# std::sort(x, x + N,
|
||||||
|
# [](float a, float b) {
|
||||||
|
# return std::abs(a) < std::abs(b);
|
||||||
|
# });
|
||||||
|
# }
|
||||||
|
# \endcode
|
||||||
|
CursorKind.LAMBDA_EXPR = CursorKind(144)
|
||||||
|
|
||||||
|
# Objective-c Boolean Literal.
|
||||||
|
CursorKind.OBJ_BOOL_LITERAL_EXPR = CursorKind(145)
|
||||||
|
|
||||||
|
# Represents the "self" expression in a ObjC method.
|
||||||
|
CursorKind.OBJ_SELF_EXPR = CursorKind(146)
|
||||||
|
|
||||||
|
|
||||||
# A statement whose specific kind is not exposed via this interface.
|
# A statement whose specific kind is not exposed via this interface.
|
||||||
#
|
#
|
||||||
# Unexposed statements have the same operations as any other kind of statement;
|
# Unexposed statements have the same operations as any other kind of statement;
|
||||||
@ -999,6 +1046,9 @@ def __repr__(self):
|
|||||||
# Windows Structured Exception Handling's finally statement.
|
# Windows Structured Exception Handling's finally statement.
|
||||||
CursorKind.SEH_FINALLY_STMT = CursorKind(228)
|
CursorKind.SEH_FINALLY_STMT = CursorKind(228)
|
||||||
|
|
||||||
|
# A MS inline assembly statement extension.
|
||||||
|
CursorKind.MS_ASM_STMT = CursorKind(229)
|
||||||
|
|
||||||
# The null statement.
|
# The null statement.
|
||||||
CursorKind.NULL_STMT = CursorKind(230)
|
CursorKind.NULL_STMT = CursorKind(230)
|
||||||
|
|
||||||
@ -1028,6 +1078,7 @@ def __repr__(self):
|
|||||||
CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
|
CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
|
||||||
CursorKind.ANNOTATE_ATTR = CursorKind(406)
|
CursorKind.ANNOTATE_ATTR = CursorKind(406)
|
||||||
CursorKind.ASM_LABEL_ATTR = CursorKind(407)
|
CursorKind.ASM_LABEL_ATTR = CursorKind(407)
|
||||||
|
CursorKind.PACKED_ATTR = CursorKind(408)
|
||||||
|
|
||||||
###
|
###
|
||||||
# Preprocessing
|
# Preprocessing
|
||||||
@ -1036,6 +1087,12 @@ def __repr__(self):
|
|||||||
CursorKind.MACRO_INSTANTIATION = CursorKind(502)
|
CursorKind.MACRO_INSTANTIATION = CursorKind(502)
|
||||||
CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
|
CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
|
||||||
|
|
||||||
|
###
|
||||||
|
# Extra declaration
|
||||||
|
|
||||||
|
# A module import declaration.
|
||||||
|
CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
|
||||||
|
|
||||||
### Cursors ###
|
### Cursors ###
|
||||||
|
|
||||||
class Cursor(Structure):
|
class Cursor(Structure):
|
||||||
@ -1282,6 +1339,16 @@ def referenced(self):
|
|||||||
|
|
||||||
return self._referenced
|
return self._referenced
|
||||||
|
|
||||||
|
@property
|
||||||
|
def brief_comment(self):
|
||||||
|
"""Returns the brief comment text associated with that Cursor"""
|
||||||
|
return conf.lib.clang_Cursor_getBriefCommentText(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raw_comment(self):
|
||||||
|
"""Returns the raw comment text associated with that Cursor"""
|
||||||
|
return conf.lib.clang_Cursor_getRawCommentText(self)
|
||||||
|
|
||||||
def get_arguments(self):
|
def get_arguments(self):
|
||||||
"""Return an iterator for accessing the arguments of this cursor."""
|
"""Return an iterator for accessing the arguments of this cursor."""
|
||||||
num_args = conf.lib.clang_Cursor_getNumArguments(self)
|
num_args = conf.lib.clang_Cursor_getNumArguments(self)
|
||||||
@ -1450,6 +1517,54 @@ def __repr__(self):
|
|||||||
TypeKind.FUNCTIONPROTO = TypeKind(111)
|
TypeKind.FUNCTIONPROTO = TypeKind(111)
|
||||||
TypeKind.CONSTANTARRAY = TypeKind(112)
|
TypeKind.CONSTANTARRAY = TypeKind(112)
|
||||||
TypeKind.VECTOR = TypeKind(113)
|
TypeKind.VECTOR = TypeKind(113)
|
||||||
|
TypeKind.INCOMPLETEARRAY = TypeKind(114)
|
||||||
|
TypeKind.VARIABLEARRAY = TypeKind(115)
|
||||||
|
TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
|
||||||
|
TypeKind.MEMBERPOINTER = TypeKind(117)
|
||||||
|
|
||||||
|
class RefQualifierKind(object):
|
||||||
|
"""Describes a specific ref-qualifier of a type."""
|
||||||
|
|
||||||
|
# The unique kind objects, indexed by id.
|
||||||
|
_kinds = []
|
||||||
|
_name_map = None
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
if value >= len(RefQualifierKind._kinds):
|
||||||
|
num_kinds = value - len(RefQualifierKind._kinds) + 1
|
||||||
|
RefQualifierKind._kinds += [None] * num_kinds
|
||||||
|
if RefQualifierKind._kinds[value] is not None:
|
||||||
|
raise ValueError, 'RefQualifierKind already loaded'
|
||||||
|
self.value = value
|
||||||
|
RefQualifierKind._kinds[value] = self
|
||||||
|
RefQualifierKind._name_map = None
|
||||||
|
|
||||||
|
def from_param(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Get the enumeration name of this kind."""
|
||||||
|
if self._name_map is None:
|
||||||
|
self._name_map = {}
|
||||||
|
for key, value in RefQualifierKind.__dict__.items():
|
||||||
|
if isinstance(value, RefQualifierKind):
|
||||||
|
self._name_map[value] = key
|
||||||
|
return self._name_map[self]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_id(id):
|
||||||
|
if (id >= len(RefQualifierKind._kinds) or
|
||||||
|
RefQualifierKind._kinds[id] is None):
|
||||||
|
raise ValueError, 'Unknown type kind %d' % id
|
||||||
|
return RefQualifierKind._kinds[id]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'RefQualifierKind.%s' % (self.name,)
|
||||||
|
|
||||||
|
RefQualifierKind.NONE = RefQualifierKind(0)
|
||||||
|
RefQualifierKind.LVALUE = RefQualifierKind(1)
|
||||||
|
RefQualifierKind.RVALUE = RefQualifierKind(2)
|
||||||
|
|
||||||
class Type(Structure):
|
class Type(Structure):
|
||||||
"""
|
"""
|
||||||
@ -1625,6 +1740,12 @@ def get_array_size(self):
|
|||||||
"""
|
"""
|
||||||
return conf.lib.clang_getArraySize(self)
|
return conf.lib.clang_getArraySize(self)
|
||||||
|
|
||||||
|
def get_class_type(self):
|
||||||
|
"""
|
||||||
|
Retrieve the class type of the member pointer type.
|
||||||
|
"""
|
||||||
|
return conf.lib.clang_Type_getClassType(self)
|
||||||
|
|
||||||
def get_align(self):
|
def get_align(self):
|
||||||
"""
|
"""
|
||||||
Retrieve the alignment of the record.
|
Retrieve the alignment of the record.
|
||||||
@ -1643,6 +1764,18 @@ def get_offset(self, fieldname):
|
|||||||
"""
|
"""
|
||||||
return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname))
|
return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname))
|
||||||
|
|
||||||
|
def get_ref_qualifier(self):
|
||||||
|
"""
|
||||||
|
Retrieve the ref-qualifier of the type.
|
||||||
|
"""
|
||||||
|
return RefQualifierKind.from_id(
|
||||||
|
conf.lib.clang_Type_getCXXRefQualifier(self))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def spelling(self):
|
||||||
|
"""Retrieve the spelling of this Type."""
|
||||||
|
return conf.lib.clang_getTypeSpelling(self)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if type(other) != type(self):
|
if type(other) != type(self):
|
||||||
return False
|
return False
|
||||||
@ -1918,7 +2051,7 @@ def __del__(self):
|
|||||||
|
|
||||||
def read(self, path):
|
def read(self, path):
|
||||||
"""Load a TranslationUnit from the given AST file."""
|
"""Load a TranslationUnit from the given AST file."""
|
||||||
return TranslationUnit.from_ast(path, self)
|
return TranslationUnit.from_ast_file(path, self)
|
||||||
|
|
||||||
def parse(self, path, args=None, unsaved_files=None, options = 0):
|
def parse(self, path, args=None, unsaved_files=None, options = 0):
|
||||||
"""Load the translation unit from the given source code file by running
|
"""Load the translation unit from the given source code file by running
|
||||||
@ -2590,6 +2723,10 @@ def cursor(self):
|
|||||||
[Index, c_char_p],
|
[Index, c_char_p],
|
||||||
c_object_p),
|
c_object_p),
|
||||||
|
|
||||||
|
("clang_CXXMethod_isPureVirtual",
|
||||||
|
[Cursor],
|
||||||
|
bool),
|
||||||
|
|
||||||
("clang_CXXMethod_isStatic",
|
("clang_CXXMethod_isStatic",
|
||||||
[Cursor],
|
[Cursor],
|
||||||
bool),
|
bool),
|
||||||
@ -2973,6 +3110,11 @@ def cursor(self):
|
|||||||
_CXString,
|
_CXString,
|
||||||
_CXString.from_result),
|
_CXString.from_result),
|
||||||
|
|
||||||
|
("clang_getTypeSpelling",
|
||||||
|
[Type],
|
||||||
|
_CXString,
|
||||||
|
_CXString.from_result),
|
||||||
|
|
||||||
("clang_hashCursor",
|
("clang_hashCursor",
|
||||||
[Cursor],
|
[Cursor],
|
||||||
c_uint),
|
c_uint),
|
||||||
@ -3077,17 +3219,36 @@ def cursor(self):
|
|||||||
[Cursor],
|
[Cursor],
|
||||||
bool),
|
bool),
|
||||||
|
|
||||||
|
("clang_Cursor_getBriefCommentText",
|
||||||
|
[Cursor],
|
||||||
|
_CXString,
|
||||||
|
_CXString.from_result),
|
||||||
|
|
||||||
|
("clang_Cursor_getRawCommentText",
|
||||||
|
[Cursor],
|
||||||
|
_CXString,
|
||||||
|
_CXString.from_result),
|
||||||
|
|
||||||
("clang_Type_getAlignOf",
|
("clang_Type_getAlignOf",
|
||||||
[Type],
|
[Type],
|
||||||
c_longlong),
|
c_longlong),
|
||||||
|
|
||||||
|
("clang_Type_getClassType",
|
||||||
|
[Type],
|
||||||
|
Type,
|
||||||
|
Type.from_result),
|
||||||
|
|
||||||
("clang_Type_getOffsetOf",
|
("clang_Type_getOffsetOf",
|
||||||
[Type, c_char_p],
|
[Type, c_char_p],
|
||||||
c_longlong),
|
c_longlong),
|
||||||
|
|
||||||
("clang_Type_getSizeOf",
|
("clang_Type_getSizeOf",
|
||||||
[Type],
|
[Type],
|
||||||
c_ulonglong),
|
c_longlong),
|
||||||
|
|
||||||
|
("clang_Type_getCXXRefQualifier",
|
||||||
|
[Type],
|
||||||
|
c_uint),
|
||||||
]
|
]
|
||||||
|
|
||||||
class LibclangError(Exception):
|
class LibclangError(Exception):
|
||||||
|
40
bindings/python/tests/cindex/test_comment.py
Normal file
40
bindings/python/tests/cindex/test_comment.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
from clang.cindex import TranslationUnit
|
||||||
|
from tests.cindex.util import get_cursor
|
||||||
|
|
||||||
|
def test_comment():
|
||||||
|
files = [('fake.c', """
|
||||||
|
/// Aaa.
|
||||||
|
int test1;
|
||||||
|
|
||||||
|
/// Bbb.
|
||||||
|
/// x
|
||||||
|
void test2(void);
|
||||||
|
|
||||||
|
void f() {
|
||||||
|
|
||||||
|
}
|
||||||
|
""")]
|
||||||
|
# make a comment-aware TU
|
||||||
|
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
|
||||||
|
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
|
||||||
|
test1 = get_cursor(tu, 'test1')
|
||||||
|
assert test1 is not None, "Could not find test1."
|
||||||
|
assert test1.type.is_pod()
|
||||||
|
raw = test1.raw_comment
|
||||||
|
brief = test1.brief_comment
|
||||||
|
assert raw == """/// Aaa."""
|
||||||
|
assert brief == """Aaa."""
|
||||||
|
|
||||||
|
test2 = get_cursor(tu, 'test2')
|
||||||
|
raw = test2.raw_comment
|
||||||
|
brief = test2.brief_comment
|
||||||
|
assert raw == """/// Bbb.\n/// x"""
|
||||||
|
assert brief == """Bbb. x"""
|
||||||
|
|
||||||
|
f = get_cursor(tu, 'f')
|
||||||
|
raw = f.raw_comment
|
||||||
|
brief = f.brief_comment
|
||||||
|
assert raw is None
|
||||||
|
assert brief is None
|
||||||
|
|
||||||
|
|
@ -4,8 +4,15 @@ def test_name():
|
|||||||
assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
|
assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
|
||||||
|
|
||||||
def test_get_all_kinds():
|
def test_get_all_kinds():
|
||||||
assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds()
|
kinds = CursorKind.get_all_kinds()
|
||||||
assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds()
|
assert CursorKind.UNEXPOSED_DECL in kinds
|
||||||
|
assert CursorKind.TRANSLATION_UNIT in kinds
|
||||||
|
assert CursorKind.VARIABLE_REF in kinds
|
||||||
|
assert CursorKind.LAMBDA_EXPR in kinds
|
||||||
|
assert CursorKind.OBJ_BOOL_LITERAL_EXPR in kinds
|
||||||
|
assert CursorKind.OBJ_SELF_EXPR in kinds
|
||||||
|
assert CursorKind.MS_ASM_STMT in kinds
|
||||||
|
assert CursorKind.MODULE_IMPORT_DECL in kinds
|
||||||
|
|
||||||
def test_kind_groups():
|
def test_kind_groups():
|
||||||
"""Check that every kind classifies to exactly one group."""
|
"""Check that every kind classifies to exactly one group."""
|
||||||
|
@ -132,6 +132,22 @@ def test_equal():
|
|||||||
assert a.type != None
|
assert a.type != None
|
||||||
assert a.type != 'foo'
|
assert a.type != 'foo'
|
||||||
|
|
||||||
|
def test_type_spelling():
|
||||||
|
"""Ensure Type.spelling works."""
|
||||||
|
tu = get_tu('int c[5]; int i[]; int x; int v[x];')
|
||||||
|
c = get_cursor(tu, 'c')
|
||||||
|
i = get_cursor(tu, 'i')
|
||||||
|
x = get_cursor(tu, 'x')
|
||||||
|
v = get_cursor(tu, 'v')
|
||||||
|
assert c is not None
|
||||||
|
assert i is not None
|
||||||
|
assert x is not None
|
||||||
|
assert v is not None
|
||||||
|
assert c.type.spelling == "int [5]"
|
||||||
|
assert i.type.spelling == "int []"
|
||||||
|
assert x.type.spelling == "int"
|
||||||
|
assert v.type.spelling == "int [x]"
|
||||||
|
|
||||||
def test_typekind_spelling():
|
def test_typekind_spelling():
|
||||||
"""Ensure TypeKind.spelling works."""
|
"""Ensure TypeKind.spelling works."""
|
||||||
tu = get_tu('int a;')
|
tu = get_tu('int a;')
|
||||||
@ -237,12 +253,20 @@ def test_function_variadic():
|
|||||||
|
|
||||||
def test_element_type():
|
def test_element_type():
|
||||||
"""Ensure Type.element_type works."""
|
"""Ensure Type.element_type works."""
|
||||||
tu = get_tu('int i[5];')
|
tu = get_tu('int c[5]; int i[]; int x; int v[x];')
|
||||||
|
c = get_cursor(tu, 'c')
|
||||||
i = get_cursor(tu, 'i')
|
i = get_cursor(tu, 'i')
|
||||||
|
v = get_cursor(tu, 'v')
|
||||||
|
assert c is not None
|
||||||
assert i is not None
|
assert i is not None
|
||||||
|
assert v is not None
|
||||||
|
|
||||||
assert i.type.kind == TypeKind.CONSTANTARRAY
|
assert c.type.kind == TypeKind.CONSTANTARRAY
|
||||||
|
assert c.type.element_type.kind == TypeKind.INT
|
||||||
|
assert i.type.kind == TypeKind.INCOMPLETEARRAY
|
||||||
assert i.type.element_type.kind == TypeKind.INT
|
assert i.type.element_type.kind == TypeKind.INT
|
||||||
|
assert v.type.kind == TypeKind.VARIABLEARRAY
|
||||||
|
assert v.type.element_type.kind == TypeKind.INT
|
||||||
|
|
||||||
@raises(Exception)
|
@raises(Exception)
|
||||||
def test_invalid_element_type():
|
def test_invalid_element_type():
|
||||||
@ -361,3 +385,13 @@ def test_offset():
|
|||||||
assert teststruct.type.get_offset("bar") == bar
|
assert teststruct.type.get_offset("bar") == bar
|
||||||
|
|
||||||
|
|
||||||
|
def test_decay():
|
||||||
|
"""Ensure decayed types are handled as the original type"""
|
||||||
|
|
||||||
|
tu = get_tu("void foo(int a[]);")
|
||||||
|
foo = get_cursor(tu, 'foo')
|
||||||
|
a = foo.type.argument_types()[0]
|
||||||
|
|
||||||
|
assert a.kind == TypeKind.INCOMPLETEARRAY
|
||||||
|
assert a.element_type.kind == TypeKind.INT
|
||||||
|
assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
|
||||||
|
@ -75,7 +75,6 @@
|
|||||||
<optional>
|
<optional>
|
||||||
<ref name="USR" />
|
<ref name="USR" />
|
||||||
</optional>
|
</optional>
|
||||||
<!-- TODO: Add exception specification. -->
|
|
||||||
<optional>
|
<optional>
|
||||||
<ref name="Headerfile" />
|
<ref name="Headerfile" />
|
||||||
</optional>
|
</optional>
|
||||||
@ -91,6 +90,9 @@
|
|||||||
<optional>
|
<optional>
|
||||||
<ref name="Parameters" />
|
<ref name="Parameters" />
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<ref name="Exceptions" />
|
||||||
|
</optional>
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
<ref name="Availability" />
|
<ref name="Availability" />
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
@ -410,9 +412,14 @@
|
|||||||
</data>
|
</data>
|
||||||
</element>
|
</element>
|
||||||
<optional>
|
<optional>
|
||||||
<element name="Index">
|
<choice>
|
||||||
<data type="nonNegativeInteger" />
|
<element name="Index">
|
||||||
</element>
|
<data type="nonNegativeInteger" />
|
||||||
|
</element>
|
||||||
|
<element name="IsVarArg">
|
||||||
|
<empty />
|
||||||
|
</element>
|
||||||
|
</choice>
|
||||||
</optional>
|
</optional>
|
||||||
<element name="Direction">
|
<element name="Direction">
|
||||||
<attribute name="isExplicit">
|
<attribute name="isExplicit">
|
||||||
@ -435,6 +442,14 @@
|
|||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name="Exceptions">
|
||||||
|
<element name="Exceptions">
|
||||||
|
<oneOrMore>
|
||||||
|
<ref name="TextBlockContent" />
|
||||||
|
</oneOrMore>
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
|
|
||||||
<define name="Availability">
|
<define name="Availability">
|
||||||
<element name="Availability">
|
<element name="Availability">
|
||||||
<attribute name="distribution">
|
<attribute name="distribution">
|
||||||
|
@ -16,6 +16,7 @@ following types of bugs:
|
|||||||
* Use-after-free
|
* Use-after-free
|
||||||
* Use-after-return (to some extent)
|
* Use-after-return (to some extent)
|
||||||
* Double-free, invalid free
|
* Double-free, invalid free
|
||||||
|
* Memory leaks (experimental)
|
||||||
|
|
||||||
Typical slowdown introduced by AddressSanitizer is **2x**.
|
Typical slowdown introduced by AddressSanitizer is **2x**.
|
||||||
|
|
||||||
@ -114,8 +115,7 @@ function attribute
|
|||||||
(or a deprecated synonym `no_address_safety_analysis`)
|
(or a deprecated synonym `no_address_safety_analysis`)
|
||||||
to disable instrumentation of a particular function. This attribute may not be
|
to disable instrumentation of a particular function. This attribute may not be
|
||||||
supported by other compilers, so we suggest to use it together with
|
supported by other compilers, so we suggest to use it together with
|
||||||
``__has_feature(address_sanitizer)``. Note: currently, this attribute will be
|
``__has_feature(address_sanitizer)``.
|
||||||
lost if the function is inlined.
|
|
||||||
|
|
||||||
Initialization order checking
|
Initialization order checking
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@ -126,6 +126,42 @@ globals defined in another translation unit. To enable this check at runtime,
|
|||||||
you should set environment variable
|
you should set environment variable
|
||||||
``ASAN_OPTIONS=check_initialization_order=1``.
|
``ASAN_OPTIONS=check_initialization_order=1``.
|
||||||
|
|
||||||
|
Blacklist
|
||||||
|
---------
|
||||||
|
|
||||||
|
AddressSanitizer supports ``src`` and ``fun`` entity types in
|
||||||
|
:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
|
||||||
|
in the specified source files or functions. Additionally, AddressSanitizer
|
||||||
|
introduces ``global`` and ``type`` entity types that can be used to
|
||||||
|
suppress error reports for out-of-bound access to globals with certain
|
||||||
|
names and types (you may only specify class or struct types).
|
||||||
|
|
||||||
|
You may use an ``init`` category to suppress reports about initialization-order
|
||||||
|
problems happening in certain source files or with certain global variables.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Suppress error reports for code in a file or in a function:
|
||||||
|
src:bad_file.cpp
|
||||||
|
# Ignore all functions with names containing MyFooBar:
|
||||||
|
fun:*MyFooBar*
|
||||||
|
# Disable out-of-bound checks for global:
|
||||||
|
global:bad_array
|
||||||
|
# Disable out-of-bound checks for global instances of a given class ...
|
||||||
|
type:class.Namespace::BadClassName
|
||||||
|
# ... or a given struct. Use wildcard to deal with anonymous namespace.
|
||||||
|
type:struct.Namespace2::*::BadStructName
|
||||||
|
# Disable initialization-order checks for globals:
|
||||||
|
global:bad_init_global=init
|
||||||
|
type:*BadInitClassSubstring*=init
|
||||||
|
src:bad/init/files/*=init
|
||||||
|
|
||||||
|
Memory leak detection
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
For the experimental memory leak detector in AddressSanitizer, see
|
||||||
|
:doc:`LeakSanitizer`.
|
||||||
|
|
||||||
Supported Platforms
|
Supported Platforms
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
51
docs/CMakeLists.txt
Normal file
51
docs/CMakeLists.txt
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
if (DOXYGEN_FOUND)
|
||||||
|
if (LLVM_ENABLE_DOXYGEN)
|
||||||
|
set(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
set(abs_builddir ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
if (HAVE_DOT)
|
||||||
|
set(DOT ${LLVM_PATH_DOT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (LLVM_DOXYGEN_EXTERNAL_SEARCH)
|
||||||
|
set(enable_searchengine "YES")
|
||||||
|
set(searchengine_url "${LLVM_DOXYGEN_SEARCHENGINE_URL}")
|
||||||
|
set(enable_server_based_search "YES")
|
||||||
|
set(enable_external_search "YES")
|
||||||
|
set(extra_search_mappings "${LLVM_DOXYGEN_SEARCH_MAPPINGS}")
|
||||||
|
else()
|
||||||
|
set(enable_searchengine "NO")
|
||||||
|
set(searchengine_url "")
|
||||||
|
set(enable_server_based_search "NO")
|
||||||
|
set(enable_external_search "NO")
|
||||||
|
set(extra_search_mappings "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY)
|
||||||
|
|
||||||
|
set(abs_top_srcdir)
|
||||||
|
set(abs_top_builddir)
|
||||||
|
set(DOT)
|
||||||
|
set(enable_searchengine)
|
||||||
|
set(searchengine_url)
|
||||||
|
set(enable_server_based_search)
|
||||||
|
set(enable_external_search)
|
||||||
|
set(extra_search_mappings)
|
||||||
|
|
||||||
|
add_custom_target(doxygen-clang
|
||||||
|
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMENT "Generating clang doxygen documentation." VERBATIM)
|
||||||
|
|
||||||
|
if (LLVM_BUILD_DOCS)
|
||||||
|
add_dependencies(doxygen doxygen-clang)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||||
|
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doxygen/html
|
||||||
|
DESTINATION docs/html)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
@ -15,26 +15,73 @@ to format C/C++/Obj-C code.
|
|||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
$ clang-format --help
|
$ clang-format -help
|
||||||
OVERVIEW: A tool to format C/C++/Obj-C code.
|
OVERVIEW: A tool to format C/C++/Obj-C code.
|
||||||
|
|
||||||
If no arguments are specified, it formats the code from standard input
|
If no arguments are specified, it formats the code from standard input
|
||||||
and writes the result to the standard output.
|
and writes the result to the standard output.
|
||||||
If <file> is given, it reformats the file. If -i is specified together
|
If <file>s are given, it reformats the files. If -i is specified
|
||||||
with <file>, the file is edited in-place. Otherwise, the result is
|
together with <file>s, the files are edited in-place. Otherwise, the
|
||||||
written to the standard output.
|
result is written to the standard output.
|
||||||
|
|
||||||
USAGE: clang-format [options] [<file>]
|
USAGE: clang-format [options] [<file> ...]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-fatal-assembler-warnings - Consider warnings as error
|
|
||||||
-help - Display available options (-help-hidden for more)
|
Clang-format options:
|
||||||
-i - Inplace edit <file>, if specified.
|
|
||||||
-length=<int> - Format a range of this length, -1 for end of file.
|
-cursor=<uint> - The position of the cursor when invoking
|
||||||
-offset=<int> - Format a range starting at this file offset.
|
clang-format from an editor integration
|
||||||
-stats - Enable statistics output from program
|
-dump-config - Dump configuration options to stdout and exit.
|
||||||
-style=<string> - Coding style, currently supports: LLVM, Google, Chromium.
|
Can be used with -style option.
|
||||||
-version - Display the version of this program
|
-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}"
|
||||||
|
|
||||||
|
General options:
|
||||||
|
|
||||||
|
-help - Display available options (-help-hidden for more)
|
||||||
|
-help-list - Display list of available options (-help-list-hidden for more)
|
||||||
|
-version - Display the version of this program
|
||||||
|
|
||||||
|
|
||||||
|
When the desired code formatting style is different from the available options,
|
||||||
|
the style can be customized using the ``-style="{key: value, ...}"`` option or
|
||||||
|
by putting your style configuration in the ``.clang-format`` or ``_clang-format``
|
||||||
|
file in your project's directory and using ``clang-format -style=file``.
|
||||||
|
|
||||||
|
An easy way to create the ``.clang-format`` file is:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
clang-format -style=llvm -dump-config > .clang-format
|
||||||
|
|
||||||
|
Available style options are described in :doc:`ClangFormatStyleOptions`.
|
||||||
|
|
||||||
|
|
||||||
Vim Integration
|
Vim Integration
|
||||||
@ -96,6 +143,13 @@ menu item by renaming the script, and can assign the menu item a keyboard
|
|||||||
shortcut in the BBEdit preferences, under Menus & Shortcuts.
|
shortcut in the BBEdit preferences, under Menus & Shortcuts.
|
||||||
|
|
||||||
|
|
||||||
|
Visual Studio Integration
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Download the latest Visual Studio plugin from the `alpha build site
|
||||||
|
<http://llvm.org/builds/>`_. The default key-binding is Ctrl-R,Ctrl-F.
|
||||||
|
|
||||||
|
|
||||||
Script for patch reformatting
|
Script for patch reformatting
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
@ -106,18 +160,19 @@ a unified diff and reformats all contained lines with :program:`clang-format`.
|
|||||||
|
|
||||||
usage: clang-format-diff.py [-h] [-p P] [-style STYLE]
|
usage: clang-format-diff.py [-h] [-p P] [-style STYLE]
|
||||||
|
|
||||||
Reformat changed lines in diff
|
Reformat changed lines in diff.
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-p P strip the smallest prefix containing P slashes
|
-p P strip the smallest prefix containing P slashes
|
||||||
-style STYLE formatting style to apply (LLVM, Google, Chromium)
|
-style STYLE formatting style to apply (LLVM, Google, Chromium, Mozilla,
|
||||||
|
WebKit)
|
||||||
|
|
||||||
So to reformat all the lines in the latest :program:`git` commit, just do:
|
So to reformat all the lines in the latest :program:`git` commit, just do:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
git diff -U0 HEAD^ | clang-format-diff.py
|
git diff -U0 HEAD^ | clang-format-diff.py -p1
|
||||||
|
|
||||||
The :option:`-U0` will create a diff without context lines (the script would format
|
The :option:`-U0` will create a diff without context lines (the script would format
|
||||||
those as well).
|
those as well).
|
||||||
|
391
docs/ClangFormatStyleOptions.rst
Normal file
391
docs/ClangFormatStyleOptions.rst
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
==========================
|
||||||
|
Clang-Format Style Options
|
||||||
|
==========================
|
||||||
|
|
||||||
|
:doc:`ClangFormatStyleOptions` describes configurable formatting style options
|
||||||
|
supported by :doc:`LibFormat` and :doc:`ClangFormat`.
|
||||||
|
|
||||||
|
When using :program:`clang-format` command line utility or
|
||||||
|
``clang::format::reformat(...)`` functions from code, one can either use one of
|
||||||
|
the predefined styles (LLVM, Google, Chromium, Mozilla, WebKit) or create a
|
||||||
|
custom style by configuring specific style options.
|
||||||
|
|
||||||
|
|
||||||
|
Configuring Style with clang-format
|
||||||
|
===================================
|
||||||
|
|
||||||
|
:program:`clang-format` supports two ways to provide custom style options:
|
||||||
|
directly specify style configuration in the ``-style=`` command line option or
|
||||||
|
use ``-style=file`` and put style configuration in the ``.clang-format`` or
|
||||||
|
``_clang-format`` file in the project directory.
|
||||||
|
|
||||||
|
When using ``-style=file``, :program:`clang-format` for each input file will
|
||||||
|
try to find the ``.clang-format`` file located in the closest parent directory
|
||||||
|
of the input file. When the standard input is used, the search is started from
|
||||||
|
the current directory.
|
||||||
|
|
||||||
|
The ``.clang-format`` file uses YAML format:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
key1: value1
|
||||||
|
key2: value2
|
||||||
|
# A comment.
|
||||||
|
...
|
||||||
|
|
||||||
|
An easy way to get a valid ``.clang-format`` file containing all configuration
|
||||||
|
options of a certain predefined style is:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
clang-format -style=llvm -dump-config > .clang-format
|
||||||
|
|
||||||
|
When specifying configuration in the ``-style=`` option, the same configuration
|
||||||
|
is applied for all input files. The format of the configuration is:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
-style='{key1: value1, key2: value2, ...}'
|
||||||
|
|
||||||
|
|
||||||
|
Configuring Style in Code
|
||||||
|
=========================
|
||||||
|
|
||||||
|
When using ``clang::format::reformat(...)`` functions, the format is specified
|
||||||
|
by supplying the `clang::format::FormatStyle
|
||||||
|
<http://clang.llvm.org/doxygen/structclang_1_1format_1_1FormatStyle.html>`_
|
||||||
|
structure.
|
||||||
|
|
||||||
|
|
||||||
|
Configurable Format Style Options
|
||||||
|
=================================
|
||||||
|
|
||||||
|
This section lists the supported style options. Value type is specified for
|
||||||
|
each option. For enumeration types possible values are specified both as a C++
|
||||||
|
enumeration member (with a prefix, e.g. ``LS_Auto``), and as a value usable in
|
||||||
|
the configuration (without a prefix: ``Auto``).
|
||||||
|
|
||||||
|
|
||||||
|
**BasedOnStyle** (``string``)
|
||||||
|
The style used for all options not specifically set in the configuration.
|
||||||
|
|
||||||
|
This option is supported only in the :program:`clang-format` configuration
|
||||||
|
(both within ``-style='{...}'`` and the ``.clang-format`` file).
|
||||||
|
|
||||||
|
Possible values:
|
||||||
|
|
||||||
|
* ``LLVM``
|
||||||
|
A style complying with the `LLVM coding standards
|
||||||
|
<http://llvm.org/docs/CodingStandards.html>`_
|
||||||
|
* ``Google``
|
||||||
|
A style complying with `Google's C++ style guide
|
||||||
|
<http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml>`_
|
||||||
|
* ``Chromium``
|
||||||
|
A style complying with `Chromium's style guide
|
||||||
|
<http://www.chromium.org/developers/coding-style>`_
|
||||||
|
* ``Mozilla``
|
||||||
|
A style complying with `Mozilla's style guide
|
||||||
|
<https://developer.mozilla.org/en-US/docs/Developer_Guide/Coding_Style>`_
|
||||||
|
* ``WebKit``
|
||||||
|
A style complying with `WebKit's style guide
|
||||||
|
<http://www.webkit.org/coding/coding-style.html>`_
|
||||||
|
|
||||||
|
.. START_FORMAT_STYLE_OPTIONS
|
||||||
|
|
||||||
|
**AccessModifierOffset** (``int``)
|
||||||
|
The extra indent or outdent of access modifiers, e.g. ``public:``.
|
||||||
|
|
||||||
|
**AlignEscapedNewlinesLeft** (``bool``)
|
||||||
|
If ``true``, aligns escaped newlines as far left as possible.
|
||||||
|
Otherwise puts them into the right-most column.
|
||||||
|
|
||||||
|
**AlignTrailingComments** (``bool``)
|
||||||
|
If ``true``, aligns trailing comments.
|
||||||
|
|
||||||
|
**AllowAllParametersOfDeclarationOnNextLine** (``bool``)
|
||||||
|
Allow putting all parameters of a function declaration onto
|
||||||
|
the next line even if ``BinPackParameters`` is ``false``.
|
||||||
|
|
||||||
|
**AllowShortIfStatementsOnASingleLine** (``bool``)
|
||||||
|
If ``true``, ``if (a) return;`` can be put on a single
|
||||||
|
line.
|
||||||
|
|
||||||
|
**AllowShortLoopsOnASingleLine** (``bool``)
|
||||||
|
If ``true``, ``while (true) continue;`` can be put on a
|
||||||
|
single line.
|
||||||
|
|
||||||
|
**AlwaysBreakBeforeMultilineStrings** (``bool``)
|
||||||
|
If ``true``, always break before multiline string literals.
|
||||||
|
|
||||||
|
**AlwaysBreakTemplateDeclarations** (``bool``)
|
||||||
|
If ``true``, always break after the ``template<...>`` of a
|
||||||
|
template declaration.
|
||||||
|
|
||||||
|
**BinPackParameters** (``bool``)
|
||||||
|
If ``false``, a function call's or function definition's parameters
|
||||||
|
will either all be on the same line or will have one line each.
|
||||||
|
|
||||||
|
**BreakBeforeBinaryOperators** (``bool``)
|
||||||
|
If ``true``, binary operators will be placed after line breaks.
|
||||||
|
|
||||||
|
**BreakBeforeBraces** (``BraceBreakingStyle``)
|
||||||
|
The brace breaking style to use.
|
||||||
|
|
||||||
|
Possible values:
|
||||||
|
|
||||||
|
* ``BS_Attach`` (in configuration: ``Attach``)
|
||||||
|
Always attach braces to surrounding context.
|
||||||
|
* ``BS_Linux`` (in configuration: ``Linux``)
|
||||||
|
Like ``Attach``, but break before braces on function, namespace and
|
||||||
|
class definitions.
|
||||||
|
* ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
|
||||||
|
Like ``Attach``, but break before function definitions.
|
||||||
|
* ``BS_Allman`` (in configuration: ``Allman``)
|
||||||
|
Always break before braces.
|
||||||
|
|
||||||
|
|
||||||
|
**BreakConstructorInitializersBeforeComma** (``bool``)
|
||||||
|
Always break constructor initializers before commas and align
|
||||||
|
the commas with the colon.
|
||||||
|
|
||||||
|
**ColumnLimit** (``unsigned``)
|
||||||
|
The column limit.
|
||||||
|
|
||||||
|
A column limit of ``0`` means that there is no column limit. In this case,
|
||||||
|
clang-format will respect the input's line breaking decisions within
|
||||||
|
statements.
|
||||||
|
|
||||||
|
**ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``)
|
||||||
|
If the constructor initializers don't fit on a line, put each
|
||||||
|
initializer on its own line.
|
||||||
|
|
||||||
|
**ConstructorInitializerIndentWidth** (``unsigned``)
|
||||||
|
The number of characters to use for indentation of constructor
|
||||||
|
initializer lists.
|
||||||
|
|
||||||
|
**Cpp11BracedListStyle** (``bool``)
|
||||||
|
If ``true``, format braced lists as best suited for C++11 braced
|
||||||
|
lists.
|
||||||
|
|
||||||
|
Important differences:
|
||||||
|
- No spaces inside the braced list.
|
||||||
|
- No line break before the closing brace.
|
||||||
|
- Indentation with the continuation indent, not with the block indent.
|
||||||
|
|
||||||
|
Fundamentally, C++11 braced lists are formatted exactly like function
|
||||||
|
calls would be formatted in their place. If the braced list follows a name
|
||||||
|
(e.g. a type or variable name), clang-format formats as if the ``{}`` were
|
||||||
|
the parentheses of a function call with that name. If there is no name,
|
||||||
|
a zero-length name is assumed.
|
||||||
|
|
||||||
|
**DerivePointerBinding** (``bool``)
|
||||||
|
If ``true``, analyze the formatted file for the most common binding.
|
||||||
|
|
||||||
|
**ExperimentalAutoDetectBinPacking** (``bool``)
|
||||||
|
If ``true``, clang-format detects whether function calls and
|
||||||
|
definitions are formatted with one parameter per line.
|
||||||
|
|
||||||
|
Each call can be bin-packed, one-per-line or inconclusive. If it is
|
||||||
|
inconclusive, e.g. completely on one line, but a decision needs to be
|
||||||
|
made, clang-format analyzes whether there are other bin-packed cases in
|
||||||
|
the input file and act accordingly.
|
||||||
|
|
||||||
|
NOTE: This is an experimental flag, that might go away or be renamed. Do
|
||||||
|
not use this in config files, etc. Use at your own risk.
|
||||||
|
|
||||||
|
**IndentCaseLabels** (``bool``)
|
||||||
|
Indent case labels one level from the switch statement.
|
||||||
|
|
||||||
|
When ``false``, use the same indentation level as for the switch statement.
|
||||||
|
Switch statement body is always indented one level more than case labels.
|
||||||
|
|
||||||
|
**IndentFunctionDeclarationAfterType** (``bool``)
|
||||||
|
If ``true``, indent when breaking function declarations which
|
||||||
|
are not also definitions after the type.
|
||||||
|
|
||||||
|
**IndentWidth** (``unsigned``)
|
||||||
|
The number of columns to use for indentation.
|
||||||
|
|
||||||
|
**MaxEmptyLinesToKeep** (``unsigned``)
|
||||||
|
The maximum number of consecutive empty lines to keep.
|
||||||
|
|
||||||
|
**NamespaceIndentation** (``NamespaceIndentationKind``)
|
||||||
|
The indentation used for namespaces.
|
||||||
|
|
||||||
|
Possible values:
|
||||||
|
|
||||||
|
* ``NI_None`` (in configuration: ``None``)
|
||||||
|
Don't indent in namespaces.
|
||||||
|
* ``NI_Inner`` (in configuration: ``Inner``)
|
||||||
|
Indent only in inner namespaces (nested in other namespaces).
|
||||||
|
* ``NI_All`` (in configuration: ``All``)
|
||||||
|
Indent in all namespaces.
|
||||||
|
|
||||||
|
|
||||||
|
**ObjCSpaceBeforeProtocolList** (``bool``)
|
||||||
|
Add a space in front of an Objective-C protocol list, i.e. use
|
||||||
|
``Foo <Protocol>`` instead of ``Foo<Protocol>``.
|
||||||
|
|
||||||
|
**PenaltyBreakComment** (``unsigned``)
|
||||||
|
The penalty for each line break introduced inside a comment.
|
||||||
|
|
||||||
|
**PenaltyBreakFirstLessLess** (``unsigned``)
|
||||||
|
The penalty for breaking before the first ``<<``.
|
||||||
|
|
||||||
|
**PenaltyBreakString** (``unsigned``)
|
||||||
|
The penalty for each line break introduced inside a string literal.
|
||||||
|
|
||||||
|
**PenaltyExcessCharacter** (``unsigned``)
|
||||||
|
The penalty for each character outside of the column limit.
|
||||||
|
|
||||||
|
**PenaltyReturnTypeOnItsOwnLine** (``unsigned``)
|
||||||
|
Penalty for putting the return type of a function onto its own
|
||||||
|
line.
|
||||||
|
|
||||||
|
**PointerBindsToType** (``bool``)
|
||||||
|
Set whether & and * bind to the type as opposed to the variable.
|
||||||
|
|
||||||
|
**SpaceAfterControlStatementKeyword** (``bool``)
|
||||||
|
If ``true``, spaces will be inserted between 'for'/'if'/'while'/...
|
||||||
|
and '('.
|
||||||
|
|
||||||
|
**SpaceBeforeAssignmentOperators** (``bool``)
|
||||||
|
If ``false``, spaces will be removed before assignment operators.
|
||||||
|
|
||||||
|
**SpaceInEmptyParentheses** (``bool``)
|
||||||
|
If ``false``, spaces may be inserted into '()'.
|
||||||
|
|
||||||
|
**SpacesBeforeTrailingComments** (``unsigned``)
|
||||||
|
The number of spaces to before trailing line comments.
|
||||||
|
|
||||||
|
**SpacesInCStyleCastParentheses** (``bool``)
|
||||||
|
If ``false``, spaces may be inserted into C style casts.
|
||||||
|
|
||||||
|
**SpacesInParentheses** (``bool``)
|
||||||
|
If ``true``, spaces will be inserted after every '(' and before
|
||||||
|
every ')'.
|
||||||
|
|
||||||
|
**Standard** (``LanguageStandard``)
|
||||||
|
Format compatible with this standard, e.g. use
|
||||||
|
``A<A<int> >`` instead of ``A<A<int>>`` for LS_Cpp03.
|
||||||
|
|
||||||
|
Possible values:
|
||||||
|
|
||||||
|
* ``LS_Cpp03`` (in configuration: ``Cpp03``)
|
||||||
|
Use C++03-compatible syntax.
|
||||||
|
* ``LS_Cpp11`` (in configuration: ``Cpp11``)
|
||||||
|
Use features of C++11 (e.g. ``A<A<int>>`` instead of
|
||||||
|
``A<A<int> >``).
|
||||||
|
* ``LS_Auto`` (in configuration: ``Auto``)
|
||||||
|
Automatic detection based on the input.
|
||||||
|
|
||||||
|
|
||||||
|
**TabWidth** (``unsigned``)
|
||||||
|
The number of columns used for tab stops.
|
||||||
|
|
||||||
|
**UseTab** (``UseTabStyle``)
|
||||||
|
The way to use tab characters in the resulting file.
|
||||||
|
|
||||||
|
Possible values:
|
||||||
|
|
||||||
|
* ``UT_Never`` (in configuration: ``Never``)
|
||||||
|
Never use tab.
|
||||||
|
* ``UT_ForIndentation`` (in configuration: ``ForIndentation``)
|
||||||
|
Use tabs only for indentation.
|
||||||
|
* ``UT_Always`` (in configuration: ``Always``)
|
||||||
|
Use tabs whenever we need to fill whitespace that spans at least from
|
||||||
|
one tab stop to the next one.
|
||||||
|
|
||||||
|
|
||||||
|
.. END_FORMAT_STYLE_OPTIONS
|
||||||
|
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
A style similar to the `Linux Kernel style
|
||||||
|
<https://www.kernel.org/doc/Documentation/CodingStyle>`_:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 8
|
||||||
|
UseTab: Always
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
|
||||||
|
The result is (imagine that tabs are used for indentation here):
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
switch (x) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
do_something();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
do_something_else();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (condition)
|
||||||
|
do_something_completely_different();
|
||||||
|
|
||||||
|
if (x == y) {
|
||||||
|
q();
|
||||||
|
} else if (x > y) {
|
||||||
|
w();
|
||||||
|
} else {
|
||||||
|
r();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
A style similar to the default Visual Studio formatting style:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
UseTab: Never
|
||||||
|
IndentWidth: 4
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
ColumnLimit: 0
|
||||||
|
|
||||||
|
The result is:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
switch (suffix)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
do_something();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
do_something_else();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (condition)
|
||||||
|
do_somthing_completely_different();
|
||||||
|
|
||||||
|
if (x == y)
|
||||||
|
{
|
||||||
|
q();
|
||||||
|
}
|
||||||
|
else if (x > y)
|
||||||
|
{
|
||||||
|
w();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -88,8 +88,8 @@ Clang-format is both a :doc:`library <LibFormat>` and a :doc:`stand-alone tool
|
|||||||
<ClangFormat>` with the goal of automatically reformatting C++ sources files
|
<ClangFormat>` with the goal of automatically reformatting C++ sources files
|
||||||
according to configurable style guides. To do so, clang-format uses Clang's
|
according to configurable style guides. To do so, clang-format uses Clang's
|
||||||
``Lexer`` to transform an input file into a token stream and then changes all
|
``Lexer`` to transform an input file into a token stream and then changes all
|
||||||
the whitespace around those tokens. The goal is for clang-format to both serve
|
the whitespace around those tokens. The goal is for clang-format to serve both
|
||||||
both as a user tool (ideally with powerful IDE integrations) and part of other
|
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
|
refactoring tools, e.g. to do a reformatting of all the lines changed during a
|
||||||
renaming.
|
renaming.
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ Ideas for new Tools
|
|||||||
``foo`` is a standard container. We could also detect similar patterns for
|
``foo`` is a standard container. We could also detect similar patterns for
|
||||||
arrays.
|
arrays.
|
||||||
* ``make_shared`` / ``make_unique`` conversion. Part of this transformation
|
* ``make_shared`` / ``make_unique`` conversion. Part of this transformation
|
||||||
can be incorporated into the ``auto`` transformation. Will convert
|
can be incorporated into the ``auto`` transformation. Will convert
|
||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
|
204
docs/CrossCompilation.rst
Normal file
204
docs/CrossCompilation.rst
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
===================================================================
|
||||||
|
Cross-compilation using Clang
|
||||||
|
===================================================================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This document will guide you in choosing the right Clang options
|
||||||
|
for cross-compiling your code to a different architecture. It assumes you
|
||||||
|
already know how to compile the code in question for the host architecture,
|
||||||
|
and that you know how to choose additional include and library paths.
|
||||||
|
|
||||||
|
However, this document is *not* a "how to" and won't help you setting your
|
||||||
|
build system or Makefiles, nor choosing the right CMake options, etc.
|
||||||
|
Also, it does not cover all the possible options, nor does it contain
|
||||||
|
specific examples for specific architectures. For a concrete example, the
|
||||||
|
`instructions for cross-compiling LLVM itself
|
||||||
|
<http://llvm.org/docs/HowToCrossCompileLLVM.html>`_ may be of interest.
|
||||||
|
|
||||||
|
After reading this document, you should be familiar with the main issues
|
||||||
|
related to cross-compilation, and what main compiler options Clang provides
|
||||||
|
for performing cross-compilation.
|
||||||
|
|
||||||
|
Cross compilation issues
|
||||||
|
========================
|
||||||
|
|
||||||
|
In GCC world, every host/target combination has its own set of binaries,
|
||||||
|
headers, libraries, etc. So, it's usually simple to download a package
|
||||||
|
with all files in, unzip to a directory and point the build system to
|
||||||
|
that compiler, that will know about its location and find all it needs to
|
||||||
|
when compiling your code.
|
||||||
|
|
||||||
|
On the other hand, Clang/LLVM is natively a cross-compiler, meaning that
|
||||||
|
one set of programs can compile to all targets by setting the ``-target``
|
||||||
|
option. That makes it a lot easier for programers wishing to compile to
|
||||||
|
different platforms and architectures, and for compiler developers that
|
||||||
|
only have to maintain one build system, and for OS distributions, that
|
||||||
|
need only one set of main packages.
|
||||||
|
|
||||||
|
But, as is true to any cross-compiler, and given the complexity of
|
||||||
|
different architectures, OS's and options, it's not always easy finding
|
||||||
|
the headers, libraries or binutils to generate target specific code.
|
||||||
|
So you'll need special options to help Clang understand what target
|
||||||
|
you're compiling to, where your tools are, etc.
|
||||||
|
|
||||||
|
Another problem is that compilers come with standard libraries only (like
|
||||||
|
``compiler-rt``, ``libcxx``, ``libgcc``, ``libm``, etc), so you'll have to
|
||||||
|
find and make available to the build system, every other library required
|
||||||
|
to build your software, that is specific to your target. It's not enough to
|
||||||
|
have your host's libraries installed.
|
||||||
|
|
||||||
|
Finally, not all toolchains are the same, and consequently, not every Clang
|
||||||
|
option will work magically. Some options, like ``--sysroot`` (which
|
||||||
|
effectively changes the logical root for headers and libraries), assume
|
||||||
|
all your binaries and libraries are in the same directory, which may not
|
||||||
|
true when your cross-compiler was installed by the distribution's package
|
||||||
|
management. So, for each specific case, you may use more than one
|
||||||
|
option, and in most cases, you'll end up setting include paths (``-I``) and
|
||||||
|
library paths (``-L``) manually.
|
||||||
|
|
||||||
|
To sum up, different toolchains can:
|
||||||
|
* be host/target specific or more flexible
|
||||||
|
* be in a single directory, or spread out across your system
|
||||||
|
* have different sets of libraries and headers by default
|
||||||
|
* need special options, which your build system won't be able to figure
|
||||||
|
out by itself
|
||||||
|
|
||||||
|
General Cross-Compilation Options in Clang
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Target Triple
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The basic option is to define the target architecture. For that, use
|
||||||
|
``-target <triple>``. If you don't specify the target, CPU names won't
|
||||||
|
match (since Clang assumes the host triple), and the compilation will
|
||||||
|
go ahead, creating code for the host platform, which will break later
|
||||||
|
on when assembling or linking.
|
||||||
|
|
||||||
|
The triple has the general format ``<arch><sub>-<vendor>-<sys>-<abi>``, where:
|
||||||
|
* ``arch`` = ``x86``, ``arm``, ``thumb``, ``mips``, etc.
|
||||||
|
* ``sub`` = for ex. on ARM: ``v5``, ``v6m``, ``v7a``, ``v7m``, etc.
|
||||||
|
* ``vendor`` = ``pc``, ``apple``, ``nvidia``, ``ibm``, etc.
|
||||||
|
* ``sys`` = ``none``, ``linux``, ``win32``, ``darwin``, ``cuda``, etc.
|
||||||
|
* ``abi`` = ``eabi``, ``gnu``, ``android``, ``macho``, ``elf``, etc.
|
||||||
|
|
||||||
|
The sub-architecture options are available for their own architectures,
|
||||||
|
of course, so "x86v7a" doesn't make sense. The vendor needs to be
|
||||||
|
specified only if there's a relevant change, for instance between PC
|
||||||
|
and Apple. Most of the time it can be omitted (and Unknown)
|
||||||
|
will be assumed, which sets the defaults for the specified architecture.
|
||||||
|
The system name is generally the OS (linux, darwin), but could be special
|
||||||
|
like the bare-metal "none".
|
||||||
|
|
||||||
|
When a parameter is not important, they can be omitted, or you can
|
||||||
|
choose ``unknown`` and the defaults will be used. If you choose a parameter
|
||||||
|
that Clang doesn't know, like ``blerg``, it'll ignore and assume
|
||||||
|
``unknown``, which is not always desired, so be careful.
|
||||||
|
|
||||||
|
Finally, the ABI option is something that will pick default CPU/FPU,
|
||||||
|
define the specific behaviour of your code (PCS, extensions),
|
||||||
|
and also choose the correct library calls, etc.
|
||||||
|
|
||||||
|
CPU, FPU, ABI
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Once your target is specified, it's time to pick the hardware you'll
|
||||||
|
be compiling to. For every architecture, a default set of CPU/FPU/ABI
|
||||||
|
will be chosen, so you'll almost always have to change it via flags.
|
||||||
|
|
||||||
|
Typical flags include:
|
||||||
|
* ``-mcpu=<cpu-name>``, like x86-64, swift, cortex-a15
|
||||||
|
* ``-fpu=<fpu-name>``, like SSE3, NEON, controlling the FP unit available
|
||||||
|
* ``-mfloat-abi=<fabi>``, like soft, hard, controlling which registers
|
||||||
|
to use for floating-point
|
||||||
|
|
||||||
|
The default is normally the common denominator, so that Clang doesn't
|
||||||
|
generate code that breaks. But that also means you won't get the best
|
||||||
|
code for your specific hardware, which may mean orders of magnitude
|
||||||
|
slower than you expect.
|
||||||
|
|
||||||
|
For example, if your target is ``arm-none-eabi``, the default CPU will
|
||||||
|
be ``arm7tdmi`` using soft float, which is extremely slow on modern cores,
|
||||||
|
whereas if your triple is ``armv7a-none-eabi``, it'll be Cortex-A8 with
|
||||||
|
NEON, but still using soft-float, which is much better, but still not
|
||||||
|
great.
|
||||||
|
|
||||||
|
Toolchain Options
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
There are three main options to control access to your cross-compiler:
|
||||||
|
``--sysroot``, ``-I``, and ``-L``. The two last ones are well known,
|
||||||
|
but they're particularly important for additional libraries
|
||||||
|
and headers that are specific to your target.
|
||||||
|
|
||||||
|
There are two main ways to have a cross-compiler:
|
||||||
|
|
||||||
|
#. When you have extracted your cross-compiler from a zip file into
|
||||||
|
a directory, you have to use ``--sysroot=<path>``. The path is the
|
||||||
|
root directory where you have unpacked your file, and Clang will
|
||||||
|
look for the directories ``bin``, ``lib``, ``include`` in there.
|
||||||
|
|
||||||
|
In this case, your setup should be pretty much done (if no
|
||||||
|
additional headers or libraries are needed), as Clang will find
|
||||||
|
all binaries it needs (assembler, linker, etc) in there.
|
||||||
|
|
||||||
|
#. When you have installed via a package manager (modern Linux
|
||||||
|
distributions have cross-compiler packages available), make
|
||||||
|
sure the target triple you set is *also* the prefix of your
|
||||||
|
cross-compiler toolchain.
|
||||||
|
|
||||||
|
In this case, Clang will find the other binaries (assembler,
|
||||||
|
linker), but not always where the target headers and libraries
|
||||||
|
are. People add system-specific clues to Clang often, but as
|
||||||
|
things change, it's more likely that it won't find than the
|
||||||
|
other way around.
|
||||||
|
|
||||||
|
So, here, you'll be a lot safer if you specify the include/library
|
||||||
|
directories manually (via ``-I`` and ``-L``).
|
||||||
|
|
||||||
|
Target-Specific Libraries
|
||||||
|
=========================
|
||||||
|
|
||||||
|
All libraries that you compile as part of your build will be
|
||||||
|
cross-compiled to your target, and your build system will probably
|
||||||
|
find them in the right place. But all dependencies that are
|
||||||
|
normally checked against (like ``libxml`` or ``libz`` etc) will match
|
||||||
|
against the host platform, not the target.
|
||||||
|
|
||||||
|
So, if the build system is not aware that you want to cross-compile
|
||||||
|
your code, it will get every dependency wrong, and your compilation
|
||||||
|
will fail during build time, not configure time.
|
||||||
|
|
||||||
|
Also, finding the libraries for your target are not as easy
|
||||||
|
as for your host machine. There aren't many cross-libraries available
|
||||||
|
as packages to most OS's, so you'll have to either cross-compile them
|
||||||
|
from source, or download the package for your target platform,
|
||||||
|
extract the libraries and headers, put them in specific directories
|
||||||
|
and add ``-I`` and ``-L`` pointing to them.
|
||||||
|
|
||||||
|
Also, some libraries have different dependencies on different targets,
|
||||||
|
so configuration tools to find dependencies in the host can get the
|
||||||
|
list wrong for the target platform. This means that the configuration
|
||||||
|
of your build can get things wrong when setting their own library
|
||||||
|
paths, and you'll have to augment it via additional flags (configure,
|
||||||
|
Make, CMake, etc).
|
||||||
|
|
||||||
|
Multilibs
|
||||||
|
---------
|
||||||
|
|
||||||
|
When you want to cross-compile to more than one configuration, for
|
||||||
|
example hard-float-ARM and soft-float-ARM, you'll have to have multiple
|
||||||
|
copies of your libraries and (possibly) headers.
|
||||||
|
|
||||||
|
Some Linux distributions have support for Multilib, which handle that
|
||||||
|
for you in an easier way, but if you're not careful and, for instance,
|
||||||
|
forget to specify ``-ccc-gcc-name armv7l-linux-gnueabihf-gcc`` (which
|
||||||
|
uses hard-float), Clang will pick the ``armv7l-linux-gnueabi-ld``
|
||||||
|
(which uses soft-float) and linker errors will happen.
|
||||||
|
|
||||||
|
The same is true if you're compiling for different ABIs, like ``gnueabi``
|
||||||
|
and ``androideabi``, and might even link and run, but produce run-time
|
||||||
|
errors, which are much harder to track down and fix.
|
||||||
|
|
158
docs/DataFlowSanitizer.rst
Normal file
158
docs/DataFlowSanitizer.rst
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
=================
|
||||||
|
DataFlowSanitizer
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
DataFlowSanitizerDesign
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
DataFlowSanitizer is a generalised dynamic data flow analysis.
|
||||||
|
|
||||||
|
Unlike other Sanitizer tools, this tool is not designed to detect a
|
||||||
|
specific class of bugs on its own. Instead, it provides a generic
|
||||||
|
dynamic data flow analysis framework to be used by clients to help
|
||||||
|
detect application-specific issues within their own code.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
With no program changes, applying DataFlowSanitizer to a program
|
||||||
|
will not alter its behavior. To use DataFlowSanitizer, the program
|
||||||
|
uses API functions to apply tags to data to cause it to be tracked, and to
|
||||||
|
check the tag of a specific data item. DataFlowSanitizer manages
|
||||||
|
the propagation of tags through the program according to its data flow.
|
||||||
|
|
||||||
|
The APIs are defined in the header file ``sanitizer/dfsan_interface.h``.
|
||||||
|
For further information about each function, please refer to the header
|
||||||
|
file.
|
||||||
|
|
||||||
|
ABI List
|
||||||
|
--------
|
||||||
|
|
||||||
|
DataFlowSanitizer uses a list of functions known as an ABI list to decide
|
||||||
|
whether a call to a specific function should use the operating system's native
|
||||||
|
ABI or whether it should use a variant of this ABI that also propagates labels
|
||||||
|
through function parameters and return values. The ABI list file also controls
|
||||||
|
how labels are propagated in the former case. DataFlowSanitizer comes with a
|
||||||
|
default ABI list which is intended to eventually cover the glibc library on
|
||||||
|
Linux but it may become necessary for users to extend the ABI list in cases
|
||||||
|
where a particular library or function cannot be instrumented (e.g. because
|
||||||
|
it is implemented in assembly or another language which DataFlowSanitizer does
|
||||||
|
not support) or a function is called from a library or function which cannot
|
||||||
|
be instrumented.
|
||||||
|
|
||||||
|
DataFlowSanitizer's ABI list file is a :doc:`SanitizerSpecialCaseList`.
|
||||||
|
The pass treats every function in the ``uninstrumented`` category in the
|
||||||
|
ABI list file as conforming to the native ABI. Unless the ABI list contains
|
||||||
|
additional categories for those functions, a call to one of those functions
|
||||||
|
will produce a warning message, as the labelling behavior of the function
|
||||||
|
is unknown. The other supported categories are ``discard``, ``functional``
|
||||||
|
and ``custom``.
|
||||||
|
|
||||||
|
* ``discard`` -- To the extent that this function writes to (user-accessible)
|
||||||
|
memory, it also updates labels in shadow memory (this condition is trivially
|
||||||
|
satisfied for functions which do not write to user-accessible memory). Its
|
||||||
|
return value is unlabelled.
|
||||||
|
* ``functional`` -- Like ``discard``, except that the label of its return value
|
||||||
|
is the union of the label of its arguments.
|
||||||
|
* ``custom`` -- Instead of calling the function, a custom wrapper ``__dfsw_F``
|
||||||
|
is called, where ``F`` is the name of the function. This function may wrap
|
||||||
|
the original function or provide its own implementation. This category is
|
||||||
|
generally used for uninstrumentable functions which write to user-accessible
|
||||||
|
memory or which have more complex label propagation behavior. The signature
|
||||||
|
of ``__dfsw_F`` is based on that of ``F`` with each argument having a
|
||||||
|
label of type ``dfsan_label`` appended to the argument list. If ``F``
|
||||||
|
is of non-void return type a final argument of type ``dfsan_label *``
|
||||||
|
is appended to which the custom function can store the label for the
|
||||||
|
return value. For example:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
void f(int x);
|
||||||
|
void __dfsw_f(int x, dfsan_label x_label);
|
||||||
|
|
||||||
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
|
void *__dfsw_memcpy(void *dest, const void *src, size_t n,
|
||||||
|
dfsan_label dest_label, dfsan_label src_label,
|
||||||
|
dfsan_label n_label, dfsan_label *ret_label);
|
||||||
|
|
||||||
|
If a function defined in the translation unit being compiled belongs to the
|
||||||
|
``uninstrumented`` category, it will be compiled so as to conform to the
|
||||||
|
native ABI. Its arguments will be assumed to be unlabelled, but it will
|
||||||
|
propagate labels in shadow memory.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
# main is called by the C runtime using the native ABI.
|
||||||
|
fun:main=uninstrumented
|
||||||
|
fun:main=discard
|
||||||
|
|
||||||
|
# malloc only writes to its internal data structures, not user-accessible memory.
|
||||||
|
fun:malloc=uninstrumented
|
||||||
|
fun:malloc=discard
|
||||||
|
|
||||||
|
# tolower is a pure function.
|
||||||
|
fun:tolower=uninstrumented
|
||||||
|
fun:tolower=functional
|
||||||
|
|
||||||
|
# memcpy needs to copy the shadow from the source to the destination region.
|
||||||
|
# This is done in a custom function.
|
||||||
|
fun:memcpy=uninstrumented
|
||||||
|
fun:memcpy=custom
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
The following program demonstrates label propagation by checking that
|
||||||
|
the correct labels are propagated.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
#include <sanitizer/dfsan_interface.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int i = 1;
|
||||||
|
dfsan_label i_label = dfsan_create_label("i", 0);
|
||||||
|
dfsan_set_label(i_label, &i, sizeof(i));
|
||||||
|
|
||||||
|
int j = 2;
|
||||||
|
dfsan_label j_label = dfsan_create_label("j", 0);
|
||||||
|
dfsan_set_label(j_label, &j, sizeof(j));
|
||||||
|
|
||||||
|
int k = 3;
|
||||||
|
dfsan_label k_label = dfsan_create_label("k", 0);
|
||||||
|
dfsan_set_label(k_label, &k, sizeof(k));
|
||||||
|
|
||||||
|
dfsan_label ij_label = dfsan_get_label(i + j);
|
||||||
|
assert(dfsan_has_label(ij_label, i_label));
|
||||||
|
assert(dfsan_has_label(ij_label, j_label));
|
||||||
|
assert(!dfsan_has_label(ij_label, k_label));
|
||||||
|
|
||||||
|
dfsan_label ijk_label = dfsan_get_label(i + j + k);
|
||||||
|
assert(dfsan_has_label(ijk_label, i_label));
|
||||||
|
assert(dfsan_has_label(ijk_label, j_label));
|
||||||
|
assert(dfsan_has_label(ijk_label, k_label));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Current status
|
||||||
|
==============
|
||||||
|
|
||||||
|
DataFlowSanitizer is a work in progress, currently under development for
|
||||||
|
x86\_64 Linux.
|
||||||
|
|
||||||
|
Design
|
||||||
|
======
|
||||||
|
|
||||||
|
Please refer to the :doc:`design document<DataFlowSanitizerDesign>`.
|
220
docs/DataFlowSanitizerDesign.rst
Normal file
220
docs/DataFlowSanitizerDesign.rst
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
DataFlowSanitizer Design Document
|
||||||
|
=================================
|
||||||
|
|
||||||
|
This document sets out the design for DataFlowSanitizer, a general
|
||||||
|
dynamic data flow analysis. Unlike other Sanitizer tools, this tool is
|
||||||
|
not designed to detect a specific class of bugs on its own. Instead,
|
||||||
|
it provides a generic dynamic data flow analysis framework to be used
|
||||||
|
by clients to help detect application-specific issues within their
|
||||||
|
own code.
|
||||||
|
|
||||||
|
DataFlowSanitizer is a program instrumentation which can associate
|
||||||
|
a number of taint labels with any data stored in any memory region
|
||||||
|
accessible by the program. The analysis is dynamic, which means that
|
||||||
|
it operates on a running program, and tracks how the labels propagate
|
||||||
|
through that program. The tool shall support a large (>100) number
|
||||||
|
of labels, such that programs which operate on large numbers of data
|
||||||
|
items may be analysed with each data item being tracked separately.
|
||||||
|
|
||||||
|
Use Cases
|
||||||
|
---------
|
||||||
|
|
||||||
|
This instrumentation can be used as a tool to help monitor how data
|
||||||
|
flows from a program's inputs (sources) to its outputs (sinks).
|
||||||
|
This has applications from a privacy/security perspective in that
|
||||||
|
one can audit how a sensitive data item is used within a program and
|
||||||
|
ensure it isn't exiting the program anywhere it shouldn't be.
|
||||||
|
|
||||||
|
Interface
|
||||||
|
---------
|
||||||
|
|
||||||
|
A number of functions are provided which will create taint labels,
|
||||||
|
attach labels to memory regions and extract the set of labels
|
||||||
|
associated with a specific memory region. These functions are declared
|
||||||
|
in the header file ``sanitizer/dfsan_interface.h``.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
/// Creates and returns a base label with the given description and user data.
|
||||||
|
dfsan_label dfsan_create_label(const char *desc, void *userdata);
|
||||||
|
|
||||||
|
/// Sets the label for each address in [addr,addr+size) to \c label.
|
||||||
|
void dfsan_set_label(dfsan_label label, void *addr, size_t size);
|
||||||
|
|
||||||
|
/// Sets the label for each address in [addr,addr+size) to the union of the
|
||||||
|
/// current label for that address and \c label.
|
||||||
|
void dfsan_add_label(dfsan_label label, void *addr, size_t size);
|
||||||
|
|
||||||
|
/// Retrieves the label associated with the given data.
|
||||||
|
///
|
||||||
|
/// The type of 'data' is arbitrary. The function accepts a value of any type,
|
||||||
|
/// which can be truncated or extended (implicitly or explicitly) as necessary.
|
||||||
|
/// The truncation/extension operations will preserve the label of the original
|
||||||
|
/// value.
|
||||||
|
dfsan_label dfsan_get_label(long data);
|
||||||
|
|
||||||
|
/// Retrieves a pointer to the dfsan_label_info struct for the given label.
|
||||||
|
const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
|
||||||
|
|
||||||
|
/// Returns whether the given label label contains the label elem.
|
||||||
|
int dfsan_has_label(dfsan_label label, dfsan_label elem);
|
||||||
|
|
||||||
|
/// If the given label label contains a label with the description desc, returns
|
||||||
|
/// that label, else returns 0.
|
||||||
|
dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc);
|
||||||
|
|
||||||
|
Taint label representation
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
As stated above, the tool must track a large number of taint
|
||||||
|
labels. This poses an implementation challenge, as most multiple-label
|
||||||
|
tainting systems assign one label per bit to shadow storage, and
|
||||||
|
union taint labels using a bitwise or operation. This will not scale
|
||||||
|
to clients which use hundreds or thousands of taint labels, as the
|
||||||
|
label union operation becomes O(n) in the number of supported labels,
|
||||||
|
and data associated with it will quickly dominate the live variable
|
||||||
|
set, causing register spills and hampering performance.
|
||||||
|
|
||||||
|
Instead, a low overhead approach is proposed which is best-case O(log\
|
||||||
|
:sub:`2` n) during execution. The underlying assumption is that
|
||||||
|
the required space of label unions is sparse, which is a reasonable
|
||||||
|
assumption to make given that we are optimizing for the case where
|
||||||
|
applications mostly copy data from one place to another, without often
|
||||||
|
invoking the need for an actual union operation. The representation
|
||||||
|
of a taint label is a 16-bit integer, and new labels are allocated
|
||||||
|
sequentially from a pool. The label identifier 0 is special, and means
|
||||||
|
that the data item is unlabelled.
|
||||||
|
|
||||||
|
When a label union operation is requested at a join point (any
|
||||||
|
arithmetic or logical operation with two or more operands, such as
|
||||||
|
addition), the code checks whether a union is required, whether the
|
||||||
|
same union has been requested before, and whether one union label
|
||||||
|
subsumes the other. If so, it returns the previously allocated union
|
||||||
|
label. If not, it allocates a new union label from the same pool used
|
||||||
|
for new labels.
|
||||||
|
|
||||||
|
Specifically, the instrumentation pass will insert code like this
|
||||||
|
to decide the union label ``lu`` for a pair of labels ``l1``
|
||||||
|
and ``l2``:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
if (l1 == l2)
|
||||||
|
lu = l1;
|
||||||
|
else
|
||||||
|
lu = __dfsan_union(l1, l2);
|
||||||
|
|
||||||
|
The equality comparison is outlined, to provide an early exit in
|
||||||
|
the common cases where the program is processing unlabelled data, or
|
||||||
|
where the two data items have the same label. ``__dfsan_union`` is
|
||||||
|
a runtime library function which performs all other union computation.
|
||||||
|
|
||||||
|
Further optimizations are possible, for example if ``l1`` is known
|
||||||
|
at compile time to be zero (e.g. it is derived from a constant),
|
||||||
|
``l2`` can be used for ``lu``, and vice versa.
|
||||||
|
|
||||||
|
Memory layout and label management
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
The following is the current memory layout for Linux/x86\_64:
|
||||||
|
|
||||||
|
+---------------+---------------+--------------------+
|
||||||
|
| Start | End | Use |
|
||||||
|
+===============+===============+====================+
|
||||||
|
| 0x700000008000|0x800000000000 | application memory |
|
||||||
|
+---------------+---------------+--------------------+
|
||||||
|
| 0x200200000000|0x700000008000 | unused |
|
||||||
|
+---------------+---------------+--------------------+
|
||||||
|
| 0x200000000000|0x200200000000 | union table |
|
||||||
|
+---------------+---------------+--------------------+
|
||||||
|
| 0x000000010000|0x200000000000 | shadow memory |
|
||||||
|
+---------------+---------------+--------------------+
|
||||||
|
| 0x000000000000|0x000000010000 | reserved by kernel |
|
||||||
|
+---------------+---------------+--------------------+
|
||||||
|
|
||||||
|
Each byte of application memory corresponds to two bytes of shadow
|
||||||
|
memory, which are used to store its taint label. As for LLVM SSA
|
||||||
|
registers, we have not found it necessary to associate a label with
|
||||||
|
each byte or bit of data, as some other tools do. Instead, labels are
|
||||||
|
associated directly with registers. Loads will result in a union of
|
||||||
|
all shadow labels corresponding to bytes loaded (which most of the
|
||||||
|
time will be short circuited by the initial comparison) and stores will
|
||||||
|
result in a copy of the label to the shadow of all bytes stored to.
|
||||||
|
|
||||||
|
Propagating labels through arguments
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
In order to propagate labels through function arguments and return values,
|
||||||
|
DataFlowSanitizer changes the ABI of each function in the translation unit.
|
||||||
|
There are currently two supported ABIs:
|
||||||
|
|
||||||
|
* Args -- Argument and return value labels are passed through additional
|
||||||
|
arguments and by modifying the return type.
|
||||||
|
|
||||||
|
* TLS -- Argument and return value labels are passed through TLS variables
|
||||||
|
``__dfsan_arg_tls`` and ``__dfsan_retval_tls``.
|
||||||
|
|
||||||
|
The main advantage of the TLS ABI is that it is more tolerant of ABI mismatches
|
||||||
|
(TLS storage is not shared with any other form of storage, whereas extra
|
||||||
|
arguments may be stored in registers which under the native ABI are not used
|
||||||
|
for parameter passing and thus could contain arbitrary values). On the other
|
||||||
|
hand the args ABI is more efficient and allows ABI mismatches to be more easily
|
||||||
|
identified by checking for nonzero labels in nominally unlabelled programs.
|
||||||
|
|
||||||
|
Implementing the ABI list
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
The `ABI list <DataFlowSanitizer.html#abi-list>`_ provides a list of functions
|
||||||
|
which conform to the native ABI, each of which is callable from an instrumented
|
||||||
|
program. This is implemented by replacing each reference to a native ABI
|
||||||
|
function with a reference to a function which uses the instrumented ABI.
|
||||||
|
Such functions are automatically-generated wrappers for the native functions.
|
||||||
|
For example, given the ABI list example provided in the user manual, the
|
||||||
|
following wrappers will be generated under the args ABI:
|
||||||
|
|
||||||
|
.. code-block:: llvm
|
||||||
|
|
||||||
|
define linkonce_odr { i8*, i16 } @"dfsw$malloc"(i64 %0, i16 %1) {
|
||||||
|
entry:
|
||||||
|
%2 = call i8* @malloc(i64 %0)
|
||||||
|
%3 = insertvalue { i8*, i16 } undef, i8* %2, 0
|
||||||
|
%4 = insertvalue { i8*, i16 } %3, i16 0, 1
|
||||||
|
ret { i8*, i16 } %4
|
||||||
|
}
|
||||||
|
|
||||||
|
define linkonce_odr { i32, i16 } @"dfsw$tolower"(i32 %0, i16 %1) {
|
||||||
|
entry:
|
||||||
|
%2 = call i32 @tolower(i32 %0)
|
||||||
|
%3 = insertvalue { i32, i16 } undef, i32 %2, 0
|
||||||
|
%4 = insertvalue { i32, i16 } %3, i16 %1, 1
|
||||||
|
ret { i32, i16 } %4
|
||||||
|
}
|
||||||
|
|
||||||
|
define linkonce_odr { i8*, i16 } @"dfsw$memcpy"(i8* %0, i8* %1, i64 %2, i16 %3, i16 %4, i16 %5) {
|
||||||
|
entry:
|
||||||
|
%labelreturn = alloca i16
|
||||||
|
%6 = call i8* @__dfsw_memcpy(i8* %0, i8* %1, i64 %2, i16 %3, i16 %4, i16 %5, i16* %labelreturn)
|
||||||
|
%7 = load i16* %labelreturn
|
||||||
|
%8 = insertvalue { i8*, i16 } undef, i8* %6, 0
|
||||||
|
%9 = insertvalue { i8*, i16 } %8, i16 %7, 1
|
||||||
|
ret { i8*, i16 } %9
|
||||||
|
}
|
||||||
|
|
||||||
|
As an optimization, direct calls to native ABI functions will call the
|
||||||
|
native ABI function directly and the pass will compute the appropriate label
|
||||||
|
internally. This has the advantage of reducing the number of union operations
|
||||||
|
required when the return value label is known to be zero (i.e. ``discard``
|
||||||
|
functions, or ``functional`` functions with known unlabelled arguments).
|
||||||
|
|
||||||
|
Checking ABI Consistency
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
DFSan changes the ABI of each function in the module. This makes it possible
|
||||||
|
for a function with the native ABI to be called with the instrumented ABI,
|
||||||
|
or vice versa, thus possibly invoking undefined behavior. A simple way
|
||||||
|
of statically detecting instances of this problem is to prepend the prefix
|
||||||
|
"dfs$" to the name of each instrumented-ABI function.
|
||||||
|
|
||||||
|
This will not catch every such problem; in particular function pointers passed
|
||||||
|
across the instrumented-native barrier cannot be used on the other side.
|
||||||
|
These problems could potentially be caught dynamically.
|
@ -950,17 +950,13 @@ functions, Objective-C methods, C++ constructors, destructors, and operators
|
|||||||
``DeclarationName`` is designed to efficiently represent any kind of name.
|
``DeclarationName`` is designed to efficiently represent any kind of name.
|
||||||
|
|
||||||
Given a ``DeclarationName`` ``N``, ``N.getNameKind()`` will produce a value
|
Given a ``DeclarationName`` ``N``, ``N.getNameKind()`` will produce a value
|
||||||
that describes what kind of name ``N`` stores. There are 8 options (all of the
|
that describes what kind of name ``N`` stores. There are 10 options (all of
|
||||||
names are inside the ``DeclarationName`` class).
|
the names are inside the ``DeclarationName`` class).
|
||||||
|
|
||||||
``Identifier``
|
``Identifier``
|
||||||
|
|
||||||
The name is a simple identifier. Use ``N.getAsIdentifierInfo()`` to retrieve
|
The name is a simple identifier. Use ``N.getAsIdentifierInfo()`` to retrieve
|
||||||
the corresponding ``IdentifierInfo*`` pointing to the actual identifier.
|
the corresponding ``IdentifierInfo*`` pointing to the actual identifier.
|
||||||
Note that C++ overloaded operators (e.g., "``operator+``") are represented as
|
|
||||||
special kinds of identifiers. Use ``IdentifierInfo``'s
|
|
||||||
``getOverloadedOperatorID`` function to determine whether an identifier is an
|
|
||||||
overloaded operator name.
|
|
||||||
|
|
||||||
``ObjCZeroArgSelector``, ``ObjCOneArgSelector``, ``ObjCMultiArgSelector``
|
``ObjCZeroArgSelector``, ``ObjCOneArgSelector``, ``ObjCMultiArgSelector``
|
||||||
|
|
||||||
@ -999,6 +995,21 @@ names are inside the ``DeclarationName`` class).
|
|||||||
Use ``N.getCXXOverloadedOperator()`` to retrieve the overloaded operator (a
|
Use ``N.getCXXOverloadedOperator()`` to retrieve the overloaded operator (a
|
||||||
value of type ``OverloadedOperatorKind``).
|
value of type ``OverloadedOperatorKind``).
|
||||||
|
|
||||||
|
``CXXLiteralOperatorName``
|
||||||
|
|
||||||
|
The name is a C++11 user defined literal operator. User defined
|
||||||
|
Literal operators are named according to the suffix they define,
|
||||||
|
e.g., "``_foo``" for "``operator "" _foo``". Use
|
||||||
|
``N.getCXXLiteralIdentifier()`` to retrieve the corresponding
|
||||||
|
``IdentifierInfo*`` pointing to the identifier.
|
||||||
|
|
||||||
|
``CXXUsingDirective``
|
||||||
|
|
||||||
|
The name is a C++ using directive. Using directives are not really
|
||||||
|
NamedDecls, in that they all have the same name, but they are
|
||||||
|
implemented as such in order to store them in DeclContext
|
||||||
|
effectively.
|
||||||
|
|
||||||
``DeclarationName``\ s are cheap to create, copy, and compare. They require
|
``DeclarationName``\ s are cheap to create, copy, and compare. They require
|
||||||
only a single pointer's worth of storage in the common cases (identifiers,
|
only a single pointer's worth of storage in the common cases (identifiers,
|
||||||
zero- and one-argument Objective-C selectors) and use dense, uniqued storage
|
zero- and one-argument Objective-C selectors) and use dense, uniqued storage
|
||||||
|
@ -7,6 +7,12 @@ AST. It is targeted at developers who either want to contribute to
|
|||||||
Clang, or use tools that work based on Clang's AST, like the AST
|
Clang, or use tools that work based on Clang's AST, like the AST
|
||||||
matchers.
|
matchers.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<center><iframe width="560" height="315" src="http://www.youtube.com/embed/VqCkCDFLSsc?vq=hd720" frameborder="0" allowfullscreen></iframe></center>
|
||||||
|
|
||||||
|
`Slides <http://llvm.org/devmtg/2013-04/klimek-slides.pdf>`_
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
@ -27,9 +33,8 @@ Examining the AST
|
|||||||
=================
|
=================
|
||||||
|
|
||||||
A good way to familarize yourself with the Clang AST is to actually look
|
A good way to familarize yourself with the Clang AST is to actually look
|
||||||
at it on some simple example code. Clang has a builtin AST-dump modes,
|
at it on some simple example code. Clang has a builtin AST-dump mode,
|
||||||
which can be enabled with the flags ``-ast-dump`` and ``-ast-dump-xml``. Note
|
which can be enabled with the flag ``-ast-dump``.
|
||||||
that ``-ast-dump-xml`` currently only works with debug builds of clang.
|
|
||||||
|
|
||||||
Let's look at a simple example AST:
|
Let's look at a simple example AST:
|
||||||
|
|
||||||
@ -41,40 +46,26 @@ Let's look at a simple example AST:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Clang by default is a frontend for many tools; -cc1 tells it to directly
|
# Clang by default is a frontend for many tools; -Xclang is used to pass
|
||||||
# use the C++ compiler mode. -undef leaves out some internal declarations.
|
# options directly to the C++ frontend.
|
||||||
$ clang -cc1 -undef -ast-dump-xml test.cc
|
$ clang -Xclang -ast-dump -fsyntax-only test.cc
|
||||||
|
TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
|
||||||
... cutting out internal declarations of clang ...
|
... cutting out internal declarations of clang ...
|
||||||
<TranslationUnit ptr="0x4871160">
|
`-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
|
||||||
<Function ptr="0x48a5800" name="f" prototype="true">
|
|-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
|
||||||
<FunctionProtoType ptr="0x4871de0" canonical="0x4871de0">
|
`-CompoundStmt 0x5aead88 <col:14, line:4:1>
|
||||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
|-DeclStmt 0x5aead10 <line:2:3, col:24>
|
||||||
<parameters>
|
| `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
|
||||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
| `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
|
||||||
</parameters>
|
| `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
|
||||||
</FunctionProtoType>
|
| |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
|
||||||
<ParmVar ptr="0x4871d80" name="x" initstyle="c">
|
| | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
|
||||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
| `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
|
||||||
</ParmVar>
|
`-ReturnStmt 0x5aead68 <line:3:3, col:10>
|
||||||
<Stmt>
|
`-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
|
||||||
(CompoundStmt 0x48a5a38 <t2.cc:1:14, line:4:1>
|
`-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'
|
||||||
(DeclStmt 0x48a59c0 <line:2:3, col:24>
|
|
||||||
0x48a58c0 "int result =
|
|
||||||
(ParenExpr 0x48a59a0 <col:16, col:23> 'int'
|
|
||||||
(BinaryOperator 0x48a5978 <col:17, col:21> 'int' '/'
|
|
||||||
(ImplicitCastExpr 0x48a5960 <col:17> 'int' <LValueToRValue>
|
|
||||||
(DeclRefExpr 0x48a5918 <col:17> 'int' lvalue ParmVar 0x4871d80 'x' 'int'))
|
|
||||||
(IntegerLiteral 0x48a5940 <col:21> 'int' 42)))")
|
|
||||||
(ReturnStmt 0x48a5a18 <line:3:3, col:10>
|
|
||||||
(ImplicitCastExpr 0x48a5a00 <col:10> 'int' <LValueToRValue>
|
|
||||||
(DeclRefExpr 0x48a59d8 <col:10> 'int' lvalue Var 0x48a58c0 'result' 'int'))))
|
|
||||||
|
|
||||||
</Stmt>
|
The toplevel declaration in
|
||||||
</Function>
|
|
||||||
</TranslationUnit>
|
|
||||||
|
|
||||||
In general, ``-ast-dump-xml`` dumps declarations in an XML-style format and
|
|
||||||
statements in an S-expression-style format. The toplevel declaration in
|
|
||||||
a translation unit is always the `translation unit
|
a translation unit is always the `translation unit
|
||||||
declaration <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_.
|
declaration <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_.
|
||||||
In this example, our first user written declaration is the `function
|
In this example, our first user written declaration is the `function
|
||||||
|
@ -159,12 +159,16 @@ include paths, or 0 otherwise:
|
|||||||
# include "myinclude.h"
|
# include "myinclude.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
To test for this feature, use ``#if defined(__has_include)``:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
// To avoid problem with non-clang compilers not having this macro.
|
// To avoid problem with non-clang compilers not having this macro.
|
||||||
#if defined(__has_include) && __has_include("myinclude.h")
|
#if defined(__has_include)
|
||||||
|
#if __has_include("myinclude.h")
|
||||||
# include "myinclude.h"
|
# include "myinclude.h"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
To test for this feature, use ``#if defined(__has_include)``.
|
|
||||||
|
|
||||||
.. _langext-__has_include_next:
|
.. _langext-__has_include_next:
|
||||||
|
|
||||||
@ -185,9 +189,11 @@ or 0 otherwise:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// To avoid problem with non-clang compilers not having this macro.
|
// To avoid problem with non-clang compilers not having this macro.
|
||||||
#if defined(__has_include_next) && __has_include_next("myinclude.h")
|
#if defined(__has_include_next)
|
||||||
|
#if __has_include_next("myinclude.h")
|
||||||
# include_next "myinclude.h"
|
# include_next "myinclude.h"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
Note that ``__has_include_next``, like the GNU extension ``#include_next``
|
Note that ``__has_include_next``, like the GNU extension ``#include_next``
|
||||||
directive, is intended for use in headers only, and will issue a warning if
|
directive, is intended for use in headers only, and will issue a warning if
|
||||||
@ -801,8 +807,7 @@ Use ``__has_feature(cxx_contextual_conversions)`` or
|
|||||||
``__has_extension(cxx_contextual_conversions)`` to determine if the C++1y rules
|
``__has_extension(cxx_contextual_conversions)`` to determine if the C++1y rules
|
||||||
are used when performing an implicit conversion for an array bound in a
|
are used when performing an implicit conversion for an array bound in a
|
||||||
*new-expression*, the operand of a *delete-expression*, an integral constant
|
*new-expression*, the operand of a *delete-expression*, an integral constant
|
||||||
expression, or a condition in a ``switch`` statement. Clang does not yet
|
expression, or a condition in a ``switch`` statement.
|
||||||
support this feature.
|
|
||||||
|
|
||||||
C++1y decltype(auto)
|
C++1y decltype(auto)
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -821,9 +826,9 @@ for default initializers in aggregate members is enabled.
|
|||||||
C++1y generalized lambda capture
|
C++1y generalized lambda capture
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Use ``__has_feature(cxx_generalized_capture)`` or
|
Use ``__has_feature(cxx_init_capture)`` or
|
||||||
``__has_extension(cxx_generalized_capture`` to determine if support for
|
``__has_extension(cxx_init_capture)`` to determine if support for
|
||||||
generalized lambda captures is enabled
|
lambda captures with explicit initializers is enabled
|
||||||
(for instance, ``[n(0)] { return ++n; }``).
|
(for instance, ``[n(0)] { return ++n; }``).
|
||||||
Clang does not yet support this feature.
|
Clang does not yet support this feature.
|
||||||
|
|
||||||
@ -843,7 +848,6 @@ Use ``__has_feature(cxx_relaxed_constexpr)`` or
|
|||||||
``__has_extension(cxx_relaxed_constexpr)`` to determine if variable
|
``__has_extension(cxx_relaxed_constexpr)`` to determine if variable
|
||||||
declarations, local variable modification, and control flow constructs
|
declarations, local variable modification, and control flow constructs
|
||||||
are permitted in ``constexpr`` functions.
|
are permitted in ``constexpr`` functions.
|
||||||
Clang's implementation of this feature is incomplete.
|
|
||||||
|
|
||||||
C++1y return type deduction
|
C++1y return type deduction
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -852,7 +856,6 @@ Use ``__has_feature(cxx_return_type_deduction)`` or
|
|||||||
``__has_extension(cxx_return_type_deduction)`` to determine if support
|
``__has_extension(cxx_return_type_deduction)`` to determine if support
|
||||||
for return type deduction for functions (using ``auto`` as a return type)
|
for return type deduction for functions (using ``auto`` as a return type)
|
||||||
is enabled.
|
is enabled.
|
||||||
Clang's implementation of this feature is incomplete.
|
|
||||||
|
|
||||||
C++1y runtime-sized arrays
|
C++1y runtime-sized arrays
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -918,8 +921,8 @@ enabled.
|
|||||||
C11 ``_Thread_local``
|
C11 ``_Thread_local``
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Use ``__has_feature(c_thread_local)`` to determine if support for
|
Use ``__has_feature(c_thread_local)`` or ``__has_extension(c_thread_local)``
|
||||||
``_Thread_local`` variables is enabled.
|
to determine if support for ``_Thread_local`` variables is enabled.
|
||||||
|
|
||||||
Checks for Type Traits
|
Checks for Type Traits
|
||||||
======================
|
======================
|
||||||
@ -1173,8 +1176,52 @@ of this feature in version of clang being used.
|
|||||||
|
|
||||||
.. _langext-objc_method_family:
|
.. _langext-objc_method_family:
|
||||||
|
|
||||||
The ``objc_method_family`` attribute
|
|
||||||
------------------------------------
|
Objective-C requiring a call to ``super`` in an override
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
Some Objective-C classes allow a subclass to override a particular method in a
|
||||||
|
parent class but expect that the overriding method also calls the overridden
|
||||||
|
method in the parent class. For these cases, we provide an attribute to
|
||||||
|
designate that a method requires a "call to ``super``" in the overriding
|
||||||
|
method in the subclass.
|
||||||
|
|
||||||
|
**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only
|
||||||
|
be placed at the end of a method declaration:
|
||||||
|
|
||||||
|
.. code-block:: objc
|
||||||
|
|
||||||
|
- (void)foo __attribute__((objc_requires_super));
|
||||||
|
|
||||||
|
This attribute can only be applied the method declarations within a class, and
|
||||||
|
not a protocol. Currently this attribute does not enforce any placement of
|
||||||
|
where the call occurs in the overriding method (such as in the case of
|
||||||
|
``-dealloc`` where the call must appear at the end). It checks only that it
|
||||||
|
exists.
|
||||||
|
|
||||||
|
Note that on both OS X and iOS that the Foundation framework provides a
|
||||||
|
convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this
|
||||||
|
attribute:
|
||||||
|
|
||||||
|
.. code-block:: objc
|
||||||
|
|
||||||
|
- (void)foo NS_REQUIRES_SUPER;
|
||||||
|
|
||||||
|
This macro is conditionally defined depending on the compiler's support for
|
||||||
|
this attribute. If the compiler does not support the attribute the macro
|
||||||
|
expands to nothing.
|
||||||
|
|
||||||
|
Operationally, when a method has this annotation the compiler will warn if the
|
||||||
|
implementation of an override in a subclass does not call super. For example:
|
||||||
|
|
||||||
|
.. code-block:: objc
|
||||||
|
|
||||||
|
warning: method possibly missing a [super AnnotMeth] call
|
||||||
|
- (void) AnnotMeth{};
|
||||||
|
^
|
||||||
|
|
||||||
|
Objective-C Method Families
|
||||||
|
---------------------------
|
||||||
|
|
||||||
Many methods in Objective-C have conventional meanings determined by their
|
Many methods in Objective-C have conventional meanings determined by their
|
||||||
selectors. It is sometimes useful to be able to mark a method as having a
|
selectors. It is sometimes useful to be able to mark a method as having a
|
||||||
@ -1253,6 +1300,21 @@ Query for these features with ``__has_attribute(ns_consumed)``,
|
|||||||
``__has_attribute(ns_returns_retained)``, etc.
|
``__has_attribute(ns_returns_retained)``, etc.
|
||||||
|
|
||||||
|
|
||||||
|
Objective-C++ ABI: protocol-qualifier mangling of parameters
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Starting with LLVM 3.4, Clang produces a new mangling for parameters whose
|
||||||
|
type is a qualified-``id`` (e.g., ``id<Foo>``). This mangling allows such
|
||||||
|
parameters to be differentiated from those with the regular unqualified ``id``
|
||||||
|
type.
|
||||||
|
|
||||||
|
This was a non-backward compatible mangling change to the ABI. This change
|
||||||
|
allows proper overloading, and also prevents mangling conflicts with template
|
||||||
|
parameters of protocol-qualified type.
|
||||||
|
|
||||||
|
Query the presence of this new mangling with
|
||||||
|
``__has_feature(objc_protocol_qualifier_mangling)``.
|
||||||
|
|
||||||
Function Overloading in C
|
Function Overloading in C
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
@ -1411,7 +1473,9 @@ should only be used for timing small intervals. When not supported by the
|
|||||||
target, the return value is always zero. This builtin takes no arguments and
|
target, the return value is always zero. This builtin takes no arguments and
|
||||||
produces an unsigned long long result.
|
produces an unsigned long long result.
|
||||||
|
|
||||||
Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``.
|
Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``. Note
|
||||||
|
that even if present, its use may depend on run-time privilege or other OS
|
||||||
|
controlled state.
|
||||||
|
|
||||||
.. _langext-__builtin_shufflevector:
|
.. _langext-__builtin_shufflevector:
|
||||||
|
|
||||||
@ -1433,8 +1497,8 @@ for the implementation of various target-specific header files like
|
|||||||
|
|
||||||
.. code-block:: c++
|
.. code-block:: c++
|
||||||
|
|
||||||
// Identity operation - return 4-element vector V1.
|
// identity operation - return 4-element vector v1.
|
||||||
__builtin_shufflevector(V1, V1, 0, 1, 2, 3)
|
__builtin_shufflevector(v1, v1, 0, 1, 2, 3)
|
||||||
|
|
||||||
// "Splat" element 0 of V1 into a 4-element result.
|
// "Splat" element 0 of V1 into a 4-element result.
|
||||||
__builtin_shufflevector(V1, V1, 0, 0, 0, 0)
|
__builtin_shufflevector(V1, V1, 0, 0, 0, 0)
|
||||||
@ -1448,6 +1512,9 @@ for the implementation of various target-specific header files like
|
|||||||
// Concatenate every other element of 8-element vectors V1 and V2.
|
// Concatenate every other element of 8-element vectors V1 and V2.
|
||||||
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
|
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
|
||||||
|
|
||||||
|
// Shuffle v1 with some elements being undefined
|
||||||
|
__builtin_shufflevector(v1, v1, 3, -1, 1, -1)
|
||||||
|
|
||||||
**Description**:
|
**Description**:
|
||||||
|
|
||||||
The first two arguments to ``__builtin_shufflevector`` are vectors that have
|
The first two arguments to ``__builtin_shufflevector`` are vectors that have
|
||||||
@ -1456,7 +1523,8 @@ specify the elements indices of the first two vectors that should be extracted
|
|||||||
and returned in a new vector. These element indices are numbered sequentially
|
and returned in a new vector. These element indices are numbered sequentially
|
||||||
starting with the first vector, continuing into the second vector. Thus, if
|
starting with the first vector, continuing into the second vector. Thus, if
|
||||||
``vec1`` is a 4-element vector, index 5 would refer to the second element of
|
``vec1`` is a 4-element vector, index 5 would refer to the second element of
|
||||||
``vec2``.
|
``vec2``. An index of -1 can be used to indicate that the corresponding element
|
||||||
|
in the returned vector is a don't care and can be optimized by the backend.
|
||||||
|
|
||||||
The result of ``__builtin_shufflevector`` is a vector with the same element
|
The result of ``__builtin_shufflevector`` is a vector with the same element
|
||||||
type as ``vec1``/``vec2`` but that has an element count equal to the number of
|
type as ``vec1``/``vec2`` but that has an element count equal to the number of
|
||||||
@ -1464,6 +1532,50 @@ indices specified.
|
|||||||
|
|
||||||
Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
|
Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
|
||||||
|
|
||||||
|
``__builtin_convertvector``
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
``__builtin_convertvector`` is used to express generic vector
|
||||||
|
type-conversion operations. The input vector and the output vector
|
||||||
|
type must have the same number of elements.
|
||||||
|
|
||||||
|
**Syntax**:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
__builtin_convertvector(src_vec, dst_vec_type)
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
typedef double vector4double __attribute__((__vector_size__(32)));
|
||||||
|
typedef float vector4float __attribute__((__vector_size__(16)));
|
||||||
|
typedef short vector4short __attribute__((__vector_size__(8)));
|
||||||
|
vector4float vf; vector4short vs;
|
||||||
|
|
||||||
|
// convert from a vector of 4 floats to a vector of 4 doubles.
|
||||||
|
__builtin_convertvector(vf, vector4double)
|
||||||
|
// equivalent to:
|
||||||
|
(vector4double) { (double) vf[0], (double) vf[1], (double) vf[2], (double) vf[3] }
|
||||||
|
|
||||||
|
// convert from a vector of 4 shorts to a vector of 4 floats.
|
||||||
|
__builtin_convertvector(vs, vector4float)
|
||||||
|
// equivalent to:
|
||||||
|
(vector4float) { (float) vf[0], (float) vf[1], (float) vf[2], (float) vf[3] }
|
||||||
|
|
||||||
|
**Description**:
|
||||||
|
|
||||||
|
The first argument to ``__builtin_convertvector`` is a vector, and the second
|
||||||
|
argument is a vector type with the same number of elements as the first
|
||||||
|
argument.
|
||||||
|
|
||||||
|
The result of ``__builtin_convertvector`` is a vector with the same element
|
||||||
|
type as the second argument, with a value defined in terms of the action of a
|
||||||
|
C-style cast applied to each element of the first argument.
|
||||||
|
|
||||||
|
Query for this feature with ``__has_builtin(__builtin_convertvector)``.
|
||||||
|
|
||||||
``__builtin_unreachable``
|
``__builtin_unreachable``
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
@ -1526,6 +1638,22 @@ correct code by avoiding expensive loops around
|
|||||||
implementation details of ``__sync_lock_test_and_set()``. The
|
implementation details of ``__sync_lock_test_and_set()``. The
|
||||||
``__sync_swap()`` builtin is a full barrier.
|
``__sync_swap()`` builtin is a full barrier.
|
||||||
|
|
||||||
|
``__builtin_addressof``
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
``__builtin_addressof`` performs the functionality of the built-in ``&``
|
||||||
|
operator, ignoring any ``operator&`` overload. This is useful in constant
|
||||||
|
expressions in C++11, where there is no other way to take the address of an
|
||||||
|
object that overloads ``operator&``.
|
||||||
|
|
||||||
|
**Example of use**:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
template<typename T> constexpr T *addressof(T &value) {
|
||||||
|
return __builtin_addressof(value);
|
||||||
|
}
|
||||||
|
|
||||||
Multiprecision Arithmetic Builtins
|
Multiprecision Arithmetic Builtins
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
@ -1554,15 +1682,60 @@ The complete list of builtins are:
|
|||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
|
unsigned char __builtin_addcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
|
||||||
unsigned short __builtin_addcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
|
unsigned short __builtin_addcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
|
||||||
unsigned __builtin_addc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
|
unsigned __builtin_addc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
|
||||||
unsigned long __builtin_addcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
|
unsigned long __builtin_addcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
|
||||||
unsigned long long __builtin_addcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
|
unsigned long long __builtin_addcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
|
||||||
|
unsigned char __builtin_subcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
|
||||||
unsigned short __builtin_subcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
|
unsigned short __builtin_subcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
|
||||||
unsigned __builtin_subc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
|
unsigned __builtin_subc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
|
||||||
unsigned long __builtin_subcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
|
unsigned long __builtin_subcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
|
||||||
unsigned long long __builtin_subcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
|
unsigned long long __builtin_subcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
|
||||||
|
|
||||||
|
Checked Arithmetic Builtins
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Clang provides a set of builtins that implement checked arithmetic for security
|
||||||
|
critical applications in a manner that is fast and easily expressable in C. As
|
||||||
|
an example of their usage:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
errorcode_t security_critical_application(...) {
|
||||||
|
unsigned x, y, result;
|
||||||
|
...
|
||||||
|
if (__builtin_umul_overflow(x, y, &result))
|
||||||
|
return kErrorCodeHackers;
|
||||||
|
...
|
||||||
|
use_multiply(result);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
A complete enumeration of the builtins are:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
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);
|
||||||
|
bool __builtin_usub_overflow (unsigned x, unsigned y, unsigned *diff);
|
||||||
|
bool __builtin_usubl_overflow (unsigned long x, unsigned long y, unsigned long *diff);
|
||||||
|
bool __builtin_usubll_overflow(unsigned long long x, unsigned long long y, unsigned long long *diff);
|
||||||
|
bool __builtin_umul_overflow (unsigned x, unsigned y, unsigned *prod);
|
||||||
|
bool __builtin_umull_overflow (unsigned long x, unsigned long y, unsigned long *prod);
|
||||||
|
bool __builtin_umulll_overflow(unsigned long long x, unsigned long long y, unsigned long long *prod);
|
||||||
|
bool __builtin_sadd_overflow (int x, int y, int *sum);
|
||||||
|
bool __builtin_saddl_overflow (long x, long y, long *sum);
|
||||||
|
bool __builtin_saddll_overflow(long long x, long long y, long long *sum);
|
||||||
|
bool __builtin_ssub_overflow (int x, int y, int *diff);
|
||||||
|
bool __builtin_ssubl_overflow (long x, long y, long *diff);
|
||||||
|
bool __builtin_ssubll_overflow(long long x, long long y, long long *diff);
|
||||||
|
bool __builtin_smul_overflow (int x, int y, int *prod);
|
||||||
|
bool __builtin_smull_overflow (long x, long y, long *prod);
|
||||||
|
bool __builtin_smulll_overflow(long long x, long long y, long long *prod);
|
||||||
|
|
||||||
|
|
||||||
.. _langext-__c11_atomic:
|
.. _langext-__c11_atomic:
|
||||||
|
|
||||||
__c11_atomic builtins
|
__c11_atomic builtins
|
||||||
@ -1588,6 +1761,37 @@ C11's ``<stdatomic.h>`` header. These builtins provide the semantics of the
|
|||||||
* ``__c11_atomic_fetch_or``
|
* ``__c11_atomic_fetch_or``
|
||||||
* ``__c11_atomic_fetch_xor``
|
* ``__c11_atomic_fetch_xor``
|
||||||
|
|
||||||
|
Low-level ARM exclusive memory builtins
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
Clang provides overloaded builtins giving direct access to the three key ARM
|
||||||
|
instructions for implementing atomic operations.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
T __builtin_arm_ldrex(const volatile T *addr);
|
||||||
|
int __builtin_arm_strex(T val, volatile T *addr);
|
||||||
|
void __builtin_arm_clrex(void);
|
||||||
|
|
||||||
|
The types ``T`` currently supported are:
|
||||||
|
* Integer types with width at most 64 bits.
|
||||||
|
* Floating-point types
|
||||||
|
* Pointer types.
|
||||||
|
|
||||||
|
Note that the compiler does not guarantee it will not insert stores which clear
|
||||||
|
the exclusive monitor in between an ``ldrex`` and its paired ``strex``. In
|
||||||
|
practice this is only usually a risk when the extra store is on the same cache
|
||||||
|
line as the variable being modified and Clang will only insert stack stores on
|
||||||
|
its own, so it is best not to use these operations on variables with automatic
|
||||||
|
storage duration.
|
||||||
|
|
||||||
|
Also, loads and stores may be implicit in code written between the ``ldrex`` and
|
||||||
|
``strex``. Clang will not necessarily mitigate the effects of these either, so
|
||||||
|
care should be exercised.
|
||||||
|
|
||||||
|
For these reasons the higher level atomic primitives should be preferred where
|
||||||
|
possible.
|
||||||
|
|
||||||
Non-standard C++11 Attributes
|
Non-standard C++11 Attributes
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
@ -1649,7 +1853,7 @@ are accepted with the ``__attribute__((foo))`` syntax are also accepted as
|
|||||||
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_, `GCC variable
|
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_, `GCC variable
|
||||||
attributes <http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html>`_, and
|
attributes <http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html>`_, and
|
||||||
`GCC type attributes
|
`GCC type attributes
|
||||||
<http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html>`_. As with the GCC
|
<http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html>`_). As with the GCC
|
||||||
implementation, these attributes must appertain to the *declarator-id* in a
|
implementation, these attributes must appertain to the *declarator-id* in a
|
||||||
declaration, which means they must go either at the start of the declaration or
|
declaration, which means they must go either at the start of the declaration or
|
||||||
immediately after the name being declared.
|
immediately after the name being declared.
|
||||||
@ -1698,6 +1902,48 @@ Which compiles to (on X86-32):
|
|||||||
movl %gs:(%eax), %eax
|
movl %gs:(%eax), %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
ARM Language Extensions
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Interrupt attribute
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on
|
||||||
|
ARM 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.
|
||||||
|
|
||||||
|
The parameter passed to the interrupt attribute is optional, but if
|
||||||
|
provided it must be a string literal with one of the following values: "IRQ",
|
||||||
|
"FIQ", "SWI", "ABORT", "UNDEF".
|
||||||
|
|
||||||
|
The semantics are as follows:
|
||||||
|
|
||||||
|
- If the function is AAPCS, Clang instructs the backend to realign the stack to
|
||||||
|
8 bytes on entry. This is a general requirement of the AAPCS at public
|
||||||
|
interfaces, but may not hold when an exception is taken. Doing this allows
|
||||||
|
other AAPCS functions to be called.
|
||||||
|
- If the CPU is M-class this is all that needs to be done since the architecture
|
||||||
|
itself is designed in such a way that functions obeying the normal AAPCS ABI
|
||||||
|
constraints are valid exception handlers.
|
||||||
|
- If the CPU is not M-class, the prologue and epilogue are modified to save all
|
||||||
|
non-banked registers that are used, so that upon return the user-mode state
|
||||||
|
will not be corrupted. Note that to avoid unnecessary overhead, only
|
||||||
|
general-purpose (integer) registers are saved in this way. If VFP operations
|
||||||
|
are needed, that state must be saved manually.
|
||||||
|
|
||||||
|
Specifically, interrupt kinds other than "FIQ" will save all core registers
|
||||||
|
except "lr" and "sp". "FIQ" interrupts will save r0-r7.
|
||||||
|
- If the CPU is not M-class, the return instruction is changed to one of the
|
||||||
|
canonical sequences permitted by the architecture for exception return. Where
|
||||||
|
possible the function itself will make the necessary "lr" adjustments so that
|
||||||
|
the "preferred return address" is selected.
|
||||||
|
|
||||||
|
Unfortunately the compiler is unable to make this guarantee for an "UNDEF"
|
||||||
|
handler, where the offset from "lr" to the preferred return address depends on
|
||||||
|
the execution state of the code which generated the exception. In this case
|
||||||
|
a sequence equivalent to "movs pc, lr" will be used.
|
||||||
|
|
||||||
Extensions for Static Analysis
|
Extensions for Static Analysis
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
@ -1735,8 +1981,8 @@ with :doc:`ThreadSanitizer`.
|
|||||||
Use ``__attribute__((no_sanitize_thread))`` on a function declaration
|
Use ``__attribute__((no_sanitize_thread))`` on a function declaration
|
||||||
to specify that checks for data races on plain (non-atomic) memory accesses
|
to specify that checks for data races on plain (non-atomic) memory accesses
|
||||||
should not be inserted by ThreadSanitizer.
|
should not be inserted by ThreadSanitizer.
|
||||||
The function may still be instrumented by the tool
|
The function is still instrumented by the tool to avoid false positives and
|
||||||
to avoid false positives in other places.
|
provide meaningful stack traces.
|
||||||
|
|
||||||
.. _langext-memory_sanitizer:
|
.. _langext-memory_sanitizer:
|
||||||
|
|
||||||
@ -1905,15 +2151,72 @@ to specify that the function must be called while holding the listed shared
|
|||||||
locks. Arguments must be lockable type, and there must be at least one
|
locks. Arguments must be lockable type, and there must be at least one
|
||||||
argument.
|
argument.
|
||||||
|
|
||||||
|
Consumed Annotation Checking
|
||||||
|
============================
|
||||||
|
|
||||||
|
Clang supports additional attributes for checking basic resource management
|
||||||
|
properties, specifically for unique objects that have a single owning reference.
|
||||||
|
The following attributes are currently supported, although **the implementation
|
||||||
|
for these annotations is currently in development and are subject to change.**
|
||||||
|
|
||||||
|
``consumable``
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Each class that uses any of the following annotations must first be marked
|
||||||
|
using the consumable attribute. Failure to do so will result in a warning.
|
||||||
|
|
||||||
|
``set_typestate(new_state)``
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Annotate methods that transition an object into a new state with
|
||||||
|
``__attribute__((set_typestate(new_state)))``. The new new state must be
|
||||||
|
unconsumed, consumed, or unknown.
|
||||||
|
|
||||||
|
``callable_when(...)``
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Use ``__attribute__((callable_when(...)))`` to indicate what states a method
|
||||||
|
may be called in. Valid states are unconsumed, consumed, or unknown. Each
|
||||||
|
argument to this attribute must be a quoted string. E.g.:
|
||||||
|
|
||||||
|
``__attribute__((callable_when("unconsumed", "unknown")))``
|
||||||
|
|
||||||
|
``tests_typestate(tested_state)``
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Use ``__attribute__((tests_typestate(tested_state)))`` to indicate that a method
|
||||||
|
returns true if the object is in the specified state..
|
||||||
|
|
||||||
|
``param_typestate(expected_state)``
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
This attribute specifies expectations about function parameters. Calls to an
|
||||||
|
function with annotated parameters will issue a warning if the corresponding
|
||||||
|
argument isn't in the expected state. The attribute is also used to set the
|
||||||
|
initial state of the parameter when analyzing the function's body.
|
||||||
|
|
||||||
|
``return_typestate(ret_state)``
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The ``return_typestate`` attribute can be applied to functions or parameters.
|
||||||
|
When applied to a function the attribute specifies the state of the returned
|
||||||
|
value. The function's body is checked to ensure that it always returns a value
|
||||||
|
in the specified state. On the caller side, values returned by the annotated
|
||||||
|
function are initialized to the given state.
|
||||||
|
|
||||||
|
If the attribute is applied to a function parameter it modifies the state of
|
||||||
|
an argument after a call to the function returns. The function's body is
|
||||||
|
checked to ensure that the parameter is in the expected state before returning.
|
||||||
|
|
||||||
Type Safety Checking
|
Type Safety Checking
|
||||||
====================
|
====================
|
||||||
|
|
||||||
Clang supports additional attributes to enable checking type safety properties
|
Clang supports additional attributes to enable checking type safety properties
|
||||||
that can't be enforced by C type system. Usecases include:
|
that can't be enforced by the C type system. Use cases include:
|
||||||
|
|
||||||
* MPI library implementations, where these attributes enable checking that
|
* MPI library implementations, where these attributes enable checking that
|
||||||
buffer type matches the passed ``MPI_Datatype``;
|
the buffer type matches the passed ``MPI_Datatype``;
|
||||||
* for HDF5 library there is a similar usecase as MPI;
|
* for HDF5 library there is a similar use case to MPI;
|
||||||
* checking types of variadic functions' arguments for functions like
|
* checking types of variadic functions' arguments for functions like
|
||||||
``fcntl()`` and ``ioctl()``.
|
``fcntl()`` and ``ioctl()``.
|
||||||
|
|
||||||
@ -1948,7 +2251,7 @@ accepts a type tag that determines the type of some other argument.
|
|||||||
applicable type tags.
|
applicable type tags.
|
||||||
|
|
||||||
This attribute is primarily useful for checking arguments of variadic functions
|
This attribute is primarily useful for checking arguments of variadic functions
|
||||||
(``pointer_with_type_tag`` can be used in most of non-variadic cases).
|
(``pointer_with_type_tag`` can be used in most non-variadic cases).
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
32
docs/LeakSanitizer.rst
Normal file
32
docs/LeakSanitizer.rst
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
================
|
||||||
|
LeakSanitizer
|
||||||
|
================
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
LeakSanitizer is a run-time memory leak detector. It can be combined with
|
||||||
|
:doc:`AddressSanitizer` to get both memory error and leak detection.
|
||||||
|
LeakSanitizer does not introduce any additional slowdown when used in this mode.
|
||||||
|
The LeakSanitizer runtime can also be linked in separately to get leak detection
|
||||||
|
only, at a minimal performance cost.
|
||||||
|
|
||||||
|
Current status
|
||||||
|
==============
|
||||||
|
|
||||||
|
LeakSanitizer is experimental and supported only on x86\_64 Linux.
|
||||||
|
|
||||||
|
The combined mode has been tested on fairly large software projects. The
|
||||||
|
stand-alone mode has received much less testing.
|
||||||
|
|
||||||
|
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>`_
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -176,7 +176,7 @@ Builtin includes
|
|||||||
|
|
||||||
Clang tools need their builtin headers and search for them the same way Clang
|
Clang tools need their builtin headers and search for them the same way Clang
|
||||||
does. Thus, the default location to look for builtin headers is in a path
|
does. Thus, the default location to look for builtin headers is in a path
|
||||||
``$(dirname /path/to/tool)/../lib/clang/3.3/include`` relative to the tool
|
``$(dirname /path/to/tool)/../lib/clang/3.4/include`` relative to the tool
|
||||||
binary. This works out-of-the-box for tools running from llvm's toplevel
|
binary. This works out-of-the-box for tools running from llvm's toplevel
|
||||||
binary directory after building clang-headers, or if the tool is running from
|
binary directory after building clang-headers, or if the tool is running from
|
||||||
the binary directory of a clang install next to the clang binary.
|
the binary directory of a clang install next to the clang binary.
|
||||||
|
@ -19,7 +19,12 @@ $(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
|
|||||||
-e 's/@abs_srcdir@/./g' \
|
-e 's/@abs_srcdir@/./g' \
|
||||||
-e 's/@DOT@/dot/g' \
|
-e 's/@DOT@/dot/g' \
|
||||||
-e 's/@PACKAGE_VERSION@/mainline/' \
|
-e 's/@PACKAGE_VERSION@/mainline/' \
|
||||||
-e 's/@abs_builddir@/./g' > $@
|
-e 's/@abs_builddir@/./g' \
|
||||||
|
-e 's/@enable_searchengine@/NO/g' \
|
||||||
|
-e 's/@searchengine_url@//g' \
|
||||||
|
-e 's/@enable_server_based_search@/NO/g' \
|
||||||
|
-e 's/@enable_external_search@/NO/g' \
|
||||||
|
-e 's/@extra_search_mappings@//g' > $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(CLANG_LEVEL)/Makefile
|
include $(CLANG_LEVEL)/Makefile
|
||||||
@ -73,10 +78,10 @@ doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
|
|||||||
|
|
||||||
regendoc:
|
regendoc:
|
||||||
$(Echo) Building doxygen documentation
|
$(Echo) Building doxygen documentation
|
||||||
$(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \
|
$(Verb) $(RM) -rf $(PROJ_OBJ_DIR)/doxygen
|
||||||
$(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
|
|
||||||
fi
|
|
||||||
$(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
|
$(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||||
|
$(Verb) sed -i "s/[$$]LatestRev[$$]/`svnversion $(PROJ_SRC_DIR)`/g" \
|
||||||
|
$(PROJ_OBJ_DIR)/doxygen/html/*.html
|
||||||
|
|
||||||
$(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
|
$(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||||
$(Echo) Packaging doxygen documentation
|
$(Echo) Packaging doxygen documentation
|
||||||
|
@ -90,8 +90,16 @@ to disable uninitialized checks in a particular function.
|
|||||||
MemorySanitizer may still instrument such functions to avoid false positives.
|
MemorySanitizer may still instrument such functions to avoid false positives.
|
||||||
This attribute may not be
|
This attribute may not be
|
||||||
supported by other compilers, so we suggest to use it together with
|
supported by other compilers, so we suggest to use it together with
|
||||||
``__has_feature(memory_sanitizer)``. Note: currently, this attribute will be
|
``__has_feature(memory_sanitizer)``.
|
||||||
lost if the function is inlined.
|
|
||||||
|
Blacklist
|
||||||
|
---------
|
||||||
|
|
||||||
|
MemorySanitizer supports ``src`` and ``fun`` entity types in
|
||||||
|
:doc:`SanitizerSpecialCaseList`, that can be used to relax MemorySanitizer
|
||||||
|
checks for certain source files and functions. All "Use of uninitialized value"
|
||||||
|
warnings will be suppressed and all values loaded from memory will be
|
||||||
|
considered fully initialized.
|
||||||
|
|
||||||
Origin Tracking
|
Origin Tracking
|
||||||
===============
|
===============
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
Modules
|
Modules
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
The functionality described on this page is supported for C and
|
||||||
|
Objective-C. C++ support is experimental.
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
:local:
|
:local:
|
||||||
|
|
||||||
.. warning::
|
|
||||||
The functionality described on this page is still experimental! Please
|
|
||||||
try it out and send us bug reports!
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
Most software is built using a number of software libraries, including libraries supplied by the platform, internal libraries built as part of the software itself to provide structure, and third-party libraries. For each library, one needs to access both its interface (API) and its implementation. In the C family of languages, the interface to a library is accessed by including the appropriate header files(s):
|
Most software is built using a number of software libraries, including libraries supplied by the platform, internal libraries built as part of the software itself to provide structure, and third-party libraries. For each library, one needs to access both its interface (API) and its implementation. In the C family of languages, the interface to a library is accessed by including the appropriate header files(s):
|
||||||
@ -106,24 +106,25 @@ Using Modules
|
|||||||
=============
|
=============
|
||||||
To enable modules, pass the command-line flag ``-fmodules`` [#]_. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later.
|
To enable modules, pass the command-line flag ``-fmodules`` [#]_. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later.
|
||||||
|
|
||||||
Import declaration
|
Objective-C Import declaration
|
||||||
------------------
|
------------------------------
|
||||||
The most direct way to import a module is with an *import declaration*, which imports the named module:
|
Objective-C provides syntax for importing a module via an *@import declaration*, which imports the named module:
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
import std;
|
@import std;
|
||||||
|
|
||||||
The import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
|
The @import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
import std.io;
|
@import std.io;
|
||||||
|
|
||||||
Redundant import declarations are ignored, and one is free to import modules at any point within the translation unit, so long as the import declaration is at global scope.
|
Redundant import declarations are ignored, and one is free to import modules at any point within the translation unit, so long as the import declaration is at global scope.
|
||||||
|
|
||||||
.. warning::
|
At present, there is no C or C++ syntax for import declarations. Clang
|
||||||
The import declaration syntax described here does not actually exist. Rather, it is a straw man proposal that may very well change when modules are discussed in the C and C++ committees. See the section `Includes as imports`_ to see how modules get imported today.
|
will track the modules proposal in the C++ committee. See the section
|
||||||
|
`Includes as imports`_ to see how modules get imported today.
|
||||||
|
|
||||||
Includes as imports
|
Includes as imports
|
||||||
-------------------
|
-------------------
|
||||||
@ -148,6 +149,8 @@ Module maps are specified as separate files (each named ``module.map``) alongsid
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps.
|
To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps.
|
||||||
|
|
||||||
|
One can use module maps without modules to check the integrity of the use of header files. To do this, use the ``-fmodule-maps`` option instead of the ``-fmodules`` option.
|
||||||
|
|
||||||
Compilation model
|
Compilation model
|
||||||
-----------------
|
-----------------
|
||||||
@ -165,6 +168,9 @@ Command-line parameters
|
|||||||
``-fcxx-modules``
|
``-fcxx-modules``
|
||||||
Enable the modules feature for C++ (EXPERIMENTAL and VERY BROKEN).
|
Enable the modules feature for C++ (EXPERIMENTAL and VERY BROKEN).
|
||||||
|
|
||||||
|
``-fmodule-maps``
|
||||||
|
Enable interpretation of module maps (EXPERIMENTAL). This option is implied by ``-fmodules``.
|
||||||
|
|
||||||
``-fmodules-cache-path=<directory>``
|
``-fmodules-cache-path=<directory>``
|
||||||
Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default.
|
Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default.
|
||||||
|
|
||||||
@ -183,6 +189,15 @@ Command-line parameters
|
|||||||
``-module-file-info <module file name>``
|
``-module-file-info <module file name>``
|
||||||
Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with.
|
Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with.
|
||||||
|
|
||||||
|
``-fmodules-decluse``
|
||||||
|
Enable checking of module ``use`` declarations.
|
||||||
|
|
||||||
|
``-fmodule-name=module-id``
|
||||||
|
Consider a source file as a part of the given module.
|
||||||
|
|
||||||
|
``-fmodule-map-file=<file>``
|
||||||
|
Load the given module map file if a header from its directory or one of its subdirectories is loaded.
|
||||||
|
|
||||||
Module Map Language
|
Module Map Language
|
||||||
===================
|
===================
|
||||||
|
|
||||||
@ -231,8 +246,9 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
|
|||||||
|
|
||||||
``config_macros`` ``export`` ``module``
|
``config_macros`` ``export`` ``module``
|
||||||
``conflict`` ``framework`` ``requires``
|
``conflict`` ``framework`` ``requires``
|
||||||
``exclude`` ``header`` ``umbrella``
|
``exclude`` ``header`` ``private``
|
||||||
``explicit`` ``link``
|
``explicit`` ``link`` ``umbrella``
|
||||||
|
``extern`` ``use``
|
||||||
|
|
||||||
Module map file
|
Module map file
|
||||||
---------------
|
---------------
|
||||||
@ -258,6 +274,7 @@ A module declaration describes a module, including the headers that contribute t
|
|||||||
|
|
||||||
*module-declaration*:
|
*module-declaration*:
|
||||||
``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}'
|
``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}'
|
||||||
|
``extern`` ``module`` *module-id* *string-literal*
|
||||||
|
|
||||||
The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition.
|
The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition.
|
||||||
|
|
||||||
@ -286,10 +303,13 @@ Modules can have a number of different kinds of members, each of which is descri
|
|||||||
*umbrella-dir-declaration*
|
*umbrella-dir-declaration*
|
||||||
*submodule-declaration*
|
*submodule-declaration*
|
||||||
*export-declaration*
|
*export-declaration*
|
||||||
|
*use-declaration*
|
||||||
*link-declaration*
|
*link-declaration*
|
||||||
*config-macros-declaration*
|
*config-macros-declaration*
|
||||||
*conflict-declaration*
|
*conflict-declaration*
|
||||||
|
|
||||||
|
An extern module references a module defined by the *module-id* in a file given by the *string-literal*. The file can be referenced either by an absolute path or by a path relative to the current map file.
|
||||||
|
|
||||||
Requires declaration
|
Requires declaration
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
A *requires-declaration* specifies the requirements that an importing translation unit must satisfy to use the module.
|
A *requires-declaration* specifies the requirements that an importing translation unit must satisfy to use the module.
|
||||||
@ -300,9 +320,12 @@ A *requires-declaration* specifies the requirements that an importing translatio
|
|||||||
``requires`` *feature-list*
|
``requires`` *feature-list*
|
||||||
|
|
||||||
*feature-list*:
|
*feature-list*:
|
||||||
*identifier* (',' *identifier*)*
|
*feature* (',' *feature*)*
|
||||||
|
|
||||||
The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module.
|
*feature*:
|
||||||
|
``!``:sub:`opt` *identifier*
|
||||||
|
|
||||||
|
The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module. The optional ``!`` indicates that a feature is incompatible with the module.
|
||||||
|
|
||||||
The following features are defined:
|
The following features are defined:
|
||||||
|
|
||||||
@ -360,6 +383,7 @@ A header declaration specifies that a particular header is associated with the e
|
|||||||
|
|
||||||
*header-declaration*:
|
*header-declaration*:
|
||||||
``umbrella``:sub:`opt` ``header`` *string-literal*
|
``umbrella``:sub:`opt` ``header`` *string-literal*
|
||||||
|
``private`` ``header`` *string-literal*
|
||||||
``exclude`` ``header`` *string-literal*
|
``exclude`` ``header`` *string-literal*
|
||||||
|
|
||||||
A header declaration that does not contain ``exclude`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule.
|
A header declaration that does not contain ``exclude`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule.
|
||||||
@ -372,6 +396,8 @@ A header with the ``umbrella`` specifier is called an umbrella header. An umbrel
|
|||||||
``-Wincomplete-umbrella`` warning option to ask Clang to complain
|
``-Wincomplete-umbrella`` warning option to ask Clang to complain
|
||||||
about headers not covered by the umbrella header or the module map.
|
about headers not covered by the umbrella header or the module map.
|
||||||
|
|
||||||
|
A header with the ``private`` specifier may not be included from outside the module itself.
|
||||||
|
|
||||||
A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module.
|
A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module.
|
||||||
|
|
||||||
**Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings).
|
**Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings).
|
||||||
@ -521,6 +547,36 @@ Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard e
|
|||||||
compatibility for programs that rely on transitive inclusion (i.e.,
|
compatibility for programs that rely on transitive inclusion (i.e.,
|
||||||
all of them).
|
all of them).
|
||||||
|
|
||||||
|
Use declaration
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
A *use-declaration* specifies one of the other modules that the module is allowed to use. An import or include not matching one of these is rejected when the option *-fmodules-decluse*.
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
*use-declaration*:
|
||||||
|
``use`` *module-id*
|
||||||
|
|
||||||
|
**Example**:: In the following example, use of A from C is not declared, so will trigger a warning.
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
module A {
|
||||||
|
header "a.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
module B {
|
||||||
|
header "b.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
module C {
|
||||||
|
header "c.h"
|
||||||
|
use B
|
||||||
|
}
|
||||||
|
|
||||||
|
When compiling a source file that implements a module, use the option ``-fmodule-name=``module-id to indicate that the source file is logically part of that module.
|
||||||
|
|
||||||
|
The compiler at present only applies restrictions to the module directly being built.
|
||||||
|
|
||||||
Link declaration
|
Link declaration
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.
|
A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.
|
||||||
|
@ -218,12 +218,6 @@ character data is valid. Passing ``NULL`` as the character pointer will
|
|||||||
raise an exception at runtime. When possible, the compiler will reject
|
raise an exception at runtime. When possible, the compiler will reject
|
||||||
``NULL`` character pointers used in boxed expressions.
|
``NULL`` character pointers used in boxed expressions.
|
||||||
|
|
||||||
Availability
|
|
||||||
------------
|
|
||||||
|
|
||||||
Boxed expressions will be available in clang 3.2. It is not currently
|
|
||||||
available in any Apple compiler.
|
|
||||||
|
|
||||||
Container Literals
|
Container Literals
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
@ -1,40 +1,56 @@
|
|||||||
=======================
|
=======================
|
||||||
Clang 3.3 Release Notes
|
Clang 3.4 Release Notes
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
:local:
|
:local:
|
||||||
:depth: 2
|
:depth: 2
|
||||||
|
|
||||||
Written by the `LLVM Team <http://llvm.org/>`_
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
This document contains the release notes for the Clang C/C++/Objective-C
|
This document contains the release notes for the Clang C/C++/Objective-C
|
||||||
frontend, part of the LLVM Compiler Infrastructure, release 3.3. Here we
|
frontend, part of the LLVM Compiler Infrastructure, release 3.4. Here we
|
||||||
describe the status of Clang in some detail, including major improvements from
|
describe the status of Clang in some detail, including major
|
||||||
the previous release and new feature work. For the general LLVM release notes,
|
improvements from the previous release and new feature work. For the
|
||||||
see `the LLVM documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
|
general LLVM release notes, see `the LLVM
|
||||||
releases may be downloaded from the `LLVM releases web site
|
documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
|
||||||
<http://llvm.org/releases/>`_.
|
releases may be downloaded from the `LLVM releases web
|
||||||
|
site <http://llvm.org/releases/>`_.
|
||||||
|
|
||||||
For more information about Clang or LLVM, including information about the latest
|
For more information about Clang or LLVM, including information about
|
||||||
release, please check out the main please see the `Clang Web Site
|
the latest release, please check out the main `Clang Web
|
||||||
<http://clang.llvm.org>`_ or the `LLVM Web Site <http://llvm.org>`_.
|
Site <http://clang.llvm.org>`_ or the `LLVM Web
|
||||||
|
Site <http://llvm.org>`_.
|
||||||
|
|
||||||
Note that if you are reading this file from a Subversion checkout or the main
|
Note that if you are reading this file from a Subversion checkout or the
|
||||||
Clang web page, this document applies to the *next* release, not the current
|
main Clang web page, this document applies to the *next* release, not
|
||||||
one. To see the release notes for a specific release, please see the `releases
|
the current one. To see the release notes for a specific release, please
|
||||||
page <http://llvm.org/releases/>`_.
|
see the `releases page <http://llvm.org/releases/>`_.
|
||||||
|
|
||||||
What's New in Clang 3.3?
|
What's New in Clang 3.4?
|
||||||
========================
|
========================
|
||||||
|
|
||||||
Some of the major new features and improvements to Clang are listed
|
Some of the major new features and improvements to Clang are listed
|
||||||
here. Generic improvements to Clang as a whole or to its underlying
|
here. Generic improvements to Clang as a whole or to its underlying
|
||||||
infrastructure are described first, followed by language-specific sections with
|
infrastructure are described first, followed by language-specific
|
||||||
improvements to Clang's support for those languages.
|
sections with improvements to Clang's support for those languages.
|
||||||
|
|
||||||
|
Last release which will build as C++98
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
This is expected to be the last release of Clang which compiles using a C++98
|
||||||
|
toolchain. We expect to start using some C++11 features in Clang starting after
|
||||||
|
this release. That said, we are committed to supporting a reasonable set of
|
||||||
|
modern C++ toolchains as the host compiler on all of the platforms. This will
|
||||||
|
at least include Visual Studio 2012 on Windows, and Clang 3.1 or GCC 4.7.x on
|
||||||
|
Mac and Linux. The final set of compilers (and the C++11 features they support)
|
||||||
|
is not set in stone, but we wanted users of Clang to have a heads up that the
|
||||||
|
next release will involve a substantial change in the host toolchain
|
||||||
|
requirements.
|
||||||
|
|
||||||
|
Note that this change is part of a change for the entire LLVM project, not just
|
||||||
|
Clang.
|
||||||
|
|
||||||
Major New Features
|
Major New Features
|
||||||
------------------
|
------------------
|
||||||
@ -44,90 +60,210 @@ Improvements to Clang's diagnostics
|
|||||||
|
|
||||||
Clang's diagnostics are constantly being improved to catch more issues,
|
Clang's diagnostics are constantly being improved to catch more issues,
|
||||||
explain them more clearly, and provide more accurate source information
|
explain them more clearly, and provide more accurate source information
|
||||||
about them. The improvements since the 3.2 release include:
|
about them. The improvements since the 3.3 release include:
|
||||||
|
|
||||||
Extended Identifiers: Unicode Support and Universal Character Names
|
- -Wheader-guard warns on mismatches between the #ifndef and #define lines
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
in a header guard.
|
||||||
|
|
||||||
Clang 3.3 includes support for *extended identifiers* in C99 and C++.
|
.. code-block:: c
|
||||||
This feature allows identifiers to contain certain Unicode characters, as
|
|
||||||
specified by the active language standard; these characters can be written
|
#ifndef multiple
|
||||||
directly in the source file using the UTF-8 encoding, or referred to using
|
#define multi
|
||||||
*universal character names* (``\u00E0``, ``\U000000E0``).
|
#endif
|
||||||
|
|
||||||
|
returns
|
||||||
|
`warning: 'multiple' is used as a header guard here, followed by #define of a different macro [-Wheader-guard]`
|
||||||
|
|
||||||
|
- -Wlogical-not-parentheses warns when a logical not ('!') only applies to the
|
||||||
|
left-hand side of a comparison. This warning is part of -Wparentheses.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
int i1 = 0, i2 = 1;
|
||||||
|
bool ret;
|
||||||
|
ret = !i1 == i2;
|
||||||
|
|
||||||
|
returns
|
||||||
|
`warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses]`
|
||||||
|
|
||||||
|
|
||||||
|
- Boolean increment, a deprecated feature, has own warning flag
|
||||||
|
-Wdeprecated-increment-bool, and is still part of -Wdeprecated.
|
||||||
|
- Clang errors on builtin enum increments and decrements.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
enum A { A1, A2 };
|
||||||
|
void test() {
|
||||||
|
A a;
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
returns
|
||||||
|
`error: must use 'enum' tag to refer to type 'A'`
|
||||||
|
|
||||||
|
|
||||||
|
- -Wloop-analysis now warns on for-loops which have the same increment or
|
||||||
|
decrement in the loop header as the last statement in the loop.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void foo(char *a, char *b, unsigned c) {
|
||||||
|
for (unsigned i = 0; i < c; ++i) {
|
||||||
|
a[i] = b[i];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
returns
|
||||||
|
`warning: variable 'i' is incremented both in the loop header and in the loop body [-Wloop-analysis]`
|
||||||
|
|
||||||
|
- -Wuninitialized now performs checking across field initializers to detect
|
||||||
|
when one field in used uninitialized in another field initialization.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
class A {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
A() : x(y) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
returns
|
||||||
|
`warning: field 'y' is uninitialized when used here [-Wuninitialized]`
|
||||||
|
|
||||||
|
- Clang can detect initializer list use inside a macro and suggest parentheses
|
||||||
|
if possible to fix.
|
||||||
|
- Many improvements to Clang's typo correction facilities, such as:
|
||||||
|
|
||||||
|
+ Adding global namespace qualifiers so that corrections can refer to shadowed
|
||||||
|
or otherwise ambiguous or unreachable namespaces.
|
||||||
|
+ Including accessible class members in the set of typo correction candidates,
|
||||||
|
so that corrections requiring a class name in the name specifier are now
|
||||||
|
possible.
|
||||||
|
+ Allowing typo corrections that involve removing a name specifier.
|
||||||
|
+ In some situations, correcting function names when a function was given the
|
||||||
|
wrong number of arguments, including situations where the original function
|
||||||
|
name was correct but was shadowed by a lexically closer function with the
|
||||||
|
same name yet took a different number of arguments.
|
||||||
|
+ Offering typo suggestions for 'using' declarations.
|
||||||
|
+ Providing better diagnostics and fixit suggestions in more situations when
|
||||||
|
a '->' was used instead of '.' or vice versa.
|
||||||
|
+ Providing more relevant suggestions for typos followed by '.' or '='.
|
||||||
|
+ Various performance improvements when searching for typo correction
|
||||||
|
candidates.
|
||||||
|
|
||||||
|
- `LeakSanitizer <LeakSanitizer.html>`_ is an experimental memory leak detector
|
||||||
|
which can be combined with AddressSanitizer.
|
||||||
|
|
||||||
|
New Compiler Flags
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- Clang no longer special cases -O4 to enable lto. Explicitly pass -flto to
|
||||||
|
enable it.
|
||||||
|
- Clang no longer fails on >= -O5. These flags are mapped to -O3 instead.
|
||||||
|
- Command line "clang -O3 -flto a.c -c" and "clang -emit-llvm a.c -c"
|
||||||
|
are no longer equivalent.
|
||||||
|
- Clang now errors on unknown -m flags (``-munknown-to-clang``),
|
||||||
|
unknown -f flags (``-funknown-to-clang``) and unknown
|
||||||
|
options (``-what-is-this``).
|
||||||
|
|
||||||
C Language Changes in Clang
|
C Language Changes in Clang
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
- Added new checked arithmetic builtins for security critical applications.
|
||||||
|
|
||||||
C++ Language Changes in Clang
|
C++ Language Changes in Clang
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
- Clang now correctly implements language linkage for functions and variables.
|
- Fixed an ABI regression, introduced in Clang 3.2, which affected
|
||||||
This means that, for example, it is now possible to overload static functions
|
member offsets for classes inheriting from certain classes with tail padding.
|
||||||
declared in an ``extern "C"`` context. For backwards compatibility, an alias
|
See PR16537.
|
||||||
with the unmangled name is still emitted if it is the only one and has the
|
|
||||||
``used`` attribute.
|
- Clang 3.4 supports the 2013-08-28 draft of the ISO WG21 SG10 feature test
|
||||||
|
macro recommendations. These aim to provide a portable method to determine
|
||||||
|
whether a compiler supports a language feature, much like Clang's
|
||||||
|
|has_feature macro|_.
|
||||||
|
|
||||||
|
.. |has_feature macro| replace:: ``__has_feature`` macro
|
||||||
|
.. _has_feature macro: LanguageExtensions.html#has-feature-and-has-extension
|
||||||
|
|
||||||
|
C++1y Feature Support
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Clang 3.4 supports all the features in the current working draft of the
|
||||||
|
upcoming C++ standard, provisionally named C++1y. Support for the following
|
||||||
|
major new features has been added since Clang 3.3:
|
||||||
|
|
||||||
|
- Generic lambdas and initialized lambda captures.
|
||||||
|
- Deduced function return types (``auto f() { return 0; }``).
|
||||||
|
- Generalized ``constexpr`` support (variable mutation and loops).
|
||||||
|
- Variable templates and static data member templates.
|
||||||
|
- Use of ``'`` as a digit separator in numeric literals.
|
||||||
|
- Support for sized ``::operator delete`` functions.
|
||||||
|
|
||||||
|
In addition, ``[[deprecated]]`` is now accepted as a synonym for Clang's
|
||||||
|
existing ``deprecated`` attribute.
|
||||||
|
|
||||||
|
Use ``-std=c++1y`` to enable C++1y mode.
|
||||||
|
|
||||||
|
OpenCL C Language Changes in Clang
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
- OpenCL C "long" now always has a size of 64 bit, and all OpenCL C
|
||||||
|
types are aligned as specified in the OpenCL C standard. Also,
|
||||||
|
"char" is now always signed.
|
||||||
|
|
||||||
Internal API Changes
|
Internal API Changes
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
These are major API changes that have happened since the 3.2 release of
|
These are major API changes that have happened since the 3.3 release of
|
||||||
Clang. If upgrading an external codebase that uses Clang as a library,
|
Clang. If upgrading an external codebase that uses Clang as a library,
|
||||||
this section should help get you past the largest hurdles of upgrading.
|
this section should help get you past the largest hurdles of upgrading.
|
||||||
|
|
||||||
Value Casting
|
Wide Character Types
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Certain type hierarchies (TypeLoc, CFGElement, ProgramPoint, and SVal) were
|
The ASTContext class now keeps track of two different types for wide character
|
||||||
misusing the llvm::cast machinery to perform undefined operations. Their APIs
|
types: WCharTy and WideCharTy. WCharTy represents the built-in wchar_t type
|
||||||
have been changed to use two member function templates that return values
|
available in C++. WideCharTy is the type used for wide character literals; in
|
||||||
instead of pointers or references - "T castAs" and "Optional<T> getAs" (in the
|
C++ it is the same as WCharTy, but in C99, where wchar_t is a typedef, it is an
|
||||||
case of the TypeLoc hierarchy the latter is "T getAs" and you can use the
|
integer type.
|
||||||
boolean testability of a TypeLoc (or its 'validity') to verify that the cast
|
|
||||||
succeeded). Essentially all previous 'cast' usage should be replaced with
|
|
||||||
'castAs' and 'dyn_cast' should be replaced with 'getAs'. See r175462 for the
|
|
||||||
first example of such a change along with many examples of how code was
|
|
||||||
migrated to the new API.
|
|
||||||
|
|
||||||
Storage Class
|
|
||||||
^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
For each variable and function Clang used to keep the storage class as written
|
|
||||||
in the source, the linkage and a semantic storage class. This was a bit
|
|
||||||
redundant and the semantic storage class has been removed. The method
|
|
||||||
getStorageClass now returns what is written in the source code for that decl.
|
|
||||||
|
|
||||||
libclang
|
|
||||||
--------
|
|
||||||
|
|
||||||
The clang_CXCursorSet_contains() function previously incorrectly returned 0
|
|
||||||
if it contained a CXCursor, contrary to what the documentation stated. This
|
|
||||||
has been fixed so that the function returns a non-zero value if the set
|
|
||||||
contains a cursor. This is API breaking change, but matches the intended
|
|
||||||
original behavior. Moreover, this also fixes the issue of an invalid CXCursorSet
|
|
||||||
appearing to contain any CXCursor.
|
|
||||||
|
|
||||||
Static Analyzer
|
Static Analyzer
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
The static analyzer (which contains additional code checking beyond compiler
|
The static analyzer has been greatly improved. This impacts the overall analyzer quality and reduces a number of false positives.
|
||||||
warnings) has improved significantly in both in the core analysis engine and
|
In particular, this release provides enhanced C++ support, reasoning about initializer lists, zeroing constructors, noreturn destructors and modeling of destructor calls on calls to delete.
|
||||||
also in the kinds of issues it can find.
|
|
||||||
|
|
||||||
Core Analysis Improvements
|
Clang Format
|
||||||
==========================
|
------------
|
||||||
|
|
||||||
- Support for interprocedural reasoning about constructors and destructors.
|
Clang now includes a new tool ``clang-format`` which can be used to
|
||||||
- New false positive suppression mechanisms that reduced the number of false
|
automatically format C, C++ and Objective-C source code. ``clang-format``
|
||||||
null pointer dereference warnings due to interprocedural analysis.
|
automatically chooses linebreaks and indentation and can be easily integrated
|
||||||
- Major performance enhancements to speed up interprocedural analysis
|
into editors, IDEs and version control systems. It supports several pre-defined
|
||||||
|
styles as well as precise style control using a multitude of formatting
|
||||||
|
options. ``clang-format`` itself is just a thin wrapper around a library which
|
||||||
|
can also be used directly from code refactoring and code translation tools.
|
||||||
|
More information can be found on `Clang Format's
|
||||||
|
site <http://clang.llvm.org/docs/ClangFormat.html>`_.
|
||||||
|
|
||||||
New Issues Found
|
Windows Support
|
||||||
================
|
---------------
|
||||||
|
|
||||||
- New memory error checks such as use-after-free with C++ 'delete'.
|
- `clang-cl <UsersManual.html#clang-cl>`_ provides a new driver mode that is
|
||||||
- Detection of mismatched allocators and deallocators (e.g., using 'new' with
|
designed for compatibility with Visual Studio's compiler, cl.exe. This driver
|
||||||
'free()', 'malloc()' with 'delete').
|
mode makes Clang accept the same kind of command-line options as cl.exe. The
|
||||||
- Additional checks for misuses of Apple Foundation framework collection APIs.
|
installer will attempt to expose clang-cl in any Visual Studio installations
|
||||||
|
on the system as a Platform Toolset, e.g. "LLVM-vs2012". clang-cl targets the
|
||||||
|
Microsoft ABI by default. Please note that this driver mode and compatibility
|
||||||
|
with the MS ABI is highly experimental.
|
||||||
|
|
||||||
|
Python Binding Changes
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The following methods have been added:
|
||||||
|
|
||||||
Significant Known Problems
|
Significant Known Problems
|
||||||
==========================
|
==========================
|
||||||
@ -135,11 +271,13 @@ Significant Known Problems
|
|||||||
Additional Information
|
Additional Information
|
||||||
======================
|
======================
|
||||||
|
|
||||||
A wide variety of additional information is available on the `Clang web page
|
A wide variety of additional information is available on the `Clang web
|
||||||
<http://clang.llvm.org/>`_. The web page contains versions of the API
|
page <http://clang.llvm.org/>`_. The web page contains versions of the
|
||||||
documentation which are up-to-date with the Subversion version of the source
|
API documentation which are up-to-date with the Subversion revision of
|
||||||
code. You can access versions of these documents specific to this release by
|
the source code. You can access versions of these documents specific to
|
||||||
going into the "``clang/docs/``" directory in the Clang tree.
|
this release by going into the "``clang/docs/``" directory in the Clang
|
||||||
|
tree.
|
||||||
|
|
||||||
If you have any questions or comments about Clang, please feel free to contact
|
If you have any questions or comments about Clang, please feel free to
|
||||||
us via the `mailing list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_.
|
contact us via the `mailing
|
||||||
|
list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_.
|
||||||
|
79
docs/SanitizerSpecialCaseList.rst
Normal file
79
docs/SanitizerSpecialCaseList.rst
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
===========================
|
||||||
|
Sanitizer special case list
|
||||||
|
===========================
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This document describes the way to disable or alter the behavior of
|
||||||
|
sanitizer tools for certain source-level entities by providing a special
|
||||||
|
file at compile-time.
|
||||||
|
|
||||||
|
Goal and usage
|
||||||
|
==============
|
||||||
|
|
||||||
|
User of sanitizer tools, such as :doc:`AddressSanitizer`, :doc:`ThreadSanitizer`
|
||||||
|
or :doc:`MemorySanitizer` may want to disable or alter some checks for
|
||||||
|
certain source-level entities to:
|
||||||
|
|
||||||
|
* speedup hot function, which is known to be correct;
|
||||||
|
* ignore a function that does some low-level magic (e.g. walks through the
|
||||||
|
thread stack, bypassing the frame boundaries);
|
||||||
|
* ignore a known problem.
|
||||||
|
|
||||||
|
To achieve this, user may create a file listing the entities he wants to
|
||||||
|
ignore, and pass it to clang at compile-time using
|
||||||
|
``-fsanitize-blacklist`` flag. See :doc:`UsersManual` for details.
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ cat foo.c
|
||||||
|
#include <stdlib.h>
|
||||||
|
void bad_foo() {
|
||||||
|
int *a = (int*)malloc(40);
|
||||||
|
a[10] = 1;
|
||||||
|
}
|
||||||
|
int main() { bad_foo(); }
|
||||||
|
$ cat blacklist.txt
|
||||||
|
# Ignore reports from bad_foo function.
|
||||||
|
fun:bad_foo
|
||||||
|
$ clang -fsanitize=address foo.c ; ./a.out
|
||||||
|
# AddressSanitizer prints an error report.
|
||||||
|
$ clang -fsanitize=address -fsanitize-blacklist=blacklist.txt foo.c ; ./a.out
|
||||||
|
# No error report here.
|
||||||
|
|
||||||
|
Format
|
||||||
|
======
|
||||||
|
|
||||||
|
Each line contains an entity type, followed by a colon and a regular
|
||||||
|
expression, specifying the names of the entities, optionally followed by
|
||||||
|
an equals sign and a tool-specific category. Empty lines and lines starting
|
||||||
|
with "#" are ignored. The meanining of ``*`` in regular expression for entity
|
||||||
|
names is different - it is treated as in shell wildcarding. Two generic
|
||||||
|
entity types are ``src`` and ``fun``, which allow user to add, respectively,
|
||||||
|
source files and functions to special case list. Some sanitizer tools may
|
||||||
|
introduce custom entity types - refer to tool-specific docs.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Lines starting with # are ignored.
|
||||||
|
# Turn off checks for the source file (use absolute path or path relative
|
||||||
|
# to the current working directory):
|
||||||
|
src:/path/to/source/file.c
|
||||||
|
# Turn off checks for a particular functions (use mangled names):
|
||||||
|
fun:MyFooBar
|
||||||
|
fun:_Z8MyFooBarv
|
||||||
|
# Extended regular expressions are supported:
|
||||||
|
fun:bad_(foo|bar)
|
||||||
|
src:bad_source[1-9].c
|
||||||
|
# Shell like usage of * is supported (* is treated as .*):
|
||||||
|
src:bad/sources/*
|
||||||
|
fun:*BadFunction*
|
||||||
|
# Specific sanitizer tools may introduce categories.
|
||||||
|
src:/special/path/*=special_sources
|
@ -91,11 +91,21 @@ Some code should not be instrumented by ThreadSanitizer.
|
|||||||
One may use the function attribute
|
One may use the function attribute
|
||||||
:ref:`no_sanitize_thread <langext-thread_sanitizer>`
|
:ref:`no_sanitize_thread <langext-thread_sanitizer>`
|
||||||
to disable instrumentation of plain (non-atomic) loads/stores in a particular function.
|
to disable instrumentation of plain (non-atomic) loads/stores in a particular function.
|
||||||
ThreadSanitizer may still instrument such functions to avoid false positives.
|
ThreadSanitizer still instruments such functions to avoid false positives and
|
||||||
|
provide meaningful stack traces.
|
||||||
This attribute may not be
|
This attribute may not be
|
||||||
supported by other compilers, so we suggest to use it together with
|
supported by other compilers, so we suggest to use it together with
|
||||||
``__has_feature(thread_sanitizer)``. Note: currently, this attribute will be
|
``__has_feature(thread_sanitizer)``.
|
||||||
lost if the function is inlined.
|
|
||||||
|
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.
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
@ -44,6 +44,8 @@ as to improve functionality through Clang-specific features. The Clang
|
|||||||
driver and language features are intentionally designed to be as
|
driver and language features are intentionally designed to be as
|
||||||
compatible with the GNU GCC compiler as reasonably possible, easing
|
compatible with the GNU GCC compiler as reasonably possible, easing
|
||||||
migration from GCC to Clang. In most cases, code "just works".
|
migration from GCC to Clang. In most cases, code "just works".
|
||||||
|
Clang also provides an alternative driver, :ref:`clang-cl`, that is designed
|
||||||
|
to be compatible with the Visual C++ compiler, cl.exe.
|
||||||
|
|
||||||
In addition to language specific features, Clang has a variety of
|
In addition to language specific features, Clang has a variety of
|
||||||
features that depend on what CPU architecture or operating system is
|
features that depend on what CPU architecture or operating system is
|
||||||
@ -235,6 +237,11 @@ output format of the diagnostics that it generates.
|
|||||||
^
|
^
|
||||||
//
|
//
|
||||||
|
|
||||||
|
**-fansi-escape-codes**
|
||||||
|
Controls whether ANSI escape codes are used instead of the Windows Console
|
||||||
|
API to output colored diagnostics. This option is only used on Windows and
|
||||||
|
defaults to off.
|
||||||
|
|
||||||
.. option:: -fdiagnostics-format=clang/msvc/vi
|
.. option:: -fdiagnostics-format=clang/msvc/vi
|
||||||
|
|
||||||
Changes diagnostic output format to better match IDEs and command line tools.
|
Changes diagnostic output format to better match IDEs and command line tools.
|
||||||
@ -422,7 +429,7 @@ output format of the diagnostics that it generates.
|
|||||||
map<
|
map<
|
||||||
[...],
|
[...],
|
||||||
map<
|
map<
|
||||||
[float != float],
|
[float != double],
|
||||||
[...]>>>
|
[...]>>>
|
||||||
|
|
||||||
.. _cl_diag_warning_groups:
|
.. _cl_diag_warning_groups:
|
||||||
@ -853,7 +860,7 @@ Controlling Code Generation
|
|||||||
Clang provides a number of ways to control code generation. The options
|
Clang provides a number of ways to control code generation. The options
|
||||||
are listed below.
|
are listed below.
|
||||||
|
|
||||||
**-fsanitize=check1,check2,...**
|
**-f[no-]sanitize=check1,check2,...**
|
||||||
Turn on runtime checks for various forms of undefined or suspicious
|
Turn on runtime checks for various forms of undefined or suspicious
|
||||||
behavior.
|
behavior.
|
||||||
|
|
||||||
@ -889,13 +896,14 @@ are listed below.
|
|||||||
includes all of the checks listed below other than
|
includes all of the checks listed below other than
|
||||||
``unsigned-integer-overflow``.
|
``unsigned-integer-overflow``.
|
||||||
|
|
||||||
``-fsanitize=undefined-trap``: This includes all sanitizers
|
- ``-fsanitize=undefined-trap``: This includes all sanitizers
|
||||||
included by ``-fsanitize=undefined``, except those that require
|
included by ``-fsanitize=undefined``, except those that require
|
||||||
runtime support. This group of sanitizers are generally used
|
runtime support. This group of sanitizers is intended to be
|
||||||
in conjunction with the ``-fsanitize-undefined-trap-on-error``
|
used in conjunction with the ``-fsanitize-undefined-trap-on-error``
|
||||||
flag, which causes traps to be emitted, rather than calls to
|
flag. This includes all of the checks listed below other than
|
||||||
runtime libraries. This includes all of the checks listed below
|
``unsigned-integer-overflow`` and ``vptr``.
|
||||||
other than ``unsigned-integer-overflow`` and ``vptr``.
|
- ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
|
||||||
|
flow analysis.
|
||||||
|
|
||||||
The following more fine-grained checks are also available:
|
The following more fine-grained checks are also available:
|
||||||
|
|
||||||
@ -913,6 +921,8 @@ are listed below.
|
|||||||
destination.
|
destination.
|
||||||
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
||||||
zero.
|
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=integer-divide-by-zero``: Integer division by zero.
|
||||||
- ``-fsanitize=null``: Use of a null pointer or creation of a null
|
- ``-fsanitize=null``: Use of a null pointer or creation of a null
|
||||||
reference.
|
reference.
|
||||||
@ -941,6 +951,15 @@ are listed below.
|
|||||||
it is of the wrong dynamic type, or that its lifetime has not
|
it is of the wrong dynamic type, or that its lifetime has not
|
||||||
begun or has ended. Incompatible with ``-fno-rtti``.
|
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.
|
||||||
|
|
||||||
Experimental features of AddressSanitizer (not ready for widespread
|
Experimental features of AddressSanitizer (not ready for widespread
|
||||||
use, require explicit ``-fsanitize=address``):
|
use, require explicit ``-fsanitize=address``):
|
||||||
|
|
||||||
@ -958,10 +977,31 @@ are listed below.
|
|||||||
uninitialized bits came from. Slows down execution by additional
|
uninitialized bits came from. Slows down execution by additional
|
||||||
1.5x-2x.
|
1.5x-2x.
|
||||||
|
|
||||||
|
Extra features of UndefinedBehaviorSanitizer:
|
||||||
|
|
||||||
|
- ``-fno-sanitize-recover``: By default, after a sanitizer diagnoses
|
||||||
|
an issue, it will attempt to continue executing the program if there
|
||||||
|
is a reasonable behavior it can give to the faulting operation. This
|
||||||
|
option causes the program to abort instead.
|
||||||
|
- ``-fsanitize-undefined-trap-on-error``: Causes traps to be emitted
|
||||||
|
rather than calls to runtime libraries when a problem is detected.
|
||||||
|
This option is intended for use in cases where the sanitizer runtime
|
||||||
|
cannot be used (for instance, when building libc or a kernel module).
|
||||||
|
This is only compatible with the sanitizers in the ``undefined-trap``
|
||||||
|
group.
|
||||||
|
|
||||||
The ``-fsanitize=`` argument must also be provided when linking, in
|
The ``-fsanitize=`` argument must also be provided when linking, in
|
||||||
order to link to the appropriate runtime library. It is not possible
|
order to link to the appropriate runtime library. When using
|
||||||
to combine the ``-fsanitize=address`` and ``-fsanitize=thread``
|
``-fsanitize=vptr`` (or a group that includes it, such as
|
||||||
checkers in the same program.
|
``-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.
|
||||||
|
|
||||||
|
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 be combined with other
|
||||||
|
sanitizers.
|
||||||
|
|
||||||
**-f[no-]address-sanitizer**
|
**-f[no-]address-sanitizer**
|
||||||
Deprecated synonym for :ref:`-f[no-]sanitize=address
|
Deprecated synonym for :ref:`-f[no-]sanitize=address
|
||||||
<opt_fsanitize_address>`.
|
<opt_fsanitize_address>`.
|
||||||
@ -1007,6 +1047,26 @@ are listed below.
|
|||||||
efficient model can be used. The TLS model can be overridden per
|
efficient model can be used. The TLS model can be overridden per
|
||||||
variable using the ``tls_model`` attribute.
|
variable using the ``tls_model`` attribute.
|
||||||
|
|
||||||
|
.. option:: -mhwdiv=[values]
|
||||||
|
|
||||||
|
Select the ARM modes (arm or thumb) that support hardware division
|
||||||
|
instructions.
|
||||||
|
|
||||||
|
Valid values are: ``arm``, ``thumb`` and ``arm,thumb``.
|
||||||
|
This option is used to indicate which mode (arm or thumb) supports
|
||||||
|
hardware division instructions. This only applies to the ARM
|
||||||
|
architecture.
|
||||||
|
|
||||||
|
.. option:: -m[no-]crc
|
||||||
|
|
||||||
|
Enable or disable CRC instructions.
|
||||||
|
|
||||||
|
This option is used to indicate whether CRC instructions are to
|
||||||
|
be generated. This only applies to the ARM architecture.
|
||||||
|
|
||||||
|
CRC instructions are enabled by default on ARMv8.
|
||||||
|
|
||||||
|
|
||||||
Controlling Size of Debug Information
|
Controlling Size of Debug Information
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
@ -1178,30 +1238,40 @@ Microsoft extensions
|
|||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
clang has some experimental support for extensions from Microsoft Visual
|
clang has some experimental support for extensions from Microsoft Visual
|
||||||
C++; to enable it, use the -fms-extensions command-line option. This is
|
C++; to enable it, use the ``-fms-extensions`` command-line option. This is
|
||||||
the default for Windows targets. Note that the support is incomplete;
|
the default for Windows targets. Note that the support is incomplete.
|
||||||
enabling Microsoft extensions will silently drop certain constructs
|
Some constructs such as ``dllexport`` on classes are ignored with a warning,
|
||||||
(including ``__declspec`` and Microsoft-style asm statements).
|
and others such as `Microsoft IDL annotations
|
||||||
|
<http://msdn.microsoft.com/en-us/library/8tesw2eh.aspx>`_ are silently
|
||||||
|
ignored.
|
||||||
|
|
||||||
clang has a -fms-compatibility flag that makes clang accept enough
|
clang has a ``-fms-compatibility`` flag that makes clang accept enough
|
||||||
invalid C++ to be able to parse most Microsoft headers. This flag is
|
invalid C++ to be able to parse most Microsoft headers. For example, it
|
||||||
enabled by default for Windows targets.
|
allows `unqualified lookup of dependent base class members
|
||||||
|
<http://clang.llvm.org/compatibility.html#dep_lookup_bases>`_, which is
|
||||||
|
a common compatibility issue with clang. This flag is enabled by default
|
||||||
|
for Windows targets.
|
||||||
|
|
||||||
-fdelayed-template-parsing lets clang delay all template instantiation
|
``-fdelayed-template-parsing`` lets clang delay parsing of function template
|
||||||
until the end of a translation unit. This flag is enabled by default for
|
definitions until the end of a translation unit. This flag is enabled by
|
||||||
Windows targets.
|
default for Windows targets.
|
||||||
|
|
||||||
- clang allows setting ``_MSC_VER`` with ``-fmsc-version=``. It defaults to
|
- clang allows setting ``_MSC_VER`` with ``-fmsc-version=``. It defaults to
|
||||||
1300 which is the same as Visual C/C++ 2003. Any number is supported
|
1700 which is the same as Visual C/C++ 2012. Any number is supported
|
||||||
and can greatly affect what Windows SDK and c++stdlib headers clang
|
and can greatly affect what Windows SDK and c++stdlib headers clang
|
||||||
can compile. This option will be removed when clang supports the full
|
can compile.
|
||||||
set of MS extensions required for these headers.
|
|
||||||
- clang does not support the Microsoft extension where anonymous record
|
- clang does not support the Microsoft extension where anonymous record
|
||||||
members can be declared using user defined typedefs.
|
members can be declared using user defined typedefs.
|
||||||
- clang supports the Microsoft "#pragma pack" feature for controlling
|
- clang supports the Microsoft ``#pragma pack`` feature for controlling
|
||||||
record layout. GCC also contains support for this feature, however
|
record layout. GCC also contains support for this feature, however
|
||||||
where MSVC and GCC are incompatible clang follows the MSVC
|
where MSVC and GCC are incompatible clang follows the MSVC
|
||||||
definition.
|
definition.
|
||||||
|
- clang supports the Microsoft ``#pragma comment(lib, "foo.lib")`` feature for
|
||||||
|
automatically linking against the specified library. Currently this feature
|
||||||
|
only works with the Visual C++ linker.
|
||||||
|
- clang supports the Microsoft ``#pragma comment(linker, "/flag:foo")`` feature
|
||||||
|
for adding linker flags to COFF object files. The user is responsible for
|
||||||
|
ensuring that the linker understands the flags.
|
||||||
- clang defaults to C++11 for Windows targets.
|
- clang defaults to C++11 for Windows targets.
|
||||||
|
|
||||||
.. _cxx:
|
.. _cxx:
|
||||||
@ -1210,8 +1280,8 @@ C++ Language Features
|
|||||||
=====================
|
=====================
|
||||||
|
|
||||||
clang fully implements all of standard C++98 except for exported
|
clang fully implements all of standard C++98 except for exported
|
||||||
templates (which were removed in C++11), and `many C++11
|
templates (which were removed in C++11), and all of standard C++11
|
||||||
features <http://clang.llvm.org/cxx_status.html>`_ are also implemented.
|
and the current draft standard for C++1y.
|
||||||
|
|
||||||
Controlling implementation limits
|
Controlling implementation limits
|
||||||
---------------------------------
|
---------------------------------
|
||||||
@ -1229,7 +1299,12 @@ Controlling implementation limits
|
|||||||
.. option:: -ftemplate-depth=N
|
.. option:: -ftemplate-depth=N
|
||||||
|
|
||||||
Sets the limit for recursively nested template instantiations to N. The
|
Sets the limit for recursively nested template instantiations to N. The
|
||||||
default is 1024.
|
default is 256.
|
||||||
|
|
||||||
|
.. option:: -foperator-arrow-depth=N
|
||||||
|
|
||||||
|
Sets the limit for iterative calls to 'operator->' functions to N. The
|
||||||
|
default is 256.
|
||||||
|
|
||||||
.. _objc:
|
.. _objc:
|
||||||
|
|
||||||
@ -1258,8 +1333,8 @@ Darwin (Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested
|
|||||||
to correctly compile many large C, C++, Objective-C, and Objective-C++
|
to correctly compile many large C, C++, Objective-C, and Objective-C++
|
||||||
codebases.
|
codebases.
|
||||||
|
|
||||||
On ``x86_64-mingw32``, passing i128(by value) is incompatible to Microsoft
|
On ``x86_64-mingw32``, passing i128(by value) is incompatible with the
|
||||||
x64 calling conversion. You might need to tweak
|
Microsoft x64 calling conversion. You might need to tweak
|
||||||
``WinX86_64ABIInfo::classify()`` in lib/CodeGen/TargetInfo.cpp.
|
``WinX86_64ABIInfo::classify()`` in lib/CodeGen/TargetInfo.cpp.
|
||||||
|
|
||||||
ARM
|
ARM
|
||||||
@ -1271,11 +1346,19 @@ C++, Objective-C, and Objective-C++ codebases. Clang only supports a
|
|||||||
limited number of ARM architectures. It does not yet fully support
|
limited number of ARM architectures. It does not yet fully support
|
||||||
ARMv5, for example.
|
ARMv5, for example.
|
||||||
|
|
||||||
|
PowerPC
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
The support for PowerPC (especially PowerPC64) is considered stable
|
||||||
|
on Linux and FreeBSD: it has been tested to correctly compile many
|
||||||
|
large C and C++ codebases. PowerPC (32bit) is still missing certain
|
||||||
|
features (e.g. PIC code on ELF platforms).
|
||||||
|
|
||||||
Other platforms
|
Other platforms
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
clang currently contains some support for PPC and Sparc; however,
|
clang currently contains some support for other architectures (e.g. Sparc);
|
||||||
significant pieces of code generation are still missing, and they
|
however, significant pieces of code generation are still missing, and they
|
||||||
haven't undergone significant testing.
|
haven't undergone significant testing.
|
||||||
|
|
||||||
clang contains limited support for the MSP430 embedded processor, but
|
clang contains limited support for the MSP430 embedded processor, but
|
||||||
@ -1302,9 +1385,10 @@ None
|
|||||||
Windows
|
Windows
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
Experimental supports are on Cygming.
|
Clang has experimental support for targeting "Cygming" (Cygwin / MinGW)
|
||||||
|
platforms.
|
||||||
|
|
||||||
See also `Microsoft Extensions <c_ms>`.
|
See also :ref:`Microsoft Extensions <c_ms>`.
|
||||||
|
|
||||||
Cygwin
|
Cygwin
|
||||||
""""""
|
""""""
|
||||||
@ -1349,3 +1433,111 @@ Clang expects the GCC executable "gcc.exe" compiled for
|
|||||||
|
|
||||||
`Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on
|
`Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on
|
||||||
``x86_64-w64-mingw32``.
|
``x86_64-w64-mingw32``.
|
||||||
|
|
||||||
|
.. _clang-cl:
|
||||||
|
|
||||||
|
clang-cl
|
||||||
|
========
|
||||||
|
|
||||||
|
clang-cl is an alternative command-line interface to Clang driver, designed for
|
||||||
|
compatibility with the Visual C++ compiler, cl.exe.
|
||||||
|
|
||||||
|
To enable clang-cl to find system headers, libraries, and the linker when run
|
||||||
|
from the command-line, it should be executed inside a Visual Studio Native Tools
|
||||||
|
Command Prompt or a regular Command Prompt where the environment has been set
|
||||||
|
up using e.g. `vcvars32.bat <http://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx>`_.
|
||||||
|
|
||||||
|
clang-cl can also be used from inside Visual Studio by using an LLVM Platform
|
||||||
|
Toolset.
|
||||||
|
|
||||||
|
Command-Line Options
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
To be compatible with cl.exe, clang-cl supports most of the same command-line
|
||||||
|
options. Those options can start with either ``/`` or ``-``. It also supports
|
||||||
|
some of Clang's core options, such as the ``-W`` options.
|
||||||
|
|
||||||
|
Options that are known to clang-cl, but not currently supported, are ignored
|
||||||
|
with a warning. For example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
clang-cl.exe: warning: argument unused during compilation: '/Zi'
|
||||||
|
|
||||||
|
To suppress warnings about unused arguments, use the ``-Qunused-arguments`` option.
|
||||||
|
|
||||||
|
Options that are not known to clang-cl will cause errors. If they are spelled with a
|
||||||
|
leading ``/``, they will be mistaken for a filename:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
clang-cl.exe: error: no such file or directory: '/foobar'
|
||||||
|
|
||||||
|
Please `file a bug <http://llvm.org/bugs/enter_bug.cgi?product=clang&component=Driver>`_
|
||||||
|
for any valid cl.exe flags that clang-cl does not understand.
|
||||||
|
|
||||||
|
Execute ``clang-cl /?`` to see a list of supported options:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
/? Display available options
|
||||||
|
/c Compile only
|
||||||
|
/D <macro[=value]> Define macro
|
||||||
|
/fallback Fall back to cl.exe if clang-cl fails to compile
|
||||||
|
/FA Output assembly code file during compilation
|
||||||
|
/Fa<file or directory> Output assembly code to this file during compilation
|
||||||
|
/Fe<file or directory> Set output executable file or directory (ends in / or \)
|
||||||
|
/FI<value> Include file before parsing
|
||||||
|
/Fo<file or directory> Set output object file, or directory (ends in / or \)
|
||||||
|
/GF- Disable string pooling
|
||||||
|
/GR- Disable RTTI
|
||||||
|
/GR Enable RTTI
|
||||||
|
/help Display available options
|
||||||
|
/I <dir> Add directory to include search path
|
||||||
|
/J Make char type unsigned
|
||||||
|
/LDd Create debug DLL
|
||||||
|
/LD Create DLL
|
||||||
|
/link <options> Forward options to the linker
|
||||||
|
/MDd Use DLL debug run-time
|
||||||
|
/MD Use DLL run-time
|
||||||
|
/MTd Use static debug run-time
|
||||||
|
/MT Use static run-time
|
||||||
|
/Ob0 Disable inlining
|
||||||
|
/Od Disable optimization
|
||||||
|
/Oi- Disable use of builtin functions
|
||||||
|
/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
|
||||||
|
/P Only run the preprocessor
|
||||||
|
/showIncludes Print info about included files to stderr
|
||||||
|
/TC Treat all source files as C
|
||||||
|
/Tc <filename> Specify a C source file
|
||||||
|
/TP Treat all source files as C++
|
||||||
|
/Tp <filename> Specify a C++ source file
|
||||||
|
/U <macro> Undefine macro
|
||||||
|
/W0 Disable all warnings
|
||||||
|
/W1 Enable -Wall
|
||||||
|
/W2 Enable -Wall
|
||||||
|
/W3 Enable -Wall
|
||||||
|
/W4 Enable -Wall
|
||||||
|
/Wall Enable -Wall
|
||||||
|
/WX- Do not treat warnings as errors
|
||||||
|
/WX Treat warnings as errors
|
||||||
|
/w Disable all warnings
|
||||||
|
/Zs Syntax-check only
|
||||||
|
|
||||||
|
The /fallback Option
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
When clang-cl is run with the ``/fallback`` option, it will first try to
|
||||||
|
compile files itself. For any file that it fails to compile, it will fall back
|
||||||
|
and try to compile the file by invoking cl.exe.
|
||||||
|
|
||||||
|
This option is intended to be used as a temporary means to build projects where
|
||||||
|
clang-cl cannot successfully compile all the files. clang-cl may fail to compile
|
||||||
|
a file either because it cannot generate code for some C++ feature, or because
|
||||||
|
it cannot parse some Microsoft language extension.
|
||||||
|
@ -30,6 +30,10 @@ using a 'dot' format viewer (such as Graphviz on OS X) instead.
|
|||||||
- debug.DumpLiveVars: Show the results of live variable analysis for each
|
- debug.DumpLiveVars: Show the results of live variable analysis for each
|
||||||
top-level function being analyzed.
|
top-level function being analyzed.
|
||||||
|
|
||||||
|
- debug.ViewExplodedGraph: Show the Exploded Graphs generated for the
|
||||||
|
analysis of different functions in the input translation unit. When there
|
||||||
|
are several functions analyzed, display one graph per function. Beware
|
||||||
|
that these graphs may grow very large, even for small functions.
|
||||||
|
|
||||||
Path Tracking
|
Path Tracking
|
||||||
=============
|
=============
|
||||||
@ -121,6 +125,19 @@ ExprInspection checks
|
|||||||
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
|
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- void clang_analyzer_warnIfReached();
|
||||||
|
|
||||||
|
Generate a warning if this line of code gets reached by the analyzer.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clang_analyzer_warnIfReached(); // no-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Statistics
|
Statistics
|
||||||
==========
|
==========
|
||||||
|
@ -74,7 +74,7 @@ This option controls whether functions from the C++ standard library, including
|
|||||||
methods of the container classes in the Standard Template Library, should be
|
methods of the container classes in the Standard Template Library, should be
|
||||||
considered for inlining.
|
considered for inlining.
|
||||||
|
|
||||||
-analyzer-config c++-template-inlining=[true | false]
|
-analyzer-config c++-stdlib-inlining=[true | false]
|
||||||
|
|
||||||
Currently, C++ standard library functions are considered for inlining by
|
Currently, C++ standard library functions are considered for inlining by
|
||||||
default.
|
default.
|
||||||
|
@ -48,9 +48,9 @@
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '3.3'
|
version = '3.4'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '3.3'
|
release = '3.4'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -48,9 +48,9 @@
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '3.3'
|
version = '3.4'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '3.3'
|
release = '3.4'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -1224,7 +1224,30 @@ DOT_CLEANUP = YES
|
|||||||
# Configuration::additions related to the search engine
|
# Configuration::additions related to the search engine
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
|
||||||
# used. If set to NO the values of all tags below this one will be ignored.
|
# for the HTML output. The underlying search engine uses javascript
|
||||||
|
# and DHTML and should work on any modern browser. Note that when using
|
||||||
|
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
|
||||||
|
# (GENERATE_DOCSET) there is already a search function so this one should
|
||||||
|
# typically be disabled. For large projects the javascript based search engine
|
||||||
|
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
|
||||||
|
|
||||||
SEARCHENGINE = NO
|
SEARCHENGINE = @enable_searchengine@
|
||||||
|
|
||||||
|
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
|
||||||
|
# implemented using a PHP enabled web server instead of at the web client
|
||||||
|
# using Javascript. Doxygen will generate the search PHP script and index
|
||||||
|
# file to put on the web server. The advantage of the server
|
||||||
|
# based approach is that it scales better to large projects and allows
|
||||||
|
# full text search. The disadvances is that it is more difficult to setup
|
||||||
|
# and does not have live searching capabilities.
|
||||||
|
|
||||||
|
SERVER_BASED_SEARCH = @enable_server_based_search@
|
||||||
|
|
||||||
|
SEARCHENGINE_URL = @searchengine_url@
|
||||||
|
|
||||||
|
EXTERNAL_SEARCH = @enable_external_search@
|
||||||
|
|
||||||
|
EXTERNAL_SEARCH_ID = clang
|
||||||
|
|
||||||
|
EXTRA_SEARCH_MAPPINGS = @extra_search_mappings@
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<p class="footer">
|
<p class="footer">
|
||||||
Generated on $datetime by <a href="http://www.doxygen.org">Doxygen
|
Generated on $datetime for r$LatestRev$ by <a href="http://www.doxygen.org">Doxygen
|
||||||
$doxygenversion</a>.</p>
|
$doxygenversion</a>.</p>
|
||||||
|
|
||||||
<p class="footer">
|
<p class="footer">
|
||||||
|
@ -18,9 +18,13 @@ Using Clang as a Compiler
|
|||||||
|
|
||||||
UsersManual
|
UsersManual
|
||||||
LanguageExtensions
|
LanguageExtensions
|
||||||
|
CrossCompilation
|
||||||
AddressSanitizer
|
AddressSanitizer
|
||||||
ThreadSanitizer
|
ThreadSanitizer
|
||||||
MemorySanitizer
|
MemorySanitizer
|
||||||
|
DataFlowSanitizer
|
||||||
|
LeakSanitizer
|
||||||
|
SanitizerSpecialCaseList
|
||||||
Modules
|
Modules
|
||||||
FAQ
|
FAQ
|
||||||
|
|
||||||
@ -51,6 +55,7 @@ Using Clang Tools
|
|||||||
ClangTools
|
ClangTools
|
||||||
ClangCheck
|
ClangCheck
|
||||||
ClangFormat
|
ClangFormat
|
||||||
|
ClangFormatStyleOptions
|
||||||
|
|
||||||
Design Documents
|
Design Documents
|
||||||
================
|
================
|
||||||
|
@ -7,7 +7,7 @@ clang - the Clang C, C++, and Objective-C compiler
|
|||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
|
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
|
||||||
[B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-Oz>|B<-O3>|B<-Ofast>|B<-O4>]
|
[B<-O0>|B<-O1>|B<-O2>|B<-O3>|B<-Ofast>|B<-Os>|B<-Oz>|B<-O>|B<-O4>]
|
||||||
B<-W>I<warnings...> B<-pedantic>
|
B<-W>I<warnings...> B<-pedantic>
|
||||||
B<-I>I<dir...> B<-L>I<dir...>
|
B<-I>I<dir...> B<-L>I<dir...>
|
||||||
B<-D>I<macro[=defn]>
|
B<-D>I<macro[=defn]>
|
||||||
@ -81,7 +81,8 @@ B<Clang Static Analyzer>
|
|||||||
|
|
||||||
The Clang Static Analyzer is a tool that scans source code to try to find bugs
|
The Clang Static Analyzer is a tool that scans source code to try to find bugs
|
||||||
through code analysis. This tool uses many parts of Clang and is built into the
|
through code analysis. This tool uses many parts of Clang and is built into the
|
||||||
same driver.
|
same driver. Please see L<http://clang-analyzer.llvm.org> for more details
|
||||||
|
on how to use the static analyzer.
|
||||||
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
=head1 OPTIONS
|
||||||
@ -112,10 +113,6 @@ Run all of the above, plus the assembler, generating a target ".o" object file.
|
|||||||
If no stage selection option is specified, all stages above are run, and the
|
If no stage selection option is specified, all stages above are run, and the
|
||||||
linker is run to combine the results into an executable or shared library.
|
linker is run to combine the results into an executable or shared library.
|
||||||
|
|
||||||
=item B<--analyze>
|
|
||||||
|
|
||||||
Run the Clang Static Analyzer.
|
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
||||||
@ -263,20 +260,52 @@ may not exist on earlier ones.
|
|||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
=item B<-O0> B<-O1> B<-O2> B<-Os> B<-Oz> B<-O3> B<-Ofast> B<-O4>
|
=item B<-O0> B<-O1> B<-O2> B<-O3> B<-Ofast> B<-Os> B<-Oz> B<-O> B<-O4>
|
||||||
|
|
||||||
Specify which optimization level to use. B<-O0> means "no optimization": this
|
Specify which optimization level to use:
|
||||||
level compiles the fastest and generates the most debuggable code. B<-O2> is a
|
|
||||||
moderate level of optimization which enables most optimizations. B<-Os> is like
|
=over
|
||||||
B<-O2> with extra optimizations to reduce code size. B<-Oz> is like B<-Os>
|
|
||||||
(and thus B<-O2>), but reduces code size further. B<-O3> is like B<-O2>,
|
=item B<-O0>
|
||||||
except that it enables optimizations that take longer to perform or that may
|
|
||||||
generate larger code (in an attempt to make the program run faster).
|
Means "no optimization": this level compiles the fastest and
|
||||||
B<-Ofast> enables all the optimizations from B<-O3> along with other aggressive
|
generates the most debuggable code.
|
||||||
optimizations that may violate strict compliance with language standards. On
|
|
||||||
supported platforms, B<-O4> enables link-time optimization; object files are
|
=item B<-O1>
|
||||||
stored in the LLVM bitcode file format and whole program optimization is done at
|
|
||||||
link time. B<-O1> is somewhere between B<-O0> and B<-O2>.
|
Somewhere between B<-O0> and B<-O2>.
|
||||||
|
|
||||||
|
=item B<-O2>
|
||||||
|
|
||||||
|
Moderate level of optimization which enables most optimizations.
|
||||||
|
|
||||||
|
=item B<-O3>
|
||||||
|
|
||||||
|
Like B<-O2>, except that it enables optimizations that take longer to perform
|
||||||
|
or that may generate larger code (in an attempt to make the program run faster).
|
||||||
|
|
||||||
|
=item B<-Ofast>
|
||||||
|
|
||||||
|
Enables all the optimizations from B<-O3> along with other aggressive
|
||||||
|
optimizations that may violate strict compliance with language standards.
|
||||||
|
|
||||||
|
=item B<-Os>
|
||||||
|
|
||||||
|
Like B<-O2> with extra optimizations to reduce code size.
|
||||||
|
|
||||||
|
=item B<-Oz>
|
||||||
|
|
||||||
|
Like B<-Os> (and thus B<-O2>), but reduces code size further.
|
||||||
|
|
||||||
|
=item B<-O>
|
||||||
|
|
||||||
|
Equivalent to B<-O2>.
|
||||||
|
|
||||||
|
=item B<-O4> and higher
|
||||||
|
|
||||||
|
Currently equivalent to B<-O3>
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
=item B<-g>
|
=item B<-g>
|
||||||
|
|
||||||
|
@ -154,20 +154,25 @@ def act_on_decl(declaration, comment, allowed_types):
|
|||||||
inner, name = m.groups()
|
inner, name = m.groups()
|
||||||
add_matcher('Type', name, 'Matcher<%s>...' % inner,
|
add_matcher('Type', name, 'Matcher<%s>...' % inner,
|
||||||
comment, is_dyncast=True)
|
comment, is_dyncast=True)
|
||||||
add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
|
# FIXME: re-enable once we have implemented casting on the TypeLoc
|
||||||
comment, is_dyncast=True)
|
# hierarchy.
|
||||||
|
# add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
|
||||||
|
# comment, is_dyncast=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
|
m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
|
||||||
\s*([^\s,]+\s*),
|
\s*([^\s,]+\s*),
|
||||||
\s*(?:[^\s,]+\s*)
|
\s*(?:[^\s,]+\s*),
|
||||||
|
\s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
|
||||||
\)\s*;\s*$""", declaration, flags=re.X)
|
\)\s*;\s*$""", declaration, flags=re.X)
|
||||||
if m:
|
if m:
|
||||||
loc = m.group(1)
|
loc, name, n_results, results = m.groups()[0:4]
|
||||||
name = m.group(2)
|
result_types = [r.strip() for r in results.split(',')]
|
||||||
result_types = extract_result_types(comment)
|
|
||||||
if not result_types:
|
comment_result_types = extract_result_types(comment)
|
||||||
raise Exception('Did not find allowed result types for: %s' % name)
|
if (comment_result_types and
|
||||||
|
sorted(result_types) != sorted(comment_result_types)):
|
||||||
|
raise Exception('Inconsistent documentation for: %s' % name)
|
||||||
for result_type in result_types:
|
for result_type in result_types:
|
||||||
add_matcher(result_type, name, 'Matcher<Type>', comment)
|
add_matcher(result_type, name, 'Matcher<Type>', comment)
|
||||||
if loc:
|
if loc:
|
||||||
@ -175,7 +180,31 @@ def act_on_decl(declaration, comment, allowed_types):
|
|||||||
comment)
|
comment)
|
||||||
return
|
return
|
||||||
|
|
||||||
m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
|
m = re.match(r"""^\s*AST_POLYMORPHIC_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
|
||||||
|
\s*([^\s,]+)\s*,
|
||||||
|
\s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
|
||||||
|
(?:,\s*([^\s,]+)\s*
|
||||||
|
,\s*([^\s,]+)\s*)?
|
||||||
|
(?:,\s*([^\s,]+)\s*
|
||||||
|
,\s*([^\s,]+)\s*)?
|
||||||
|
(?:,\s*\d+\s*)?
|
||||||
|
\)\s*{\s*$""", declaration, flags=re.X)
|
||||||
|
|
||||||
|
if m:
|
||||||
|
p, n, name, n_results, results = m.groups()[0:5]
|
||||||
|
args = m.groups()[5:]
|
||||||
|
result_types = [r.strip() for r in results.split(',')]
|
||||||
|
if allowed_types and allowed_types != result_types:
|
||||||
|
raise Exception('Inconsistent documentation for: %s' % name)
|
||||||
|
if n not in ['', '2']:
|
||||||
|
raise Exception('Cannot parse "%s"' % declaration)
|
||||||
|
args = ', '.join('%s %s' % (args[i], args[i+1])
|
||||||
|
for i in range(0, len(args), 2) if args[i])
|
||||||
|
for result_type in result_types:
|
||||||
|
add_matcher(result_type, name, args, comment)
|
||||||
|
return
|
||||||
|
|
||||||
|
m = re.match(r"""^\s*AST_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
|
||||||
(?:\s*([^\s,]+)\s*,)?
|
(?:\s*([^\s,]+)\s*,)?
|
||||||
\s*([^\s,]+)\s*
|
\s*([^\s,]+)\s*
|
||||||
(?:,\s*([^\s,]+)\s*
|
(?:,\s*([^\s,]+)\s*
|
||||||
@ -185,8 +214,8 @@ def act_on_decl(declaration, comment, allowed_types):
|
|||||||
(?:,\s*\d+\s*)?
|
(?:,\s*\d+\s*)?
|
||||||
\)\s*{\s*$""", declaration, flags=re.X)
|
\)\s*{\s*$""", declaration, flags=re.X)
|
||||||
if m:
|
if m:
|
||||||
p, n, result, name = m.groups()[1:5]
|
p, n, result, name = m.groups()[0:4]
|
||||||
args = m.groups()[5:]
|
args = m.groups()[4:]
|
||||||
if not result:
|
if not result:
|
||||||
if not allowed_types:
|
if not allowed_types:
|
||||||
raise Exception('Did not find allowed result types for: %s' % name)
|
raise Exception('Did not find allowed result types for: %s' % name)
|
||||||
@ -201,6 +230,26 @@ def act_on_decl(declaration, comment, allowed_types):
|
|||||||
add_matcher(result_type, name, args, comment)
|
add_matcher(result_type, name, args, comment)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Parse ArgumentAdapting matchers.
|
||||||
|
m = re.match(
|
||||||
|
r"""^.*ArgumentAdaptingMatcherFunc<.*>\s*(?:LLVM_ATTRIBUTE_UNUSED\s*)
|
||||||
|
([a-zA-Z]*)\s*=\s*{};$""",
|
||||||
|
declaration, flags=re.X)
|
||||||
|
if m:
|
||||||
|
name = m.groups()[0]
|
||||||
|
add_matcher('*', name, 'Matcher<*>', comment)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Parse Variadic operator matchers.
|
||||||
|
m = re.match(
|
||||||
|
r"""^.*VariadicOperatorMatcherFunc\s*([a-zA-Z]*)\s*=\s*{.*};$""",
|
||||||
|
declaration, flags=re.X)
|
||||||
|
if m:
|
||||||
|
name = m.groups()[0]
|
||||||
|
add_matcher('*', name, 'Matcher<*>, ..., Matcher<*>', comment)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
# Parse free standing matcher functions, like:
|
# Parse free standing matcher functions, like:
|
||||||
# Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
|
# Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
|
||||||
m = re.match(r"""^\s*(.*)\s+
|
m = re.match(r"""^\s*(.*)\s+
|
||||||
@ -270,7 +319,7 @@ def sort_table(matcher_type, matcher_map):
|
|||||||
declaration += ' ' + line
|
declaration += ' ' + line
|
||||||
if ((not line.strip()) or
|
if ((not line.strip()) or
|
||||||
line.rstrip()[-1] == ';' or
|
line.rstrip()[-1] == ';' or
|
||||||
line.rstrip()[-1] == '{'):
|
(line.rstrip()[-1] == '{' and line.rstrip()[-3:] != '= {')):
|
||||||
if line.strip() and line.rstrip()[-1] == '{':
|
if line.strip() and line.rstrip()[-1] == '{':
|
||||||
body = True
|
body = True
|
||||||
else:
|
else:
|
||||||
|
143
docs/tools/dump_format_style.py
Normal file
143
docs/tools/dump_format_style.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# A tool to parse the FormatStyle struct from Format.h and update the
|
||||||
|
# documentation in ../ClangFormatStyleOptions.rst automatically.
|
||||||
|
# Run from the directory in which this file is located to update the docs.
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import re
|
||||||
|
import urllib2
|
||||||
|
|
||||||
|
FORMAT_STYLE_FILE = '../../include/clang/Format/Format.h'
|
||||||
|
DOC_FILE = '../ClangFormatStyleOptions.rst'
|
||||||
|
|
||||||
|
|
||||||
|
def substitute(text, tag, contents):
|
||||||
|
replacement = '\n.. START_%s\n\n%s\n\n.. END_%s\n' % (tag, contents, tag)
|
||||||
|
pattern = r'\n\.\. START_%s\n.*\n\.\. END_%s\n' % (tag, tag)
|
||||||
|
return re.sub(pattern, '%s', text, flags=re.S) % replacement
|
||||||
|
|
||||||
|
def doxygen2rst(text):
|
||||||
|
text = re.sub(r'<tt>\s*(.*?)\s*<\/tt>', r'``\1``', text)
|
||||||
|
text = re.sub(r'\\c ([^ ,;\.]+)', r'``\1``', text)
|
||||||
|
text = re.sub(r'\\\w+ ', '', text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
def indent(text, columns):
|
||||||
|
indent = ' ' * columns
|
||||||
|
s = re.sub(r'\n([^\n])', '\n' + indent + '\\1', text, flags=re.S)
|
||||||
|
if s.startswith('\n'):
|
||||||
|
return s
|
||||||
|
return indent + s
|
||||||
|
|
||||||
|
class Option:
|
||||||
|
def __init__(self, name, type, comment):
|
||||||
|
self.name = name
|
||||||
|
self.type = type
|
||||||
|
self.comment = comment.strip()
|
||||||
|
self.enum = 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)
|
||||||
|
return s
|
||||||
|
|
||||||
|
class Enum:
|
||||||
|
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 EnumValue:
|
||||||
|
def __init__(self, name, comment):
|
||||||
|
self.name = name
|
||||||
|
self.comment = comment.strip()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '* ``%s`` (in configuration: ``%s``)\n%s' % (
|
||||||
|
self.name,
|
||||||
|
re.sub('.*_', '', self.name),
|
||||||
|
doxygen2rst(indent(self.comment, 2)))
|
||||||
|
|
||||||
|
def clean_comment_line(line):
|
||||||
|
return line[3:].strip() + '\n'
|
||||||
|
|
||||||
|
def read_options(header):
|
||||||
|
class State:
|
||||||
|
BeforeStruct, Finished, InStruct, InFieldComment, InEnum, \
|
||||||
|
InEnumMemberComment = range(6)
|
||||||
|
state = State.BeforeStruct
|
||||||
|
|
||||||
|
options = []
|
||||||
|
enums = {}
|
||||||
|
comment = ''
|
||||||
|
enum = None
|
||||||
|
|
||||||
|
for line in header:
|
||||||
|
line = line.strip()
|
||||||
|
if state == State.BeforeStruct:
|
||||||
|
if line == 'struct FormatStyle {':
|
||||||
|
state = State.InStruct
|
||||||
|
elif state == State.InStruct:
|
||||||
|
if line.startswith('///'):
|
||||||
|
state = State.InFieldComment
|
||||||
|
comment = clean_comment_line(line)
|
||||||
|
elif line == '};':
|
||||||
|
state = State.Finished
|
||||||
|
break
|
||||||
|
elif state == State.InFieldComment:
|
||||||
|
if line.startswith('///'):
|
||||||
|
comment += clean_comment_line(line)
|
||||||
|
elif line.startswith('enum'):
|
||||||
|
state = State.InEnum
|
||||||
|
name = re.sub(r'enum\s+(\w+)\s*\{', '\\1', line)
|
||||||
|
enum = Enum(name, comment)
|
||||||
|
elif line.endswith(';'):
|
||||||
|
state = State.InStruct
|
||||||
|
field_type, field_name = re.match(r'(\w+)\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.InEnum:
|
||||||
|
if line.startswith('///'):
|
||||||
|
state = State.InEnumMemberComment
|
||||||
|
comment = clean_comment_line(line)
|
||||||
|
elif line == '};':
|
||||||
|
state = State.InStruct
|
||||||
|
enums[enum.name] = enum
|
||||||
|
else:
|
||||||
|
raise Exception('Invalid format, expected enum field comment or };')
|
||||||
|
elif state == State.InEnumMemberComment:
|
||||||
|
if line.startswith('///'):
|
||||||
|
comment += clean_comment_line(line)
|
||||||
|
else:
|
||||||
|
state = State.InEnum
|
||||||
|
enum.values.append(EnumValue(line.replace(',', ''), comment))
|
||||||
|
if state != State.Finished:
|
||||||
|
raise Exception('Not finished by the end of file')
|
||||||
|
|
||||||
|
for option in options:
|
||||||
|
if not option.type in ['bool', 'unsigned', 'int']:
|
||||||
|
if enums.has_key(option.type):
|
||||||
|
option.enum = enums[option.type]
|
||||||
|
else:
|
||||||
|
raise Exception('Unknown type: %s' % option.type)
|
||||||
|
return options
|
||||||
|
|
||||||
|
options = read_options(open(FORMAT_STYLE_FILE))
|
||||||
|
|
||||||
|
options = sorted(options, key=lambda x: x.name)
|
||||||
|
options_text = '\n\n'.join(map(str, options))
|
||||||
|
|
||||||
|
contents = open(DOC_FILE).read()
|
||||||
|
|
||||||
|
contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text)
|
||||||
|
|
||||||
|
with open(DOC_FILE, 'w') as output:
|
||||||
|
output.write(contents)
|
||||||
|
|
@ -15,8 +15,8 @@ NO_INSTALL = 1
|
|||||||
# No plugins, optimize startup time.
|
# No plugins, optimize startup time.
|
||||||
TOOL_NO_EXPORTS = 1
|
TOOL_NO_EXPORTS = 1
|
||||||
|
|
||||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter irreader \
|
||||||
linker selectiondag asmparser instrumentation
|
ipo linker selectiondag asmparser instrumentation option
|
||||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
||||||
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
|
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
|
||||||
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
|
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||||
#include "llvm/ExecutionEngine/JIT.h"
|
#include "llvm/ExecutionEngine/JIT.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/Support/FileSystem.h"
|
||||||
#include "llvm/Support/Host.h"
|
#include "llvm/Support/Host.h"
|
||||||
#include "llvm/Support/ManagedStatic.h"
|
#include "llvm/Support/ManagedStatic.h"
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
@ -34,11 +35,11 @@ using namespace clang::driver;
|
|||||||
// GetMainExecutable (since some platforms don't support taking the
|
// GetMainExecutable (since some platforms don't support taking the
|
||||||
// address of main, and some platforms can't implement GetMainExecutable
|
// address of main, and some platforms can't implement GetMainExecutable
|
||||||
// without being given the address of a function in the main executable).
|
// without being given the address of a function in the main executable).
|
||||||
llvm::sys::Path GetExecutablePath(const char *Argv0) {
|
std::string GetExecutablePath(const char *Argv0) {
|
||||||
// This just needs to be some symbol in the binary; C++ doesn't
|
// This just needs to be some symbol in the binary; C++ doesn't
|
||||||
// allow taking the address of ::main however.
|
// allow taking the address of ::main however.
|
||||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||||
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
|
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Execute(llvm::Module *Mod, char * const *envp) {
|
static int Execute(llvm::Module *Mod, char * const *envp) {
|
||||||
@ -67,14 +68,14 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
|
|||||||
|
|
||||||
int main(int argc, const char **argv, char * const *envp) {
|
int main(int argc, const char **argv, char * const *envp) {
|
||||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||||
llvm::sys::Path Path = GetExecutablePath(argv[0]);
|
std::string Path = GetExecutablePath(argv[0]);
|
||||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||||
TextDiagnosticPrinter *DiagClient =
|
TextDiagnosticPrinter *DiagClient =
|
||||||
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
||||||
|
|
||||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||||
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
|
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
|
||||||
Driver TheDriver(Path.str(), llvm::sys::getProcessTriple(), "a.out", Diags);
|
Driver TheDriver(Path, llvm::sys::getProcessTriple(), "a.out", Diags);
|
||||||
TheDriver.setTitle("clang interpreter");
|
TheDriver.setTitle("clang interpreter");
|
||||||
|
|
||||||
// FIXME: This is a hack to try to force the driver to do something we can
|
// FIXME: This is a hack to try to force the driver to do something we can
|
||||||
@ -94,7 +95,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
|||||||
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
|
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
|
||||||
SmallString<256> Msg;
|
SmallString<256> Msg;
|
||||||
llvm::raw_svector_ostream OS(Msg);
|
llvm::raw_svector_ostream OS(Msg);
|
||||||
C->PrintJob(OS, C->getJobs(), "; ", true);
|
Jobs.Print(OS, "; ", true);
|
||||||
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
|
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -117,7 +118,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
|||||||
// Show the invocation, with -v.
|
// Show the invocation, with -v.
|
||||||
if (CI->getHeaderSearchOpts().Verbose) {
|
if (CI->getHeaderSearchOpts().Verbose) {
|
||||||
llvm::errs() << "clang invocation:\n";
|
llvm::errs() << "clang invocation:\n";
|
||||||
C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
|
Jobs.Print(llvm::errs(), "\n", true);
|
||||||
llvm::errs() << "\n";
|
llvm::errs() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ typedef void * CXCompileCommand;
|
|||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/*
|
/*
|
||||||
* \brief No error occured
|
* \brief No error occurred
|
||||||
*/
|
*/
|
||||||
CXCompilationDatabase_NoError = 0,
|
CXCompilationDatabase_NoError = 0,
|
||||||
|
|
||||||
@ -141,6 +141,24 @@ clang_CompileCommand_getNumArgs(CXCompileCommand);
|
|||||||
CINDEX_LINKAGE CXString
|
CINDEX_LINKAGE CXString
|
||||||
clang_CompileCommand_getArg(CXCompileCommand, unsigned I);
|
clang_CompileCommand_getArg(CXCompileCommand, unsigned I);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the number of source mappings for the compiler invocation.
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE unsigned
|
||||||
|
clang_CompileCommand_getNumMappedSources(CXCompileCommand);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the I'th mapped source path for the compiler invocation.
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE CXString
|
||||||
|
clang_CompileCommand_getMappedSourcePath(CXCompileCommand, unsigned I);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the I'th mapped source content for the compiler invocation.
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE CXString
|
||||||
|
clang_CompileCommand_getMappedSourceContent(CXCompileCommand, unsigned I);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
@ -46,7 +46,7 @@ typedef struct {
|
|||||||
CINDEX_LINKAGE const char *clang_getCString(CXString string);
|
CINDEX_LINKAGE const char *clang_getCString(CXString string);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Free the given string,
|
* \brief Free the given string.
|
||||||
*/
|
*/
|
||||||
CINDEX_LINKAGE void clang_disposeString(CXString string);
|
CINDEX_LINKAGE void clang_disposeString(CXString string);
|
||||||
|
|
||||||
|
@ -16,9 +16,7 @@
|
|||||||
#ifndef CLANG_C_INDEX_H
|
#ifndef CLANG_C_INDEX_H
|
||||||
#define CLANG_C_INDEX_H
|
#define CLANG_C_INDEX_H
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "clang-c/Platform.h"
|
#include "clang-c/Platform.h"
|
||||||
#include "clang-c/CXString.h"
|
#include "clang-c/CXString.h"
|
||||||
@ -32,7 +30,7 @@
|
|||||||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||||
*/
|
*/
|
||||||
#define CINDEX_VERSION_MAJOR 0
|
#define CINDEX_VERSION_MAJOR 0
|
||||||
#define CINDEX_VERSION_MINOR 19
|
#define CINDEX_VERSION_MINOR 20
|
||||||
|
|
||||||
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
||||||
((major) * 10000) \
|
((major) * 10000) \
|
||||||
@ -413,6 +411,12 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
|
|||||||
*/
|
*/
|
||||||
CINDEX_LINKAGE int clang_Location_isInSystemHeader(CXSourceLocation location);
|
CINDEX_LINKAGE int clang_Location_isInSystemHeader(CXSourceLocation location);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns non-zero if the given source location is in the main file of
|
||||||
|
* the corresponding translation unit.
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE int clang_Location_isFromMainFile(CXSourceLocation location);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Retrieve a NULL (invalid) source range.
|
* \brief Retrieve a NULL (invalid) source range.
|
||||||
*/
|
*/
|
||||||
@ -723,7 +727,7 @@ CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
|
|||||||
* \brief Retrieve the child diagnostics of a CXDiagnostic.
|
* \brief Retrieve the child diagnostics of a CXDiagnostic.
|
||||||
*
|
*
|
||||||
* This CXDiagnosticSet does not need to be released by
|
* This CXDiagnosticSet does not need to be released by
|
||||||
* clang_diposeDiagnosticSet.
|
* clang_disposeDiagnosticSet.
|
||||||
*/
|
*/
|
||||||
CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
|
CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
|
||||||
|
|
||||||
@ -763,7 +767,7 @@ CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic);
|
|||||||
* \brief Options to control the display of diagnostics.
|
* \brief Options to control the display of diagnostics.
|
||||||
*
|
*
|
||||||
* The values in this enum are meant to be combined to customize the
|
* The values in this enum are meant to be combined to customize the
|
||||||
* behavior of \c clang_displayDiagnostic().
|
* behavior of \c clang_formatDiagnostic().
|
||||||
*/
|
*/
|
||||||
enum CXDiagnosticDisplayOptions {
|
enum CXDiagnosticDisplayOptions {
|
||||||
/**
|
/**
|
||||||
@ -850,7 +854,7 @@ CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic,
|
|||||||
* default behavior of the clang compiler.
|
* default behavior of the clang compiler.
|
||||||
*
|
*
|
||||||
* \returns A set of display options suitable for use with \c
|
* \returns A set of display options suitable for use with \c
|
||||||
* clang_displayDiagnostic().
|
* clang_formatDiagnostic().
|
||||||
*/
|
*/
|
||||||
CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
|
CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
|
||||||
|
|
||||||
@ -1942,7 +1946,7 @@ enum CXCursorKind {
|
|||||||
*/
|
*/
|
||||||
CXCursor_CompoundStmt = 202,
|
CXCursor_CompoundStmt = 202,
|
||||||
|
|
||||||
/** \brief A case statment.
|
/** \brief A case statement.
|
||||||
*/
|
*/
|
||||||
CXCursor_CaseStmt = 203,
|
CXCursor_CaseStmt = 203,
|
||||||
|
|
||||||
@ -2062,7 +2066,11 @@ enum CXCursorKind {
|
|||||||
*/
|
*/
|
||||||
CXCursor_DeclStmt = 231,
|
CXCursor_DeclStmt = 231,
|
||||||
|
|
||||||
CXCursor_LastStmt = CXCursor_DeclStmt,
|
/** \brief OpenMP parallel directive.
|
||||||
|
*/
|
||||||
|
CXCursor_OMPParallelDirective = 232,
|
||||||
|
|
||||||
|
CXCursor_LastStmt = CXCursor_OMPParallelDirective,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Cursor that represents the translation unit itself.
|
* \brief Cursor that represents the translation unit itself.
|
||||||
@ -2087,7 +2095,8 @@ enum CXCursorKind {
|
|||||||
CXCursor_CXXOverrideAttr = 405,
|
CXCursor_CXXOverrideAttr = 405,
|
||||||
CXCursor_AnnotateAttr = 406,
|
CXCursor_AnnotateAttr = 406,
|
||||||
CXCursor_AsmLabelAttr = 407,
|
CXCursor_AsmLabelAttr = 407,
|
||||||
CXCursor_LastAttr = CXCursor_AsmLabelAttr,
|
CXCursor_PackedAttr = 408,
|
||||||
|
CXCursor_LastAttr = CXCursor_PackedAttr,
|
||||||
|
|
||||||
/* Preprocessing */
|
/* Preprocessing */
|
||||||
CXCursor_PreprocessingDirective = 500,
|
CXCursor_PreprocessingDirective = 500,
|
||||||
@ -2666,7 +2675,11 @@ enum CXTypeKind {
|
|||||||
CXType_FunctionNoProto = 110,
|
CXType_FunctionNoProto = 110,
|
||||||
CXType_FunctionProto = 111,
|
CXType_FunctionProto = 111,
|
||||||
CXType_ConstantArray = 112,
|
CXType_ConstantArray = 112,
|
||||||
CXType_Vector = 113
|
CXType_Vector = 113,
|
||||||
|
CXType_IncompleteArray = 114,
|
||||||
|
CXType_VariableArray = 115,
|
||||||
|
CXType_DependentSizedArray = 116,
|
||||||
|
CXType_MemberPointer = 117
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2683,6 +2696,8 @@ enum CXCallingConv {
|
|||||||
CXCallingConv_AAPCS_VFP = 7,
|
CXCallingConv_AAPCS_VFP = 7,
|
||||||
CXCallingConv_PnaclCall = 8,
|
CXCallingConv_PnaclCall = 8,
|
||||||
CXCallingConv_IntelOclBicc = 9,
|
CXCallingConv_IntelOclBicc = 9,
|
||||||
|
CXCallingConv_X86_64Win64 = 10,
|
||||||
|
CXCallingConv_X86_64SysV = 11,
|
||||||
|
|
||||||
CXCallingConv_Invalid = 100,
|
CXCallingConv_Invalid = 100,
|
||||||
CXCallingConv_Unexposed = 200
|
CXCallingConv_Unexposed = 200
|
||||||
@ -2954,6 +2969,13 @@ enum CXTypeLayoutError {
|
|||||||
*/
|
*/
|
||||||
CINDEX_LINKAGE long long clang_Type_getAlignOf(CXType T);
|
CINDEX_LINKAGE long long clang_Type_getAlignOf(CXType T);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return the class type of an member pointer type.
|
||||||
|
*
|
||||||
|
* If a non-member-pointer type is passed in, an invalid type is returned.
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE CXType clang_Type_getClassType(CXType T);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return the size of a type in bytes as per C++[expr.sizeof] standard.
|
* \brief Return the size of a type in bytes as per C++[expr.sizeof] standard.
|
||||||
*
|
*
|
||||||
@ -2980,6 +3002,23 @@ CINDEX_LINKAGE long long clang_Type_getSizeOf(CXType T);
|
|||||||
*/
|
*/
|
||||||
CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S);
|
CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S);
|
||||||
|
|
||||||
|
enum CXRefQualifierKind {
|
||||||
|
/** \brief No ref-qualifier was provided. */
|
||||||
|
CXRefQualifier_None = 0,
|
||||||
|
/** \brief An lvalue ref-qualifier was provided (\c &). */
|
||||||
|
CXRefQualifier_LValue,
|
||||||
|
/** \brief An rvalue ref-qualifier was provided (\c &&). */
|
||||||
|
CXRefQualifier_RValue
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieve the ref-qualifier kind of a function or method.
|
||||||
|
*
|
||||||
|
* The ref-qualifier is returned for C++ functions or methods. For other types
|
||||||
|
* or non-C++ declarations, CXRefQualifier_None is returned.
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Returns non-zero if the cursor specifies a Record member that is a
|
* \brief Returns non-zero if the cursor specifies a Record member that is a
|
||||||
* bitfield.
|
* bitfield.
|
||||||
@ -3413,6 +3452,13 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
|
CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Given a cursor that represents an ObjC method or property declaration,
|
||||||
|
* return non-zero if the declaration was affected by "@optional".
|
||||||
|
* Returns zero if the cursor is not such a declaration or it is "@required".
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Returns non-zero if the given cursor is a variadic function or method.
|
* \brief Returns non-zero if the given cursor is a variadic function or method.
|
||||||
*/
|
*/
|
||||||
@ -4034,6 +4080,12 @@ CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Determine if a C++ member function or member function template is
|
||||||
|
* pure virtual.
|
||||||
|
*/
|
||||||
|
CINDEX_LINKAGE unsigned clang_CXXMethod_isPureVirtual(CXCursor C);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Determine if a C++ member function or member function template is
|
* \brief Determine if a C++ member function or member function template is
|
||||||
* declared 'static'.
|
* declared 'static'.
|
||||||
|
@ -97,6 +97,8 @@ class MigrationProcess {
|
|||||||
FileRemapper Remapper;
|
FileRemapper Remapper;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool HadARCErrors;
|
||||||
|
|
||||||
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
|
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
|
||||||
StringRef outputDir = StringRef());
|
StringRef outputDir = StringRef());
|
||||||
|
|
||||||
|
@ -57,14 +57,12 @@ class MigrateAction : public WrapperFrontendAction {
|
|||||||
/// \brief Migrates to modern ObjC syntax.
|
/// \brief Migrates to modern ObjC syntax.
|
||||||
class ObjCMigrateAction : public WrapperFrontendAction {
|
class ObjCMigrateAction : public WrapperFrontendAction {
|
||||||
std::string MigrateDir;
|
std::string MigrateDir;
|
||||||
bool MigrateLiterals;
|
unsigned ObjCMigAction;
|
||||||
bool MigrateSubscripting;
|
|
||||||
FileRemapper Remapper;
|
FileRemapper Remapper;
|
||||||
CompilerInstance *CompInst;
|
CompilerInstance *CompInst;
|
||||||
public:
|
public:
|
||||||
ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
||||||
bool migrateLiterals,
|
unsigned migrateAction);
|
||||||
bool migrateSubscripting);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
|
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
|
||||||
|
@ -53,7 +53,6 @@ class FileRemapper {
|
|||||||
StringRef outputDir = StringRef());
|
StringRef outputDir = StringRef());
|
||||||
|
|
||||||
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
|
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
|
||||||
void remap(StringRef filePath, StringRef newPath);
|
|
||||||
|
|
||||||
void applyMappings(PreprocessorOptions &PPOpts) const;
|
void applyMappings(PreprocessorOptions &PPOpts) const;
|
||||||
|
|
||||||
|
@ -168,6 +168,13 @@ class APValue {
|
|||||||
MakeUninit();
|
MakeUninit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Returns whether the object performed allocations.
|
||||||
|
///
|
||||||
|
/// If APValues are constructed via placement new, \c needsCleanup()
|
||||||
|
/// indicates whether the destructor must be called in order to correctly
|
||||||
|
/// free all allocated memory.
|
||||||
|
bool needsCleanup() const;
|
||||||
|
|
||||||
/// \brief Swaps the contents of this and the given APValue.
|
/// \brief Swaps the contents of this and the given APValue.
|
||||||
void swap(APValue &RHS);
|
void swap(APValue &RHS);
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
|
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
|
||||||
#define LLVM_CLANG_AST_ASTCONSUMER_H
|
#define LLVM_CLANG_AST_ASTCONSUMER_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class ASTContext;
|
class ASTContext;
|
||||||
class CXXRecordDecl;
|
class CXXRecordDecl;
|
||||||
@ -70,6 +72,10 @@ class ASTConsumer {
|
|||||||
/// can be defined in declspecs).
|
/// can be defined in declspecs).
|
||||||
virtual void HandleTagDeclDefinition(TagDecl *D) {}
|
virtual void HandleTagDeclDefinition(TagDecl *D) {}
|
||||||
|
|
||||||
|
/// \brief This callback is invoked the first time each TagDecl is required to
|
||||||
|
/// be complete.
|
||||||
|
virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) {}
|
||||||
|
|
||||||
/// \brief Invoked when a function is implicitly instantiated.
|
/// \brief Invoked when a function is implicitly instantiated.
|
||||||
/// Note that at this point point it does not have a body, its body is
|
/// Note that at this point point it does not have a body, its body is
|
||||||
/// instantiated at the end of the translation unit and passed to
|
/// instantiated at the end of the translation unit and passed to
|
||||||
@ -86,6 +92,21 @@ class ASTConsumer {
|
|||||||
/// The default implementation passes it to HandleTopLevelDecl.
|
/// The default implementation passes it to HandleTopLevelDecl.
|
||||||
virtual void HandleImplicitImportDecl(ImportDecl *D);
|
virtual void HandleImplicitImportDecl(ImportDecl *D);
|
||||||
|
|
||||||
|
/// \brief Handle a pragma that appends to Linker Options. Currently this
|
||||||
|
/// only exists to support Microsoft's #pragma comment(linker, "/foo").
|
||||||
|
virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
|
||||||
|
|
||||||
|
/// \brief Handle a pragma that emits a mismatch identifier and value to the
|
||||||
|
/// object file for the linker to work with. Currently, this only exists to
|
||||||
|
/// support Microsoft's #pragma detect_mismatch.
|
||||||
|
virtual void HandleDetectMismatch(llvm::StringRef Name,
|
||||||
|
llvm::StringRef Value) {}
|
||||||
|
|
||||||
|
/// \brief Handle a dependent library created by a pragma in the source.
|
||||||
|
/// Currently this only exists to support Microsoft's
|
||||||
|
/// #pragma comment(lib, "/foo").
|
||||||
|
virtual void HandleDependentLibrary(llvm::StringRef Lib) {}
|
||||||
|
|
||||||
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
|
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
|
||||||
/// unit to notify the consumer that the given tentative definition should be
|
/// unit to notify the consumer that the given tentative definition should be
|
||||||
/// completed.
|
/// completed.
|
||||||
|
@ -19,11 +19,9 @@
|
|||||||
#include "clang/AST/CanonicalType.h"
|
#include "clang/AST/CanonicalType.h"
|
||||||
#include "clang/AST/CommentCommandTraits.h"
|
#include "clang/AST/CommentCommandTraits.h"
|
||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/LambdaMangleContext.h"
|
|
||||||
#include "clang/AST/NestedNameSpecifier.h"
|
#include "clang/AST/NestedNameSpecifier.h"
|
||||||
#include "clang/AST/PrettyPrinter.h"
|
#include "clang/AST/PrettyPrinter.h"
|
||||||
#include "clang/AST/RawCommentList.h"
|
#include "clang/AST/RawCommentList.h"
|
||||||
#include "clang/AST/RecursiveASTVisitor.h"
|
|
||||||
#include "clang/AST/TemplateName.h"
|
#include "clang/AST/TemplateName.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/Basic/AddressSpaces.h"
|
#include "clang/Basic/AddressSpaces.h"
|
||||||
@ -47,6 +45,7 @@ namespace llvm {
|
|||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class FileManager;
|
class FileManager;
|
||||||
|
class AtomicExpr;
|
||||||
class ASTRecordLayout;
|
class ASTRecordLayout;
|
||||||
class BlockExpr;
|
class BlockExpr;
|
||||||
class CharUnits;
|
class CharUnits;
|
||||||
@ -55,9 +54,11 @@ namespace clang {
|
|||||||
class ExternalASTSource;
|
class ExternalASTSource;
|
||||||
class ASTMutationListener;
|
class ASTMutationListener;
|
||||||
class IdentifierTable;
|
class IdentifierTable;
|
||||||
|
class MaterializeTemporaryExpr;
|
||||||
class SelectorTable;
|
class SelectorTable;
|
||||||
class TargetInfo;
|
class TargetInfo;
|
||||||
class CXXABI;
|
class CXXABI;
|
||||||
|
class MangleNumberingContext;
|
||||||
// Decls
|
// Decls
|
||||||
class MangleContext;
|
class MangleContext;
|
||||||
class ObjCIvarDecl;
|
class ObjCIvarDecl;
|
||||||
@ -81,6 +82,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
|
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
|
||||||
mutable llvm::FoldingSet<ComplexType> ComplexTypes;
|
mutable llvm::FoldingSet<ComplexType> ComplexTypes;
|
||||||
mutable llvm::FoldingSet<PointerType> PointerTypes;
|
mutable llvm::FoldingSet<PointerType> PointerTypes;
|
||||||
|
mutable llvm::FoldingSet<DecayedType> DecayedTypes;
|
||||||
mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
|
mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
|
||||||
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
|
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
|
||||||
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
|
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
|
||||||
@ -146,7 +148,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
mutable TypeInfoMap MemoizedTypeInfo;
|
mutable TypeInfoMap MemoizedTypeInfo;
|
||||||
|
|
||||||
/// \brief A cache mapping from CXXRecordDecls to key functions.
|
/// \brief A cache mapping from CXXRecordDecls to key functions.
|
||||||
llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions;
|
llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions;
|
||||||
|
|
||||||
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
|
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
|
||||||
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
|
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
|
||||||
@ -163,6 +165,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
|
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
|
||||||
ClassScopeSpecializationPattern;
|
ClassScopeSpecializationPattern;
|
||||||
|
|
||||||
|
/// \brief Mapping from materialized temporaries with static storage duration
|
||||||
|
/// that appear in constant initializers to their evaluated values.
|
||||||
|
llvm::DenseMap<const MaterializeTemporaryExpr*, APValue>
|
||||||
|
MaterializedTemporaryValues;
|
||||||
|
|
||||||
/// \brief Representation of a "canonical" template template parameter that
|
/// \brief Representation of a "canonical" template template parameter that
|
||||||
/// is used in canonical template names.
|
/// is used in canonical template names.
|
||||||
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
|
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
|
||||||
@ -190,6 +197,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
|
|
||||||
/// \brief The typedef for the __uint128_t type.
|
/// \brief The typedef for the __uint128_t type.
|
||||||
mutable TypedefDecl *UInt128Decl;
|
mutable TypedefDecl *UInt128Decl;
|
||||||
|
|
||||||
|
/// \brief The typedef for the __float128 stub type.
|
||||||
|
mutable TypeDecl *Float128StubDecl;
|
||||||
|
|
||||||
/// \brief The typedef for the target specific predefined
|
/// \brief The typedef for the target specific predefined
|
||||||
/// __builtin_va_list type.
|
/// __builtin_va_list type.
|
||||||
@ -261,13 +271,30 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// wasting space in the Decl class.
|
/// wasting space in the Decl class.
|
||||||
llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs;
|
llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs;
|
||||||
|
|
||||||
/// \brief Keeps track of the static data member templates from which
|
/// \brief A mapping from non-redeclarable declarations in modules that were
|
||||||
/// static data members of class template specializations were instantiated.
|
/// merged with other declarations to the canonical declaration that they were
|
||||||
|
/// merged into.
|
||||||
|
llvm::DenseMap<Decl*, Decl*> MergedDecls;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// \brief A type synonym for the TemplateOrInstantiation mapping.
|
||||||
|
typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *>
|
||||||
|
TemplateOrSpecializationInfo;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// \brief A mapping to contain the template or declaration that
|
||||||
|
/// a variable declaration describes or was instantiated from,
|
||||||
|
/// respectively.
|
||||||
///
|
///
|
||||||
/// This data structure stores the mapping from instantiations of static
|
/// For non-templates, this value will be NULL. For variable
|
||||||
/// data members to the static data member representations within the
|
/// declarations that describe a variable template, this will be a
|
||||||
/// class template from which they were instantiated along with the kind
|
/// pointer to a VarTemplateDecl. For static data members
|
||||||
/// of instantiation or specialization (a TemplateSpecializationKind - 1).
|
/// of class template specializations, this will be the
|
||||||
|
/// MemberSpecializationInfo referring to the member variable that was
|
||||||
|
/// instantiated or specialized. Thus, the mapping will keep track of
|
||||||
|
/// the static data member templates from which static data members of
|
||||||
|
/// class template specializations were instantiated.
|
||||||
///
|
///
|
||||||
/// Given the following example:
|
/// Given the following example:
|
||||||
///
|
///
|
||||||
@ -286,8 +313,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// This mapping will contain an entry that maps from the VarDecl for
|
/// This mapping will contain an entry that maps from the VarDecl for
|
||||||
/// X<int>::value to the corresponding VarDecl for X<T>::value (within the
|
/// X<int>::value to the corresponding VarDecl for X<T>::value (within the
|
||||||
/// class template X) and will be marked TSK_ImplicitInstantiation.
|
/// class template X) and will be marked TSK_ImplicitInstantiation.
|
||||||
llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>
|
llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>
|
||||||
InstantiatedFromStaticDataMember;
|
TemplateOrInstantiation;
|
||||||
|
|
||||||
/// \brief Keeps track of the declaration from which a UsingDecl was
|
/// \brief Keeps track of the declaration from which a UsingDecl was
|
||||||
/// created during instantiation.
|
/// created during instantiation.
|
||||||
@ -328,12 +355,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
|
typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
|
||||||
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
|
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
|
||||||
|
|
||||||
/// \brief Mapping from each declaration context to its corresponding lambda
|
/// \brief Mapping from each declaration context to its corresponding
|
||||||
/// mangling context.
|
/// mangling numbering context (used for constructs like lambdas which
|
||||||
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
|
/// need to be consistently numbered for the mangler).
|
||||||
|
llvm::DenseMap<const DeclContext *, MangleNumberingContext *>
|
||||||
|
MangleNumberingContexts;
|
||||||
|
|
||||||
llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts;
|
/// \brief Side-table of mangling numbers for declarations which rarely
|
||||||
llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers;
|
/// need them (like static local vars).
|
||||||
|
llvm::DenseMap<const NamedDecl *, unsigned> MangleNumbers;
|
||||||
|
|
||||||
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
|
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
|
||||||
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
|
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
|
||||||
@ -368,6 +398,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// \brief The logical -> physical address space map.
|
/// \brief The logical -> physical address space map.
|
||||||
const LangAS::Map *AddrSpaceMap;
|
const LangAS::Map *AddrSpaceMap;
|
||||||
|
|
||||||
|
/// \brief Address space map mangling must be used with language specific
|
||||||
|
/// address spaces (e.g. OpenCL/CUDA)
|
||||||
|
bool AddrSpaceMapMangling;
|
||||||
|
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
friend class ASTReader;
|
friend class ASTReader;
|
||||||
friend class ASTWriter;
|
friend class ASTWriter;
|
||||||
@ -419,22 +453,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
return getParents(ast_type_traits::DynTypedNode::create(Node));
|
return getParents(ast_type_traits::DynTypedNode::create(Node));
|
||||||
}
|
}
|
||||||
|
|
||||||
ParentVector getParents(const ast_type_traits::DynTypedNode &Node) {
|
ParentVector getParents(const ast_type_traits::DynTypedNode &Node);
|
||||||
assert(Node.getMemoizationData() &&
|
|
||||||
"Invariant broken: only nodes that support memoization may be "
|
|
||||||
"used in the parent map.");
|
|
||||||
if (!AllParents) {
|
|
||||||
// We always need to run over the whole translation unit, as
|
|
||||||
// hasAncestor can escape any subtree.
|
|
||||||
AllParents.reset(
|
|
||||||
ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
|
|
||||||
}
|
|
||||||
ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
|
|
||||||
if (I == AllParents->end()) {
|
|
||||||
return ParentVector();
|
|
||||||
}
|
|
||||||
return I->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
const clang::PrintingPolicy &getPrintingPolicy() const {
|
const clang::PrintingPolicy &getPrintingPolicy() const {
|
||||||
return PrintingPolicy;
|
return PrintingPolicy;
|
||||||
@ -451,7 +470,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
return BumpAlloc;
|
return BumpAlloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *Allocate(unsigned Size, unsigned Align = 8) const {
|
void *Allocate(size_t Size, unsigned Align = 8) const {
|
||||||
return BumpAlloc.Allocate(Size, Align);
|
return BumpAlloc.Allocate(Size, Align);
|
||||||
}
|
}
|
||||||
void Deallocate(void *Ptr) const { }
|
void Deallocate(void *Ptr) const { }
|
||||||
@ -470,6 +489,19 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
|
|
||||||
const TargetInfo &getTargetInfo() const { return *Target; }
|
const TargetInfo &getTargetInfo() const { return *Target; }
|
||||||
|
|
||||||
|
/// getIntTypeForBitwidth -
|
||||||
|
/// sets integer QualTy according to specified details:
|
||||||
|
/// bitwidth, signed/unsigned.
|
||||||
|
/// Returns empty type if there is no appropriate target types.
|
||||||
|
QualType getIntTypeForBitwidth(unsigned DestWidth,
|
||||||
|
unsigned Signed) const;
|
||||||
|
/// getRealTypeForBitwidth -
|
||||||
|
/// sets floating point QualTy according to specified bitwidth.
|
||||||
|
/// Returns empty type if there is no appropriate target types.
|
||||||
|
QualType getRealTypeForBitwidth(unsigned DestWidth) const;
|
||||||
|
|
||||||
|
bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const;
|
||||||
|
|
||||||
const LangOptions& getLangOpts() const { return LangOpts; }
|
const LangOptions& getLangOpts() const { return LangOpts; }
|
||||||
|
|
||||||
DiagnosticsEngine &getDiagnostics() const;
|
DiagnosticsEngine &getDiagnostics() const;
|
||||||
@ -580,7 +612,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// preprocessor is not available.
|
/// preprocessor is not available.
|
||||||
comments::FullComment *getCommentForDecl(const Decl *D,
|
comments::FullComment *getCommentForDecl(const Decl *D,
|
||||||
const Preprocessor *PP) const;
|
const Preprocessor *PP) const;
|
||||||
|
|
||||||
|
/// Return parsed documentation comment attached to a given declaration.
|
||||||
|
/// Returns NULL if no comment is attached. Does not look at any
|
||||||
|
/// redeclarations of the declaration.
|
||||||
|
comments::FullComment *getLocalCommentForDeclUncached(const Decl *D) const;
|
||||||
|
|
||||||
comments::FullComment *cloneFullComment(comments::FullComment *FC,
|
comments::FullComment *cloneFullComment(comments::FullComment *FC,
|
||||||
const Decl *D) const;
|
const Decl *D) const;
|
||||||
|
|
||||||
@ -601,9 +638,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// \brief If this variable is an instantiated static data member of a
|
/// \brief If this variable is an instantiated static data member of a
|
||||||
/// class template specialization, returns the templated static data member
|
/// class template specialization, returns the templated static data member
|
||||||
/// from which it was instantiated.
|
/// from which it was instantiated.
|
||||||
|
// FIXME: Remove ?
|
||||||
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
|
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
|
||||||
const VarDecl *Var);
|
const VarDecl *Var);
|
||||||
|
|
||||||
|
TemplateOrSpecializationInfo
|
||||||
|
getTemplateOrSpecializationInfo(const VarDecl *Var);
|
||||||
|
|
||||||
FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
|
FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
|
||||||
|
|
||||||
void setClassScopeSpecializationPattern(FunctionDecl *FD,
|
void setClassScopeSpecializationPattern(FunctionDecl *FD,
|
||||||
@ -615,6 +656,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
TemplateSpecializationKind TSK,
|
TemplateSpecializationKind TSK,
|
||||||
SourceLocation PointOfInstantiation = SourceLocation());
|
SourceLocation PointOfInstantiation = SourceLocation());
|
||||||
|
|
||||||
|
void setTemplateOrSpecializationInfo(VarDecl *Inst,
|
||||||
|
TemplateOrSpecializationInfo TSI);
|
||||||
|
|
||||||
/// \brief If the given using decl \p Inst is an instantiation of a
|
/// \brief If the given using decl \p Inst is an instantiation of a
|
||||||
/// (possibly unresolved) using decl from a template instantiation,
|
/// (possibly unresolved) using decl from a template instantiation,
|
||||||
/// return it.
|
/// return it.
|
||||||
@ -632,31 +676,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
|
|
||||||
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
|
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
|
||||||
|
|
||||||
/// \brief Return \c true if \p FD is a zero-length bitfield which follows
|
|
||||||
/// the non-bitfield \p LastFD.
|
|
||||||
bool ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
|
|
||||||
const FieldDecl *LastFD) const;
|
|
||||||
|
|
||||||
/// \brief Return \c true if \p FD is a zero-length bitfield which follows
|
|
||||||
/// the bitfield \p LastFD.
|
|
||||||
bool ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
|
|
||||||
const FieldDecl *LastFD) const;
|
|
||||||
|
|
||||||
/// \brief Return \c true if \p FD is a bitfield which follows the bitfield
|
|
||||||
/// \p LastFD.
|
|
||||||
bool BitfieldFollowsBitfield(const FieldDecl *FD,
|
|
||||||
const FieldDecl *LastFD) const;
|
|
||||||
|
|
||||||
/// \brief Return \c true if \p FD is not a bitfield which follows the
|
|
||||||
/// bitfield \p LastFD.
|
|
||||||
bool NonBitfieldFollowsBitfield(const FieldDecl *FD,
|
|
||||||
const FieldDecl *LastFD) const;
|
|
||||||
|
|
||||||
/// \brief Return \c true if \p FD is a bitfield which follows the
|
|
||||||
/// non-bitfield \p LastFD.
|
|
||||||
bool BitfieldFollowsNonBitfield(const FieldDecl *FD,
|
|
||||||
const FieldDecl *LastFD) const;
|
|
||||||
|
|
||||||
// Access to the set of methods overridden by the given C++ method.
|
// Access to the set of methods overridden by the given C++ method.
|
||||||
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
|
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
|
||||||
overridden_cxx_method_iterator
|
overridden_cxx_method_iterator
|
||||||
@ -732,7 +751,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
return import_iterator(FirstLocalImport);
|
return import_iterator(FirstLocalImport);
|
||||||
}
|
}
|
||||||
import_iterator local_import_end() const { return import_iterator(); }
|
import_iterator local_import_end() const { return import_iterator(); }
|
||||||
|
|
||||||
|
Decl *getPrimaryMergedDecl(Decl *D) {
|
||||||
|
Decl *Result = MergedDecls.lookup(D);
|
||||||
|
return Result ? Result : D;
|
||||||
|
}
|
||||||
|
void setPrimaryMergedDecl(Decl *D, Decl *Primary) {
|
||||||
|
MergedDecls[D] = Primary;
|
||||||
|
}
|
||||||
|
|
||||||
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
|
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
|
||||||
|
|
||||||
|
|
||||||
@ -740,7 +767,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
CanQualType VoidTy;
|
CanQualType VoidTy;
|
||||||
CanQualType BoolTy;
|
CanQualType BoolTy;
|
||||||
CanQualType CharTy;
|
CanQualType CharTy;
|
||||||
CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
|
CanQualType WCharTy; // [C++ 3.9.1p5].
|
||||||
|
CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99.
|
||||||
CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions.
|
CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions.
|
||||||
CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
|
CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
|
||||||
CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
|
CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
|
||||||
@ -809,6 +837,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
|
|
||||||
/// \brief Retrieve the declaration for the 128-bit unsigned integer type.
|
/// \brief Retrieve the declaration for the 128-bit unsigned integer type.
|
||||||
TypedefDecl *getUInt128Decl() const;
|
TypedefDecl *getUInt128Decl() const;
|
||||||
|
|
||||||
|
/// \brief Retrieve the declaration for a 128-bit float stub type.
|
||||||
|
TypeDecl *getFloat128StubType() const;
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Type Constructors
|
// Type Constructors
|
||||||
@ -884,6 +915,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
|
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Return the uniqued reference to the decayed version of the given
|
||||||
|
/// type. Can only be called on array and function types which decay to
|
||||||
|
/// pointer types.
|
||||||
|
QualType getDecayedType(QualType T) const;
|
||||||
|
CanQualType getDecayedType(CanQualType T) const {
|
||||||
|
return CanQualType::CreateUnsafe(getDecayedType((QualType) T));
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Return the uniqued reference to the atomic type for the specified
|
/// \brief Return the uniqued reference to the atomic type for the specified
|
||||||
/// type.
|
/// type.
|
||||||
QualType getAtomicType(QualType T) const;
|
QualType getAtomicType(QualType T) const;
|
||||||
@ -1104,7 +1143,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
|
|
||||||
/// \brief C++11 deduced auto type.
|
/// \brief C++11 deduced auto type.
|
||||||
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
|
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
|
||||||
bool IsDependent = false) const;
|
bool IsDependent) const;
|
||||||
|
|
||||||
/// \brief C++11 deduction pattern for 'auto' type.
|
/// \brief C++11 deduction pattern for 'auto' type.
|
||||||
QualType getAutoDeductType() const;
|
QualType getAutoDeductType() const;
|
||||||
@ -1130,11 +1169,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// <stdint.h>.
|
/// <stdint.h>.
|
||||||
CanQualType getUIntMaxType() const;
|
CanQualType getUIntMaxType() const;
|
||||||
|
|
||||||
/// \brief In C++, this returns the unique wchar_t type. In C99, this
|
/// \brief Return the unique wchar_t type available in C++ (and available as
|
||||||
/// returns a type compatible with the type defined in <stddef.h> as defined
|
/// __wchar_t as a Microsoft extension).
|
||||||
/// by the target.
|
|
||||||
QualType getWCharType() const { return WCharTy; }
|
QualType getWCharType() const { return WCharTy; }
|
||||||
|
|
||||||
|
/// \brief Return the type of wide characters. In C++, this returns the
|
||||||
|
/// unique wchar_t type. In C99, this returns a type compatible with the type
|
||||||
|
/// defined in <stddef.h> as defined by the target.
|
||||||
|
QualType getWideCharType() const { return WideCharTy; }
|
||||||
|
|
||||||
/// \brief Return the type of "signed wchar_t".
|
/// \brief Return the type of "signed wchar_t".
|
||||||
///
|
///
|
||||||
/// Used when in C++, as a GCC extension.
|
/// Used when in C++, as a GCC extension.
|
||||||
@ -1607,14 +1650,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// \pre \p D must not be a bitfield type, as bitfields do not have a valid
|
/// \pre \p D must not be a bitfield type, as bitfields do not have a valid
|
||||||
/// alignment.
|
/// alignment.
|
||||||
///
|
///
|
||||||
/// If \p RefAsPointee, references are treated like their underlying type
|
/// If \p ForAlignof, references are treated like their underlying type
|
||||||
/// (for alignof), else they're treated like pointers (for CodeGen).
|
/// and large arrays don't get any special treatment. If not \p ForAlignof
|
||||||
CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false) const;
|
/// it computes the value expected by CodeGen: references are treated like
|
||||||
|
/// pointers and large arrays get extra alignment.
|
||||||
|
CharUnits getDeclAlign(const Decl *D, bool ForAlignof = false) const;
|
||||||
|
|
||||||
/// \brief Get or compute information about the layout of the specified
|
/// \brief Get or compute information about the layout of the specified
|
||||||
/// record (struct/union/class) \p D, which indicates its size and field
|
/// record (struct/union/class) \p D, which indicates its size and field
|
||||||
/// position information.
|
/// position information.
|
||||||
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const;
|
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
|
/// \brief Get or compute information about the layout of the specified
|
||||||
/// Objective-C interface.
|
/// Objective-C interface.
|
||||||
@ -1721,6 +1767,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
getCanonicalType(T2).getTypePtr();
|
getCanonicalType(T2).getTypePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
|
||||||
|
const ObjCMethodDecl *MethodImp);
|
||||||
|
|
||||||
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
|
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
|
||||||
|
|
||||||
/// \brief Retrieves the "canonical" nested name specifier for a
|
/// \brief Retrieves the "canonical" nested name specifier for a
|
||||||
@ -1749,19 +1798,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
NestedNameSpecifier *
|
NestedNameSpecifier *
|
||||||
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
|
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
|
||||||
|
|
||||||
/// \brief Retrieves the default calling convention to use for
|
/// \brief Retrieves the default calling convention for the current target.
|
||||||
/// C++ instance methods.
|
CallingConv getDefaultCallingConvention(bool isVariadic,
|
||||||
CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
|
bool IsCXXMethod) const;
|
||||||
|
|
||||||
/// \brief Retrieves the canonical representation of the given
|
|
||||||
/// calling convention.
|
|
||||||
CallingConv getCanonicalCallConv(CallingConv CC) const;
|
|
||||||
|
|
||||||
/// \brief Determines whether two calling conventions name the same
|
|
||||||
/// calling convention.
|
|
||||||
bool isSameCallConv(CallingConv lcc, CallingConv rcc) {
|
|
||||||
return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Retrieves the "canonical" template name that refers to a
|
/// \brief Retrieves the "canonical" template name that refers to a
|
||||||
/// given template.
|
/// given template.
|
||||||
@ -1899,6 +1938,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
return (*AddrSpaceMap)[AS - LangAS::Offset];
|
return (*AddrSpaceMap)[AS - LangAS::Offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool addressSpaceMapManglingFor(unsigned AS) const {
|
||||||
|
return AddrSpaceMapMangling ||
|
||||||
|
AS < LangAS::Offset ||
|
||||||
|
AS >= LangAS::Offset + LangAS::Count;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Helper for integer ordering
|
// Helper for integer ordering
|
||||||
unsigned getIntegerRank(const Type *T) const;
|
unsigned getIntegerRank(const Type *T) const;
|
||||||
@ -1925,7 +1970,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
bool isObjCSelType(QualType T) const {
|
bool isObjCSelType(QualType T) const {
|
||||||
return T == getObjCSelType();
|
return T == getObjCSelType();
|
||||||
}
|
}
|
||||||
bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
|
|
||||||
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
|
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
|
||||||
bool ForCompare);
|
bool ForCompare);
|
||||||
|
|
||||||
@ -2092,12 +2136,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// it is not used.
|
/// it is not used.
|
||||||
bool DeclMustBeEmitted(const Decl *D);
|
bool DeclMustBeEmitted(const Decl *D);
|
||||||
|
|
||||||
void addUnnamedTag(const TagDecl *Tag);
|
void setManglingNumber(const NamedDecl *ND, unsigned Number);
|
||||||
int getUnnamedTagManglingNumber(const TagDecl *Tag) const;
|
unsigned getManglingNumber(const NamedDecl *ND) const;
|
||||||
|
|
||||||
|
/// \brief Retrieve the context for computing mangling numbers in the given
|
||||||
|
/// DeclContext.
|
||||||
|
MangleNumberingContext &getManglingNumberContext(const DeclContext *DC);
|
||||||
|
|
||||||
|
MangleNumberingContext *createMangleNumberingContext() const;
|
||||||
|
|
||||||
/// \brief Retrieve the lambda mangling number for a lambda expression.
|
|
||||||
unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator);
|
|
||||||
|
|
||||||
/// \brief Used by ParmVarDecl to store on the side the
|
/// \brief Used by ParmVarDecl to store on the side the
|
||||||
/// index of the parameter when it exceeds the size of the normal bitfield.
|
/// index of the parameter when it exceeds the size of the normal bitfield.
|
||||||
void setParameterIndex(const ParmVarDecl *D, unsigned index);
|
void setParameterIndex(const ParmVarDecl *D, unsigned index);
|
||||||
@ -2105,7 +2152,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
/// \brief Used by ParmVarDecl to retrieve on the side the
|
/// \brief Used by ParmVarDecl to retrieve on the side the
|
||||||
/// index of the parameter when it exceeds the size of the normal bitfield.
|
/// index of the parameter when it exceeds the size of the normal bitfield.
|
||||||
unsigned getParameterIndex(const ParmVarDecl *D) const;
|
unsigned getParameterIndex(const ParmVarDecl *D) const;
|
||||||
|
|
||||||
|
/// \brief Get the storage for the constant value of a materialized temporary
|
||||||
|
/// of static storage duration.
|
||||||
|
APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
|
||||||
|
bool MayCreate);
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Statistics
|
// Statistics
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
@ -2197,93 +2249,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||||||
const ObjCImplementationDecl *Impl) const;
|
const ObjCImplementationDecl *Impl) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// \brief A set of deallocations that should be performed when the
|
/// \brief A set of deallocations that should be performed when the
|
||||||
/// ASTContext is destroyed.
|
/// ASTContext is destroyed.
|
||||||
SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations;
|
typedef llvm::SmallDenseMap<void(*)(void*), llvm::SmallVector<void*, 16> >
|
||||||
|
DeallocationMap;
|
||||||
|
DeallocationMap Deallocations;
|
||||||
|
|
||||||
// FIXME: This currently contains the set of StoredDeclMaps used
|
// FIXME: This currently contains the set of StoredDeclMaps used
|
||||||
// by DeclContext objects. This probably should not be in ASTContext,
|
// by DeclContext objects. This probably should not be in ASTContext,
|
||||||
// but we include it here so that ASTContext can quickly deallocate them.
|
// but we include it here so that ASTContext can quickly deallocate them.
|
||||||
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
|
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
|
||||||
|
|
||||||
/// \brief A counter used to uniquely identify "blocks".
|
|
||||||
mutable unsigned int UniqueBlockByRefTypeID;
|
|
||||||
|
|
||||||
friend class DeclContext;
|
friend class DeclContext;
|
||||||
friend class DeclarationNameTable;
|
friend class DeclarationNameTable;
|
||||||
void ReleaseDeclContextMaps();
|
void ReleaseDeclContextMaps();
|
||||||
|
|
||||||
/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
|
|
||||||
/// parents as defined by the \c RecursiveASTVisitor.
|
|
||||||
///
|
|
||||||
/// Note that the relationship described here is purely in terms of AST
|
|
||||||
/// traversal - there are other relationships (for example declaration context)
|
|
||||||
/// in the AST that are better modeled by special matchers.
|
|
||||||
///
|
|
||||||
/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
|
|
||||||
class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
|
|
||||||
public:
|
|
||||||
/// \brief Builds and returns the translation unit's parent map.
|
|
||||||
///
|
|
||||||
/// The caller takes ownership of the returned \c ParentMap.
|
|
||||||
static ParentMap *buildMap(TranslationUnitDecl &TU) {
|
|
||||||
ParentMapASTVisitor Visitor(new ParentMap);
|
|
||||||
Visitor.TraverseDecl(&TU);
|
|
||||||
return Visitor.Parents;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
|
|
||||||
|
|
||||||
ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shouldVisitTemplateInstantiations() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool shouldVisitImplicitCode() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Disables data recursion. We intercept Traverse* methods in the RAV, which
|
|
||||||
// are not triggered during data recursion.
|
|
||||||
bool shouldUseDataRecursionFor(clang::Stmt *S) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
|
|
||||||
if (Node == NULL)
|
|
||||||
return true;
|
|
||||||
if (ParentStack.size() > 0)
|
|
||||||
// FIXME: Currently we add the same parent multiple times, for example
|
|
||||||
// when we visit all subexpressions of template instantiations; this is
|
|
||||||
// suboptimal, bug benign: the only way to visit those is with
|
|
||||||
// hasAncestor / hasParent, and those do not create new matches.
|
|
||||||
// The plan is to enable DynTypedNode to be storable in a map or hash
|
|
||||||
// map. The main problem there is to implement hash functions /
|
|
||||||
// comparison operators for all types that DynTypedNode supports that
|
|
||||||
// do not have pointer identity.
|
|
||||||
(*Parents)[Node].push_back(ParentStack.back());
|
|
||||||
ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
|
|
||||||
bool Result = (this ->* traverse) (Node);
|
|
||||||
ParentStack.pop_back();
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TraverseDecl(Decl *DeclNode) {
|
|
||||||
return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TraverseStmt(Stmt *StmtNode) {
|
|
||||||
return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParentMap *Parents;
|
|
||||||
llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
|
|
||||||
|
|
||||||
friend class RecursiveASTVisitor<ParentMapASTVisitor>;
|
|
||||||
};
|
|
||||||
|
|
||||||
llvm::OwningPtr<ParentMap> AllParents;
|
llvm::OwningPtr<ParentMap> AllParents;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ namespace clang {
|
|||||||
namespace diag {
|
namespace diag {
|
||||||
enum {
|
enum {
|
||||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||||
#define ASTSTART
|
#define ASTSTART
|
||||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||||
#undef DIAG
|
#undef DIAG
|
||||||
|
28
include/clang/AST/ASTFwd.h
Normal file
28
include/clang/AST/ASTFwd.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//===--- ASTFwd.h ----------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===--------------------------------------------------------------===//
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Forward declaration of all AST node types.
|
||||||
|
///
|
||||||
|
//===-------------------------------------------------------------===//
|
||||||
|
|
||||||
|
namespace clang {
|
||||||
|
|
||||||
|
class Decl;
|
||||||
|
#define DECL(DERIVED, BASE) class DERIVED##Decl;
|
||||||
|
#include "clang/AST/DeclNodes.inc"
|
||||||
|
class Stmt;
|
||||||
|
#define STMT(DERIVED, BASE) class DERIVED;
|
||||||
|
#include "clang/AST/StmtNodes.inc"
|
||||||
|
class Type;
|
||||||
|
#define TYPE(DERIVED, BASE) class DERIVED##Type;
|
||||||
|
#include "clang/AST/TypeNodes.def"
|
||||||
|
class CXXCtorInitializer;
|
||||||
|
|
||||||
|
} // end namespace clang
|
@ -271,6 +271,14 @@ namespace clang {
|
|||||||
/// Subclasses can override this function to observe all of the \c From ->
|
/// Subclasses can override this function to observe all of the \c From ->
|
||||||
/// \c To declaration mappings as they are imported.
|
/// \c To declaration mappings as they are imported.
|
||||||
virtual Decl *Imported(Decl *From, Decl *To);
|
virtual Decl *Imported(Decl *From, Decl *To);
|
||||||
|
|
||||||
|
/// \brief Called by StructuralEquivalenceContext. If a RecordDecl is
|
||||||
|
/// being compared to another RecordDecl as part of import, completing the
|
||||||
|
/// other RecordDecl may trigger importation of the first RecordDecl. This
|
||||||
|
/// happens especially for anonymous structs. If the original of the second
|
||||||
|
/// RecordDecl can be found, we can complete it without the need for
|
||||||
|
/// importation, eliminating this loop.
|
||||||
|
virtual Decl *GetOriginalDecl(Decl *To) { return NULL; }
|
||||||
|
|
||||||
/// \brief Determine whether the given types are structurally
|
/// \brief Determine whether the given types are structurally
|
||||||
/// equivalent.
|
/// equivalent.
|
||||||
|
80
include/clang/AST/ASTLambda.h
Normal file
80
include/clang/AST/ASTLambda.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
//===--- ASTLambda.h - Lambda Helper Functions --------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief This file provides some common utility functions for processing
|
||||||
|
/// Lambda related AST Constructs.
|
||||||
|
///
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_CLANG_AST_LAMBDA_H
|
||||||
|
#define LLVM_CLANG_AST_LAMBDA_H
|
||||||
|
|
||||||
|
#include "clang/AST/DeclCXX.h"
|
||||||
|
#include "clang/AST/DeclTemplate.h"
|
||||||
|
|
||||||
|
namespace clang {
|
||||||
|
inline StringRef getLambdaStaticInvokerName() {
|
||||||
|
return "__invoke";
|
||||||
|
}
|
||||||
|
// This function returns true if M is a specialization, a template,
|
||||||
|
// or a non-generic lambda call operator.
|
||||||
|
inline bool isLambdaCallOperator(const CXXMethodDecl *MD) {
|
||||||
|
const CXXRecordDecl *LambdaClass = MD->getParent();
|
||||||
|
if (!LambdaClass || !LambdaClass->isLambda()) return false;
|
||||||
|
return MD->getOverloadedOperator() == OO_Call;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isLambdaCallOperator(const DeclContext *DC) {
|
||||||
|
if (!DC || !isa<CXXMethodDecl>(DC)) return false;
|
||||||
|
return isLambdaCallOperator(cast<CXXMethodDecl>(DC));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
|
||||||
|
if (!MD) return false;
|
||||||
|
CXXRecordDecl *LambdaClass = MD->getParent();
|
||||||
|
if (LambdaClass && LambdaClass->isGenericLambda())
|
||||||
|
return isLambdaCallOperator(MD) &&
|
||||||
|
MD->isFunctionTemplateSpecialization();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isLambdaConversionOperator(CXXConversionDecl *C) {
|
||||||
|
return C ? C->getParent()->isLambda() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isLambdaConversionOperator(Decl *D) {
|
||||||
|
if (!D) return false;
|
||||||
|
if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D))
|
||||||
|
return isLambdaConversionOperator(Conv);
|
||||||
|
if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D))
|
||||||
|
if (CXXConversionDecl *Conv =
|
||||||
|
dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl()))
|
||||||
|
return isLambdaConversionOperator(Conv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) {
|
||||||
|
return isGenericLambdaCallOperatorSpecialization(
|
||||||
|
dyn_cast<CXXMethodDecl>(DC));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This returns the parent DeclContext ensuring that the correct
|
||||||
|
// parent DeclContext is returned for Lambdas
|
||||||
|
inline DeclContext *getLambdaAwareParentOfDeclContext(DeclContext *DC) {
|
||||||
|
if (isLambdaCallOperator(DC))
|
||||||
|
return DC->getParent()->getParent();
|
||||||
|
else
|
||||||
|
return DC->getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // clang
|
||||||
|
|
||||||
|
#endif // LLVM_CLANG_AST_LAMBDA_H
|
@ -27,8 +27,11 @@ namespace clang {
|
|||||||
class ObjCContainerDecl;
|
class ObjCContainerDecl;
|
||||||
class ObjCInterfaceDecl;
|
class ObjCInterfaceDecl;
|
||||||
class ObjCPropertyDecl;
|
class ObjCPropertyDecl;
|
||||||
|
class QualType;
|
||||||
class TagDecl;
|
class TagDecl;
|
||||||
class VarDecl;
|
class VarDecl;
|
||||||
|
class VarTemplateDecl;
|
||||||
|
class VarTemplateSpecializationDecl;
|
||||||
|
|
||||||
/// \brief An abstract interface that should be implemented by listeners
|
/// \brief An abstract interface that should be implemented by listeners
|
||||||
/// that want to be notified when an AST entity gets modified after its
|
/// that want to be notified when an AST entity gets modified after its
|
||||||
@ -51,11 +54,20 @@ class ASTMutationListener {
|
|||||||
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
|
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
|
||||||
const ClassTemplateSpecializationDecl *D) {}
|
const ClassTemplateSpecializationDecl *D) {}
|
||||||
|
|
||||||
|
/// \brief A template specialization (or partial one) was added to the
|
||||||
|
/// template declaration.
|
||||||
|
virtual void
|
||||||
|
AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
|
||||||
|
const VarTemplateSpecializationDecl *D) {}
|
||||||
|
|
||||||
/// \brief A template specialization (or partial one) was added to the
|
/// \brief A template specialization (or partial one) was added to the
|
||||||
/// template declaration.
|
/// template declaration.
|
||||||
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
|
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
|
||||||
const FunctionDecl *D) {}
|
const FunctionDecl *D) {}
|
||||||
|
|
||||||
|
/// \brief A function's return type has been deduced.
|
||||||
|
virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
|
||||||
|
|
||||||
/// \brief An implicit member got a definition.
|
/// \brief An implicit member got a definition.
|
||||||
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
|
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
|
||||||
|
|
||||||
@ -78,6 +90,11 @@ class ASTMutationListener {
|
|||||||
const ObjCPropertyDecl *OrigProp,
|
const ObjCPropertyDecl *OrigProp,
|
||||||
const ObjCCategoryDecl *ClassExt) {}
|
const ObjCCategoryDecl *ClassExt) {}
|
||||||
|
|
||||||
|
/// \brief A declaration is marked used which was not previously marked used.
|
||||||
|
///
|
||||||
|
/// \param D the declaration marked used
|
||||||
|
virtual void DeclarationMarkedUsed(const Decl *D) {}
|
||||||
|
|
||||||
// NOTE: If new methods are added they should also be added to
|
// NOTE: If new methods are added they should also be added to
|
||||||
// MultiplexASTMutationListener.
|
// MultiplexASTMutationListener.
|
||||||
};
|
};
|
||||||
|
@ -7,22 +7,132 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// Provides a dynamically typed node container that can be used to store
|
// Provides a dynamic type identifier and a dynamically typed node container
|
||||||
// an AST base node at runtime in the same storage in a type safe way.
|
// that can be used to store an AST base node at runtime in the same storage in
|
||||||
|
// a type safe way.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
|
#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
|
||||||
#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
|
#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
|
||||||
|
|
||||||
|
#include "clang/AST/ASTFwd.h"
|
||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
|
#include "clang/AST/NestedNameSpecifier.h"
|
||||||
#include "clang/AST/Stmt.h"
|
#include "clang/AST/Stmt.h"
|
||||||
|
#include "clang/AST/TemplateBase.h"
|
||||||
#include "clang/AST/TypeLoc.h"
|
#include "clang/AST/TypeLoc.h"
|
||||||
|
#include "clang/Basic/LLVM.h"
|
||||||
#include "llvm/Support/AlignOf.h"
|
#include "llvm/Support/AlignOf.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
class raw_ostream;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
|
struct PrintingPolicy;
|
||||||
|
|
||||||
namespace ast_type_traits {
|
namespace ast_type_traits {
|
||||||
|
|
||||||
|
/// \brief Kind identifier.
|
||||||
|
///
|
||||||
|
/// It can be constructed from any node kind and allows for runtime type
|
||||||
|
/// hierarchy checks.
|
||||||
|
/// Use getFromNodeKind<T>() to construct them.
|
||||||
|
class ASTNodeKind {
|
||||||
|
public:
|
||||||
|
/// \brief Empty identifier. It matches nothing.
|
||||||
|
ASTNodeKind() : KindId(NKI_None) {}
|
||||||
|
|
||||||
|
/// \brief Construct an identifier for T.
|
||||||
|
template <class T>
|
||||||
|
static ASTNodeKind getFromNodeKind() {
|
||||||
|
return ASTNodeKind(KindToKindId<T>::Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns \c true if \c this and \c Other represent the same kind.
|
||||||
|
bool isSame(ASTNodeKind Other) const;
|
||||||
|
|
||||||
|
/// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
|
||||||
|
bool isBaseOf(ASTNodeKind Other) const;
|
||||||
|
|
||||||
|
/// \brief String representation of the kind.
|
||||||
|
StringRef asStringRef() const;
|
||||||
|
|
||||||
|
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_Decl,
|
||||||
|
#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
|
||||||
|
#include "clang/AST/DeclNodes.inc"
|
||||||
|
NKI_Stmt,
|
||||||
|
#define STMT(DERIVED, BASE) NKI_##DERIVED,
|
||||||
|
#include "clang/AST/StmtNodes.inc"
|
||||||
|
NKI_Type,
|
||||||
|
#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
|
||||||
|
#include "clang/AST/TypeNodes.def"
|
||||||
|
NKI_NumberOfKinds
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Use getFromNodeKind<T>() to construct the kind.
|
||||||
|
ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
|
||||||
|
|
||||||
|
/// \brief Returns \c true if \c Base is a base kind of (or same as) \c
|
||||||
|
/// Derived.
|
||||||
|
static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
|
||||||
|
|
||||||
|
/// \brief Helper meta-function to convert a kind T to its enum value.
|
||||||
|
///
|
||||||
|
/// This struct is specialized below for all known kinds.
|
||||||
|
template <class T> struct KindToKindId {
|
||||||
|
static const NodeKindId Id = NKI_None;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Per kind info.
|
||||||
|
struct KindInfo {
|
||||||
|
/// \brief The id of the parent kind, or None if it has no parent.
|
||||||
|
NodeKindId ParentId;
|
||||||
|
/// \brief Name of the kind.
|
||||||
|
const char *Name;
|
||||||
|
};
|
||||||
|
static const KindInfo AllKindInfo[NKI_NumberOfKinds];
|
||||||
|
|
||||||
|
NodeKindId KindId;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define KIND_TO_KIND_ID(Class) \
|
||||||
|
template <> struct ASTNodeKind::KindToKindId<Class> { \
|
||||||
|
static const NodeKindId Id = NKI_##Class; \
|
||||||
|
};
|
||||||
|
KIND_TO_KIND_ID(CXXCtorInitializer)
|
||||||
|
KIND_TO_KIND_ID(TemplateArgument)
|
||||||
|
KIND_TO_KIND_ID(NestedNameSpecifier)
|
||||||
|
KIND_TO_KIND_ID(NestedNameSpecifierLoc)
|
||||||
|
KIND_TO_KIND_ID(QualType)
|
||||||
|
KIND_TO_KIND_ID(TypeLoc)
|
||||||
|
KIND_TO_KIND_ID(Decl)
|
||||||
|
KIND_TO_KIND_ID(Stmt)
|
||||||
|
KIND_TO_KIND_ID(Type)
|
||||||
|
#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
|
||||||
|
#include "clang/AST/DeclNodes.inc"
|
||||||
|
#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
|
||||||
|
#include "clang/AST/StmtNodes.inc"
|
||||||
|
#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
|
||||||
|
#include "clang/AST/TypeNodes.def"
|
||||||
|
#undef KIND_TO_KIND_ID
|
||||||
|
|
||||||
/// \brief A dynamically typed AST node container.
|
/// \brief A dynamically typed AST node container.
|
||||||
///
|
///
|
||||||
/// Stores an AST node in a type safe way. This allows writing code that
|
/// Stores an AST node in a type safe way. This allows writing code that
|
||||||
@ -32,7 +142,7 @@ namespace ast_type_traits {
|
|||||||
/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
|
/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
|
||||||
/// and \c get<T>() to retrieve the node as type T if the types match.
|
/// and \c get<T>() to retrieve the node as type T if the types match.
|
||||||
///
|
///
|
||||||
/// See \c NodeTypeTag for which node base types are currently supported;
|
/// See \c ASTNodeKind for which node base types are currently supported;
|
||||||
/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
|
/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
|
||||||
/// the supported base types.
|
/// the supported base types.
|
||||||
class DynTypedNode {
|
class DynTypedNode {
|
||||||
@ -49,15 +159,15 @@ class DynTypedNode {
|
|||||||
/// convertible to \c T.
|
/// convertible to \c T.
|
||||||
///
|
///
|
||||||
/// For types that have identity via their pointer in the AST
|
/// For types that have identity via their pointer in the AST
|
||||||
/// (like \c Stmt and \c Decl) the returned pointer points to the
|
/// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
|
||||||
/// referenced AST node.
|
/// pointer points to the referenced AST node.
|
||||||
/// For other types (like \c QualType) the value is stored directly
|
/// For other types (like \c QualType) the value is stored directly
|
||||||
/// in the \c DynTypedNode, and the returned pointer points at
|
/// in the \c DynTypedNode, and the returned pointer points at
|
||||||
/// the storage inside DynTypedNode. For those nodes, do not
|
/// the storage inside DynTypedNode. For those nodes, do not
|
||||||
/// use the pointer outside the scope of the DynTypedNode.
|
/// use the pointer outside the scope of the DynTypedNode.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T *get() const {
|
const T *get() const {
|
||||||
return BaseConverter<T>::get(Tag, Storage.buffer);
|
return BaseConverter<T>::get(NodeKind, Storage.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns a pointer that identifies the stored AST node.
|
/// \brief Returns a pointer that identifies the stored AST node.
|
||||||
@ -67,142 +177,171 @@ class DynTypedNode {
|
|||||||
/// method returns NULL.
|
/// method returns NULL.
|
||||||
const void *getMemoizationData() const;
|
const void *getMemoizationData() const;
|
||||||
|
|
||||||
|
/// \brief Prints the node to the given output stream.
|
||||||
|
void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
|
||||||
|
|
||||||
|
/// \brief Dumps the node to the given output stream.
|
||||||
|
void dump(llvm::raw_ostream &OS, SourceManager &SM) const;
|
||||||
|
|
||||||
|
/// \brief For nodes which represent textual entities in the source code,
|
||||||
|
/// return their SourceRange. For all other nodes, return SourceRange().
|
||||||
|
SourceRange getSourceRange() const;
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// \brief Imposes an order on \c DynTypedNode.
|
||||||
|
///
|
||||||
|
/// Supports comparison of nodes that support memoization.
|
||||||
|
/// FIXME: Implement comparsion for other node types (currently
|
||||||
|
/// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
|
||||||
|
bool operator<(const DynTypedNode &Other) const {
|
||||||
|
assert(getMemoizationData() && Other.getMemoizationData());
|
||||||
|
return getMemoizationData() < Other.getMemoizationData();
|
||||||
|
}
|
||||||
|
bool operator==(const DynTypedNode &Other) const {
|
||||||
|
// Nodes with different types cannot be equal.
|
||||||
|
if (!NodeKind.isSame(Other.NodeKind))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// FIXME: Implement for other types.
|
||||||
|
if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
|
||||||
|
return *get<QualType>() == *Other.get<QualType>();
|
||||||
|
}
|
||||||
|
assert(getMemoizationData() && Other.getMemoizationData());
|
||||||
|
return getMemoizationData() == Other.getMemoizationData();
|
||||||
|
}
|
||||||
|
bool operator!=(const DynTypedNode &Other) const {
|
||||||
|
return !operator==(Other);
|
||||||
|
}
|
||||||
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// \brief Takes care of converting from and to \c T.
|
/// \brief Takes care of converting from and to \c T.
|
||||||
template <typename T, typename EnablerT = void> struct BaseConverter;
|
template <typename T, typename EnablerT = void> struct BaseConverter;
|
||||||
|
|
||||||
/// \brief Supported base node types.
|
/// \brief Converter that uses dyn_cast<T> from a stored BaseT*.
|
||||||
enum NodeTypeTag {
|
template <typename T, typename BaseT> struct DynCastPtrConverter {
|
||||||
NT_Decl,
|
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||||
NT_Stmt,
|
if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
|
||||||
NT_NestedNameSpecifier,
|
return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
|
||||||
NT_NestedNameSpecifierLoc,
|
return NULL;
|
||||||
NT_QualType,
|
}
|
||||||
NT_Type,
|
static DynTypedNode create(const BaseT &Node) {
|
||||||
NT_TypeLoc
|
DynTypedNode Result;
|
||||||
} Tag;
|
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
|
||||||
|
new (Result.Storage.buffer) const BaseT * (&Node);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Converter that stores T* (by pointer).
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
static DynTypedNode create(const T &Node) {
|
||||||
|
DynTypedNode Result;
|
||||||
|
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
|
||||||
|
new (Result.Storage.buffer) const T * (&Node);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Converter that stores T (by value).
|
||||||
|
template <typename T> struct ValueConverter {
|
||||||
|
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||||
|
if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
|
||||||
|
return reinterpret_cast<const T *>(Storage);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static DynTypedNode create(const T &Node) {
|
||||||
|
DynTypedNode Result;
|
||||||
|
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
|
||||||
|
new (Result.Storage.buffer) T(Node);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ASTNodeKind NodeKind;
|
||||||
|
|
||||||
/// \brief Stores the data of the node.
|
/// \brief Stores the data of the node.
|
||||||
///
|
///
|
||||||
/// Note that we can store \c Decls and \c Stmts by pointer as they are
|
/// Note that we can store \c Decls, \c Stmts, \c Types,
|
||||||
/// guaranteed to be unique pointers pointing to dedicated storage in the
|
/// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
|
||||||
/// AST. \c QualTypes on the other hand do not have storage or unique
|
/// guaranteed to be unique pointers pointing to dedicated storage in the AST.
|
||||||
|
/// \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.
|
/// pointers and thus need to be stored by value.
|
||||||
llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
|
typedef llvm::AlignedCharArrayUnion<
|
||||||
NestedNameSpecifierLoc, QualType, Type,
|
Decl *, Stmt *, Type *, NestedNameSpecifier *, CXXCtorInitializer *>
|
||||||
TypeLoc> Storage;
|
KindsByPointer;
|
||||||
|
llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
|
||||||
|
NestedNameSpecifierLoc, QualType, TypeLoc>
|
||||||
|
Storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Pull out abstraction for the following.
|
template <typename T>
|
||||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
struct DynTypedNode::BaseConverter<
|
||||||
typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
|
T, typename llvm::enable_if<llvm::is_base_of<
|
||||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {};
|
||||||
if (Tag == NT_Decl)
|
|
||||||
return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
|
template <typename T>
|
||||||
return NULL;
|
struct DynTypedNode::BaseConverter<
|
||||||
}
|
T, typename llvm::enable_if<llvm::is_base_of<
|
||||||
static DynTypedNode create(const Decl &Node) {
|
Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {};
|
||||||
DynTypedNode Result;
|
|
||||||
Result.Tag = NT_Decl;
|
template <typename T>
|
||||||
new (Result.Storage.buffer) const Decl*(&Node);
|
struct DynTypedNode::BaseConverter<
|
||||||
return Result;
|
T, typename llvm::enable_if<llvm::is_base_of<
|
||||||
}
|
Type, T> >::type> : public DynCastPtrConverter<T, Type> {};
|
||||||
};
|
|
||||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
template <>
|
||||||
typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
|
struct DynTypedNode::BaseConverter<
|
||||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
|
||||||
if (Tag == NT_Stmt)
|
|
||||||
return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
|
template <>
|
||||||
return NULL;
|
struct DynTypedNode::BaseConverter<
|
||||||
}
|
CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
|
||||||
static DynTypedNode create(const Stmt &Node) {
|
|
||||||
DynTypedNode Result;
|
template <>
|
||||||
Result.Tag = NT_Stmt;
|
struct DynTypedNode::BaseConverter<
|
||||||
new (Result.Storage.buffer) const Stmt*(&Node);
|
TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
|
||||||
return Result;
|
|
||||||
}
|
template <>
|
||||||
};
|
struct DynTypedNode::BaseConverter<
|
||||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
NestedNameSpecifierLoc,
|
||||||
typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
|
void> : public ValueConverter<NestedNameSpecifierLoc> {};
|
||||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
|
||||||
if (Tag == NT_Type)
|
template <>
|
||||||
return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
|
struct DynTypedNode::BaseConverter<QualType,
|
||||||
return NULL;
|
void> : public ValueConverter<QualType> {};
|
||||||
}
|
|
||||||
static DynTypedNode create(const Type &Node) {
|
template <>
|
||||||
DynTypedNode Result;
|
struct DynTypedNode::BaseConverter<
|
||||||
Result.Tag = NT_Type;
|
TypeLoc, void> : public ValueConverter<TypeLoc> {};
|
||||||
new (Result.Storage.buffer) const Type*(&Node);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
|
|
||||||
static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
|
|
||||||
if (Tag == NT_NestedNameSpecifier)
|
|
||||||
return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
static DynTypedNode create(const NestedNameSpecifier &Node) {
|
|
||||||
DynTypedNode Result;
|
|
||||||
Result.Tag = NT_NestedNameSpecifier;
|
|
||||||
new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
|
|
||||||
static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
|
|
||||||
const char Storage[]) {
|
|
||||||
if (Tag == NT_NestedNameSpecifierLoc)
|
|
||||||
return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
|
|
||||||
DynTypedNode Result;
|
|
||||||
Result.Tag = NT_NestedNameSpecifierLoc;
|
|
||||||
new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<> struct DynTypedNode::BaseConverter<QualType, void> {
|
|
||||||
static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
|
|
||||||
if (Tag == NT_QualType)
|
|
||||||
return reinterpret_cast<const QualType*>(Storage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
static DynTypedNode create(const QualType &Node) {
|
|
||||||
DynTypedNode Result;
|
|
||||||
Result.Tag = NT_QualType;
|
|
||||||
new (Result.Storage.buffer) QualType(Node);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
|
|
||||||
static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
|
|
||||||
if (Tag == NT_TypeLoc)
|
|
||||||
return reinterpret_cast<const TypeLoc*>(Storage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
static DynTypedNode create(const TypeLoc &Node) {
|
|
||||||
DynTypedNode Result;
|
|
||||||
Result.Tag = NT_TypeLoc;
|
|
||||||
new (Result.Storage.buffer) TypeLoc(Node);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// The only operation we allow on unsupported types is \c get.
|
// The only operation we allow on unsupported types is \c get.
|
||||||
// This allows to conveniently use \c DynTypedNode when having an arbitrary
|
// This allows to conveniently use \c DynTypedNode when having an arbitrary
|
||||||
// AST node that is not supported, but prevents misuse - a user cannot create
|
// AST node that is not supported, but prevents misuse - a user cannot create
|
||||||
// a DynTypedNode from arbitrary types.
|
// a DynTypedNode from arbitrary types.
|
||||||
template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
|
template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
|
||||||
static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
|
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const void *DynTypedNode::getMemoizationData() const {
|
inline const void *DynTypedNode::getMemoizationData() const {
|
||||||
switch (Tag) {
|
if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
|
||||||
case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
|
return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
|
||||||
case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
|
} else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
|
||||||
default: return NULL;
|
return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
|
||||||
};
|
} else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) {
|
||||||
|
return BaseConverter<Type>::get(NodeKind, Storage.buffer);
|
||||||
|
} else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
|
||||||
|
return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace ast_type_traits
|
} // end namespace ast_type_traits
|
||||||
|
@ -22,12 +22,21 @@ namespace clang {
|
|||||||
|
|
||||||
/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
|
/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
|
||||||
class ASTUnresolvedSet {
|
class ASTUnresolvedSet {
|
||||||
typedef ASTVector<DeclAccessPair> DeclsTy;
|
struct DeclsTy : ASTVector<DeclAccessPair> {
|
||||||
|
DeclsTy() {}
|
||||||
|
DeclsTy(ASTContext &C, unsigned N) : ASTVector<DeclAccessPair>(C, N) {}
|
||||||
|
|
||||||
|
bool isLazy() const { return getTag(); }
|
||||||
|
void setLazy(bool Lazy) { setTag(Lazy); }
|
||||||
|
};
|
||||||
|
|
||||||
DeclsTy Decls;
|
DeclsTy Decls;
|
||||||
|
|
||||||
ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
||||||
void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
||||||
|
|
||||||
|
friend class LazyASTUnresolvedSet;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ASTUnresolvedSet() {}
|
ASTUnresolvedSet() {}
|
||||||
ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
|
ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
|
||||||
@ -48,7 +57,7 @@ class ASTUnresolvedSet {
|
|||||||
/// Replaces the given declaration with the new one, once.
|
/// Replaces the given declaration with the new one, once.
|
||||||
///
|
///
|
||||||
/// \return true if the set changed
|
/// \return true if the set changed
|
||||||
bool replace(const NamedDecl* Old, NamedDecl *New, AccessSpecifier AS) {
|
bool replace(const NamedDecl *Old, NamedDecl *New, AccessSpecifier AS) {
|
||||||
for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
|
for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
|
||||||
if (I->getDecl() == Old) {
|
if (I->getDecl() == Old) {
|
||||||
I->set(New, AS);
|
I->set(New, AS);
|
||||||
@ -58,10 +67,7 @@ class ASTUnresolvedSet {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(unsigned I) {
|
void erase(unsigned I) { Decls[I] = Decls.pop_back_val(); }
|
||||||
Decls[I] = Decls.back();
|
|
||||||
Decls.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() { Decls.clear(); }
|
void clear() { Decls.clear(); }
|
||||||
|
|
||||||
@ -79,7 +85,29 @@ class ASTUnresolvedSet {
|
|||||||
DeclAccessPair &operator[](unsigned I) { return Decls[I]; }
|
DeclAccessPair &operator[](unsigned I) { return Decls[I]; }
|
||||||
const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; }
|
const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief An UnresolvedSet-like class that might not have been loaded from the
|
||||||
|
/// external AST source yet.
|
||||||
|
class LazyASTUnresolvedSet {
|
||||||
|
mutable ASTUnresolvedSet Impl;
|
||||||
|
|
||||||
|
void getFromExternalSource(ASTContext &C) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ASTUnresolvedSet &get(ASTContext &C) const {
|
||||||
|
if (Impl.Decls.isLazy())
|
||||||
|
getFromExternalSource(C);
|
||||||
|
return Impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }
|
||||||
|
void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
|
||||||
|
assert(Impl.empty() || Impl.Decls.isLazy());
|
||||||
|
Impl.Decls.setLazy(true);
|
||||||
|
Impl.addDecl(C, reinterpret_cast<NamedDecl*>(ID << 2), AS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,16 +55,24 @@ namespace clang {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class ASTVector {
|
class ASTVector {
|
||||||
T *Begin, *End, *Capacity;
|
private:
|
||||||
|
T *Begin, *End;
|
||||||
|
llvm::PointerIntPair<T*, 1, bool> Capacity;
|
||||||
|
|
||||||
void setEnd(T *P) { this->End = P; }
|
void setEnd(T *P) { this->End = P; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Make a tag bit available to users of this class.
|
||||||
|
// FIXME: This is a horrible hack.
|
||||||
|
bool getTag() const { return Capacity.getInt(); }
|
||||||
|
void setTag(bool B) { Capacity.setInt(B); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Default ctor - Initialize to empty.
|
// Default ctor - Initialize to empty.
|
||||||
ASTVector() : Begin(NULL), End(NULL), Capacity(NULL) { }
|
ASTVector() : Begin(0), End(0), Capacity(0, false) {}
|
||||||
|
|
||||||
ASTVector(ASTContext &C, unsigned N)
|
ASTVector(const ASTContext &C, unsigned N)
|
||||||
: Begin(NULL), End(NULL), Capacity(NULL) {
|
: Begin(0), End(0), Capacity(0, false) {
|
||||||
reserve(C, N);
|
reserve(C, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,8 +163,8 @@ class ASTVector {
|
|||||||
return const_pointer(Begin);
|
return const_pointer(Begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const_reference Elt, ASTContext &C) {
|
void push_back(const_reference Elt, const ASTContext &C) {
|
||||||
if (End < Capacity) {
|
if (End < this->capacity_ptr()) {
|
||||||
Retry:
|
Retry:
|
||||||
new (End) T(Elt);
|
new (End) T(Elt);
|
||||||
++End;
|
++End;
|
||||||
@ -166,19 +174,19 @@ class ASTVector {
|
|||||||
goto Retry;
|
goto Retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(ASTContext &C, unsigned N) {
|
void reserve(const ASTContext &C, unsigned N) {
|
||||||
if (unsigned(Capacity-Begin) < N)
|
if (unsigned(this->capacity_ptr()-Begin) < N)
|
||||||
grow(C, N);
|
grow(C, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// capacity - Return the total number of elements in the currently allocated
|
/// capacity - Return the total number of elements in the currently allocated
|
||||||
/// buffer.
|
/// buffer.
|
||||||
size_t capacity() const { return Capacity - Begin; }
|
size_t capacity() const { return this->capacity_ptr() - Begin; }
|
||||||
|
|
||||||
/// append - Add the specified range to the end of the SmallVector.
|
/// append - Add the specified range to the end of the SmallVector.
|
||||||
///
|
///
|
||||||
template<typename in_iter>
|
template<typename in_iter>
|
||||||
void append(ASTContext &C, in_iter in_start, in_iter in_end) {
|
void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
|
||||||
size_type NumInputs = std::distance(in_start, in_end);
|
size_type NumInputs = std::distance(in_start, in_end);
|
||||||
|
|
||||||
if (NumInputs == 0)
|
if (NumInputs == 0)
|
||||||
@ -197,7 +205,7 @@ class ASTVector {
|
|||||||
|
|
||||||
/// append - Add the specified range to the end of the SmallVector.
|
/// append - Add the specified range to the end of the SmallVector.
|
||||||
///
|
///
|
||||||
void append(ASTContext &C, size_type NumInputs, const T &Elt) {
|
void append(const ASTContext &C, size_type NumInputs, const T &Elt) {
|
||||||
// Grow allocated space if needed.
|
// Grow allocated space if needed.
|
||||||
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
|
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
|
||||||
this->grow(C, this->size()+NumInputs);
|
this->grow(C, this->size()+NumInputs);
|
||||||
@ -214,13 +222,13 @@ class ASTVector {
|
|||||||
std::uninitialized_copy(I, E, Dest);
|
std::uninitialized_copy(I, E, Dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator insert(ASTContext &C, iterator I, const T &Elt) {
|
iterator insert(const ASTContext &C, iterator I, const T &Elt) {
|
||||||
if (I == this->end()) { // Important special case for empty vector.
|
if (I == this->end()) { // Important special case for empty vector.
|
||||||
push_back(Elt);
|
push_back(Elt, C);
|
||||||
return this->end()-1;
|
return this->end()-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->EndX < this->CapacityX) {
|
if (this->End < this->capacity_ptr()) {
|
||||||
Retry:
|
Retry:
|
||||||
new (this->end()) T(this->back());
|
new (this->end()) T(this->back());
|
||||||
this->setEnd(this->end()+1);
|
this->setEnd(this->end()+1);
|
||||||
@ -235,7 +243,7 @@ class ASTVector {
|
|||||||
goto Retry;
|
goto Retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator insert(ASTContext &C, iterator I, size_type NumToInsert,
|
iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
|
||||||
const T &Elt) {
|
const T &Elt) {
|
||||||
if (I == this->end()) { // Important special case for empty vector.
|
if (I == this->end()) { // Important special case for empty vector.
|
||||||
append(C, NumToInsert, Elt);
|
append(C, NumToInsert, Elt);
|
||||||
@ -284,7 +292,7 @@ class ASTVector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename ItTy>
|
template<typename ItTy>
|
||||||
iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) {
|
iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) {
|
||||||
if (I == this->end()) { // Important special case for empty vector.
|
if (I == this->end()) { // Important special case for empty vector.
|
||||||
append(C, From, To);
|
append(C, From, To);
|
||||||
return this->end()-1;
|
return this->end()-1;
|
||||||
@ -335,7 +343,7 @@ class ASTVector {
|
|||||||
return I;
|
return I;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(ASTContext &C, unsigned N, const T &NV) {
|
void resize(const ASTContext &C, unsigned N, const T &NV) {
|
||||||
if (N < this->size()) {
|
if (N < this->size()) {
|
||||||
this->destroy_range(this->begin()+N, this->end());
|
this->destroy_range(this->begin()+N, this->end());
|
||||||
this->setEnd(this->begin()+N);
|
this->setEnd(this->begin()+N);
|
||||||
@ -350,7 +358,7 @@ class ASTVector {
|
|||||||
private:
|
private:
|
||||||
/// grow - double the size of the allocated memory, guaranteeing space for at
|
/// grow - double the size of the allocated memory, guaranteeing space for at
|
||||||
/// least one more element or MinSize if specified.
|
/// least one more element or MinSize if specified.
|
||||||
void grow(ASTContext &C, size_type MinSize = 1);
|
void grow(const ASTContext &C, size_type MinSize = 1);
|
||||||
|
|
||||||
void construct_range(T *S, T *E, const T &Elt) {
|
void construct_range(T *S, T *E, const T &Elt) {
|
||||||
for (; S != E; ++S)
|
for (; S != E; ++S)
|
||||||
@ -365,13 +373,16 @@ class ASTVector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
iterator capacity_ptr() { return (iterator)this->Capacity; }
|
const_iterator capacity_ptr() const {
|
||||||
|
return (iterator) Capacity.getPointer();
|
||||||
|
}
|
||||||
|
iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
|
void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
|
||||||
size_t CurCapacity = Capacity-Begin;
|
size_t CurCapacity = this->capacity();
|
||||||
size_t CurSize = size();
|
size_t CurSize = size();
|
||||||
size_t NewCapacity = 2*CurCapacity;
|
size_t NewCapacity = 2*CurCapacity;
|
||||||
if (NewCapacity < MinSize)
|
if (NewCapacity < MinSize)
|
||||||
@ -394,7 +405,7 @@ void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
|
|||||||
// ASTContext never frees any memory.
|
// ASTContext never frees any memory.
|
||||||
Begin = NewElts;
|
Begin = NewElts;
|
||||||
End = NewElts+CurSize;
|
End = NewElts+CurSize;
|
||||||
Capacity = Begin+NewCapacity;
|
Capacity.setPointer(Begin+NewCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end: clang namespace
|
} // end: clang namespace
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define LLVM_CLANG_AST_ATTR_H
|
#define LLVM_CLANG_AST_ATTR_H
|
||||||
|
|
||||||
#include "clang/AST/AttrIterator.h"
|
#include "clang/AST/AttrIterator.h"
|
||||||
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/Basic/AttrKinds.h"
|
#include "clang/Basic/AttrKinds.h"
|
||||||
#include "clang/Basic/LLVM.h"
|
#include "clang/Basic/LLVM.h"
|
||||||
@ -145,7 +146,7 @@ class MSInheritanceAttr : public InheritableAttr {
|
|||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Attr *A) {
|
static bool classof(const Attr *A) {
|
||||||
// Relies on relative order of enum emission with respect to param attrs.
|
// Relies on relative order of enum emission with respect to param attrs.
|
||||||
return (A->getKind() <= attr::LAST_MS_INHERITABLE &&
|
return (A->getKind() <= attr::LAST_MS_INHERITANCE &&
|
||||||
A->getKind() > attr::LAST_INHERITABLE_PARAM);
|
A->getKind() > attr::LAST_INHERITABLE_PARAM);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -287,9 +287,9 @@ class OverridingMethods {
|
|||||||
|
|
||||||
// Iterate over the set of overriding virtual methods in a given
|
// Iterate over the set of overriding virtual methods in a given
|
||||||
// subobject.
|
// subobject.
|
||||||
typedef SmallVector<UniqueVirtualMethod, 4>::iterator
|
typedef SmallVectorImpl<UniqueVirtualMethod>::iterator
|
||||||
overriding_iterator;
|
overriding_iterator;
|
||||||
typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator
|
typedef SmallVectorImpl<UniqueVirtualMethod>::const_iterator
|
||||||
overriding_const_iterator;
|
overriding_const_iterator;
|
||||||
|
|
||||||
// Add a new overriding method for a particular subobject.
|
// Add a new overriding method for a particular subobject.
|
||||||
|
@ -81,7 +81,7 @@ class CanQual {
|
|||||||
operator QualType() const { return Stored; }
|
operator QualType() const { return Stored; }
|
||||||
|
|
||||||
/// \brief Implicit conversion to bool.
|
/// \brief Implicit conversion to bool.
|
||||||
operator bool() const { return !isNull(); }
|
LLVM_EXPLICIT operator bool() const { return !isNull(); }
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return Stored.isNull();
|
return Stored.isNull();
|
||||||
|
@ -19,21 +19,20 @@
|
|||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
/// CharUnits - This is an opaque type for sizes expressed in character units.
|
/// CharUnits - This is an opaque type for sizes expressed in character units.
|
||||||
/// Instances of this type represent a quantity as a multiple of the size
|
/// Instances of this type represent a quantity as a multiple of the size
|
||||||
/// of the standard C type, char, on the target architecture. As an opaque
|
/// of the standard C type, char, on the target architecture. As an opaque
|
||||||
/// type, CharUnits protects you from accidentally combining operations on
|
/// type, CharUnits protects you from accidentally combining operations on
|
||||||
/// quantities in bit units and character units.
|
/// quantities in bit units and character units.
|
||||||
///
|
///
|
||||||
/// It should be noted that characters and bytes are distinct concepts. Bytes
|
/// In both C and C++, an object of type 'char', 'signed char', or 'unsigned
|
||||||
/// refer to addressable units of data storage on the target machine, and
|
/// char' occupies exactly one byte, so 'character unit' and 'byte' refer to
|
||||||
/// characters are members of a set of elements used for the organization,
|
/// the same quantity of storage. However, we use the term 'character unit'
|
||||||
/// control, or representation of data. According to C99, bytes are allowed
|
/// rather than 'byte' to avoid an implication that a character unit is
|
||||||
/// to exceed characters in size, although currently, clang only supports
|
/// exactly 8 bits.
|
||||||
/// architectures where the two are the same size.
|
///
|
||||||
///
|
/// For portability, never assume that a target character is 8 bits wide. Use
|
||||||
/// For portability, never assume that a target character is 8 bits wide. Use
|
|
||||||
/// CharUnit values wherever you calculate sizes, offsets, or alignments
|
/// CharUnit values wherever you calculate sizes, offsets, or alignments
|
||||||
/// in character units.
|
/// in character units.
|
||||||
class CharUnits {
|
class CharUnits {
|
||||||
|
@ -699,7 +699,10 @@ class ParamCommandComment : public BlockCommandComment {
|
|||||||
unsigned ParamIndex;
|
unsigned ParamIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { InvalidParamIndex = ~0U };
|
enum LLVM_ENUM_INT_TYPE(unsigned) {
|
||||||
|
InvalidParamIndex = ~0U,
|
||||||
|
VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U
|
||||||
|
};
|
||||||
|
|
||||||
ParamCommandComment(SourceLocation LocBegin,
|
ParamCommandComment(SourceLocation LocBegin,
|
||||||
SourceLocation LocEnd,
|
SourceLocation LocEnd,
|
||||||
@ -755,14 +758,25 @@ class ParamCommandComment : public BlockCommandComment {
|
|||||||
return ParamIndex != InvalidParamIndex;
|
return ParamIndex != InvalidParamIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isVarArgParam() const LLVM_READONLY {
|
||||||
|
return ParamIndex == VarArgParamIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIsVarArgParam() {
|
||||||
|
ParamIndex = VarArgParamIndex;
|
||||||
|
assert(isParamIndexValid());
|
||||||
|
}
|
||||||
|
|
||||||
unsigned getParamIndex() const LLVM_READONLY {
|
unsigned getParamIndex() const LLVM_READONLY {
|
||||||
assert(isParamIndexValid());
|
assert(isParamIndexValid());
|
||||||
|
assert(!isVarArgParam());
|
||||||
return ParamIndex;
|
return ParamIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setParamIndex(unsigned Index) {
|
void setParamIndex(unsigned Index) {
|
||||||
ParamIndex = Index;
|
ParamIndex = Index;
|
||||||
assert(isParamIndexValid());
|
assert(isParamIndexValid());
|
||||||
|
assert(!isVarArgParam());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1097,10 +1111,6 @@ class FullComment : public Comment {
|
|||||||
return ThisDeclInfo;
|
return ThisDeclInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclInfo *getThisDeclInfo() const LLVM_READONLY {
|
|
||||||
return ThisDeclInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
|
ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -67,6 +67,9 @@ struct CommandInfo {
|
|||||||
/// a template parameter (\\tparam or an alias).
|
/// a template parameter (\\tparam or an alias).
|
||||||
unsigned IsTParamCommand : 1;
|
unsigned IsTParamCommand : 1;
|
||||||
|
|
||||||
|
/// True if this command is \\throws or an alias.
|
||||||
|
unsigned IsThrowsCommand : 1;
|
||||||
|
|
||||||
/// True if this command is \\deprecated or an alias.
|
/// True if this command is \\deprecated or an alias.
|
||||||
unsigned IsDeprecatedCommand : 1;
|
unsigned IsDeprecatedCommand : 1;
|
||||||
|
|
||||||
@ -142,6 +145,8 @@ class CommandTraits {
|
|||||||
llvm_unreachable("the command should be known");
|
llvm_unreachable("the command should be known");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CommandInfo *getTypoCorrectCommandInfo(StringRef Typo) const;
|
||||||
|
|
||||||
const CommandInfo *getCommandInfo(unsigned CommandID) const;
|
const CommandInfo *getCommandInfo(unsigned CommandID) const;
|
||||||
|
|
||||||
const CommandInfo *registerUnknownCommand(StringRef CommandName);
|
const CommandInfo *registerUnknownCommand(StringRef CommandName);
|
||||||
|
@ -15,6 +15,7 @@ class Command<string name> {
|
|||||||
bit IsReturnsCommand = 0;
|
bit IsReturnsCommand = 0;
|
||||||
bit IsParamCommand = 0;
|
bit IsParamCommand = 0;
|
||||||
bit IsTParamCommand = 0;
|
bit IsTParamCommand = 0;
|
||||||
|
bit IsThrowsCommand = 0;
|
||||||
bit IsDeprecatedCommand = 0;
|
bit IsDeprecatedCommand = 0;
|
||||||
bit IsHeaderfileCommand = 0;
|
bit IsHeaderfileCommand = 0;
|
||||||
|
|
||||||
@ -109,6 +110,10 @@ def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
|
|||||||
// HeaderDoc command for template parameter documentation.
|
// HeaderDoc command for template parameter documentation.
|
||||||
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
|
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
|
||||||
|
|
||||||
|
def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; }
|
||||||
|
def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; }
|
||||||
|
def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; }
|
||||||
|
|
||||||
def Deprecated : BlockCommand<"deprecated"> {
|
def Deprecated : BlockCommand<"deprecated"> {
|
||||||
let IsEmptyParagraphAllowed = 1;
|
let IsEmptyParagraphAllowed = 1;
|
||||||
let IsDeprecatedCommand = 1;
|
let IsDeprecatedCommand = 1;
|
||||||
@ -200,11 +205,17 @@ def Mainpage : VerbatimLineCommand<"mainpage">;
|
|||||||
def Subpage : VerbatimLineCommand<"subpage">;
|
def Subpage : VerbatimLineCommand<"subpage">;
|
||||||
def Ref : VerbatimLineCommand<"ref">;
|
def Ref : VerbatimLineCommand<"ref">;
|
||||||
|
|
||||||
|
def Relates : VerbatimLineCommand<"relates">;
|
||||||
|
def Related : VerbatimLineCommand<"related">;
|
||||||
|
def RelatesAlso : VerbatimLineCommand<"relatesalso">;
|
||||||
|
def RelatedAlso : VerbatimLineCommand<"relatedalso">;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// DeclarationVerbatimLineCommand
|
// DeclarationVerbatimLineCommand
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
// Doxygen commands.
|
// Doxygen commands.
|
||||||
|
def Def : DeclarationVerbatimLineCommand<"def">;
|
||||||
def Fn : DeclarationVerbatimLineCommand<"fn">;
|
def Fn : DeclarationVerbatimLineCommand<"fn">;
|
||||||
def Namespace : DeclarationVerbatimLineCommand<"namespace">;
|
def Namespace : DeclarationVerbatimLineCommand<"namespace">;
|
||||||
def Overload : DeclarationVerbatimLineCommand<"overload">;
|
def Overload : DeclarationVerbatimLineCommand<"overload">;
|
||||||
|
@ -16,7 +16,7 @@ namespace clang {
|
|||||||
namespace diag {
|
namespace diag {
|
||||||
enum {
|
enum {
|
||||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||||
#define COMMENTSTART
|
#define COMMENTSTART
|
||||||
#include "clang/Basic/DiagnosticCommentKinds.inc"
|
#include "clang/Basic/DiagnosticCommentKinds.inc"
|
||||||
#undef DIAG
|
#undef DIAG
|
||||||
|
@ -61,10 +61,8 @@ class Parser {
|
|||||||
void consumeToken() {
|
void consumeToken() {
|
||||||
if (MoreLATokens.empty())
|
if (MoreLATokens.empty())
|
||||||
L.lex(Tok);
|
L.lex(Tok);
|
||||||
else {
|
else
|
||||||
Tok = MoreLATokens.back();
|
Tok = MoreLATokens.pop_back_val();
|
||||||
MoreLATokens.pop_back();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void putBack(const Token &OldTok) {
|
void putBack(const Token &OldTok) {
|
||||||
|
@ -58,9 +58,6 @@ class Sema {
|
|||||||
/// AST node for the \\brief command and its aliases.
|
/// AST node for the \\brief command and its aliases.
|
||||||
const BlockCommandComment *BriefCommand;
|
const BlockCommandComment *BriefCommand;
|
||||||
|
|
||||||
/// AST node for the \\returns command and its aliases.
|
|
||||||
const BlockCommandComment *ReturnsCommand;
|
|
||||||
|
|
||||||
/// AST node for the \\headerfile command.
|
/// AST node for the \\headerfile command.
|
||||||
const BlockCommandComment *HeaderfileCommand;
|
const BlockCommandComment *HeaderfileCommand;
|
||||||
|
|
||||||
@ -211,7 +208,11 @@ class Sema {
|
|||||||
|
|
||||||
bool isFunctionDecl();
|
bool isFunctionDecl();
|
||||||
bool isAnyFunctionDecl();
|
bool isAnyFunctionDecl();
|
||||||
|
|
||||||
|
/// \returns \c true if declaration that this comment is attached to declares
|
||||||
|
/// a function pointer.
|
||||||
bool isFunctionPointerVarDecl();
|
bool isFunctionPointerVarDecl();
|
||||||
|
bool isFunctionOrMethodVariadic();
|
||||||
bool isObjCMethodDecl();
|
bool isObjCMethodDecl();
|
||||||
bool isObjCPropertyDecl();
|
bool isObjCPropertyDecl();
|
||||||
bool isTemplateOrSpecialization();
|
bool isTemplateOrSpecialization();
|
||||||
@ -220,6 +221,8 @@ class Sema {
|
|||||||
bool isUnionDecl();
|
bool isUnionDecl();
|
||||||
bool isObjCInterfaceDecl();
|
bool isObjCInterfaceDecl();
|
||||||
bool isObjCProtocolDecl();
|
bool isObjCProtocolDecl();
|
||||||
|
bool isClassTemplateDecl();
|
||||||
|
bool isFunctionTemplateDecl();
|
||||||
|
|
||||||
ArrayRef<const ParmVarDecl *> getParamVars();
|
ArrayRef<const ParmVarDecl *> getParamVars();
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
struct ASTTemplateArgumentListInfo;
|
struct ASTTemplateArgumentListInfo;
|
||||||
@ -43,6 +44,7 @@ class TemplateArgumentList;
|
|||||||
class TemplateParameterList;
|
class TemplateParameterList;
|
||||||
class TypeLoc;
|
class TypeLoc;
|
||||||
class UnresolvedSetImpl;
|
class UnresolvedSetImpl;
|
||||||
|
class VarTemplateDecl;
|
||||||
|
|
||||||
/// \brief A container of type source information.
|
/// \brief A container of type source information.
|
||||||
///
|
///
|
||||||
@ -109,7 +111,6 @@ class NamedDecl : public Decl {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
NamedDecl *getUnderlyingDeclImpl();
|
NamedDecl *getUnderlyingDeclImpl();
|
||||||
void verifyLinkage() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
|
NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
|
||||||
@ -142,7 +143,7 @@ class NamedDecl : public Decl {
|
|||||||
// FIXME: Deprecated, move clients to getName().
|
// FIXME: Deprecated, move clients to getName().
|
||||||
std::string getNameAsString() const { return Name.getAsString(); }
|
std::string getNameAsString() const { return Name.getAsString(); }
|
||||||
|
|
||||||
void printName(raw_ostream &os) const { return Name.printName(os); }
|
void printName(raw_ostream &os) const { os << Name; }
|
||||||
|
|
||||||
/// getDeclName - Get the actual, stored name of the declaration,
|
/// getDeclName - Get the actual, stored name of the declaration,
|
||||||
/// which may be a special name.
|
/// which may be a special name.
|
||||||
@ -189,10 +190,13 @@ class NamedDecl : public Decl {
|
|||||||
|
|
||||||
using Decl::isModulePrivate;
|
using Decl::isModulePrivate;
|
||||||
using Decl::setModulePrivate;
|
using Decl::setModulePrivate;
|
||||||
|
|
||||||
/// \brief Determine whether this declaration is hidden from name lookup.
|
/// \brief Determine whether this declaration is hidden from name lookup.
|
||||||
bool isHidden() const { return Hidden; }
|
bool isHidden() const { return Hidden; }
|
||||||
|
|
||||||
|
/// \brief Set whether this declaration is hidden from name lookup.
|
||||||
|
void setHidden(bool Hide) { Hidden = Hide; }
|
||||||
|
|
||||||
/// \brief Determine whether this declaration is a C++ class member.
|
/// \brief Determine whether this declaration is a C++ class member.
|
||||||
bool isCXXClassMember() const {
|
bool isCXXClassMember() const {
|
||||||
const DeclContext *DC = getDeclContext();
|
const DeclContext *DC = getDeclContext();
|
||||||
@ -212,11 +216,24 @@ class NamedDecl : public Decl {
|
|||||||
bool isCXXInstanceMember() const;
|
bool isCXXInstanceMember() const;
|
||||||
|
|
||||||
/// \brief Determine what kind of linkage this entity has.
|
/// \brief Determine what kind of linkage this entity has.
|
||||||
Linkage getLinkage() const;
|
/// This is not the linkage as defined by the standard or the codegen notion
|
||||||
|
/// of linkage. It is just an implementation detail that is used to compute
|
||||||
|
/// those.
|
||||||
|
Linkage getLinkageInternal() const;
|
||||||
|
|
||||||
|
/// \brief Get the linkage from a semantic point of view. Entities in
|
||||||
|
/// anonymous namespaces are external (in c++98).
|
||||||
|
Linkage getFormalLinkage() const {
|
||||||
|
return clang::getFormalLinkage(getLinkageInternal());
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief True if this decl has external linkage.
|
/// \brief True if this decl has external linkage.
|
||||||
bool hasExternalLinkage() const {
|
bool hasExternalFormalLinkage() const {
|
||||||
return getLinkage() == ExternalLinkage;
|
return isExternalFormalLinkage(getLinkageInternal());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isExternallyVisible() const {
|
||||||
|
return clang::isExternallyVisible(getLinkageInternal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determines the visibility of this entity.
|
/// \brief Determines the visibility of this entity.
|
||||||
@ -256,6 +273,13 @@ class NamedDecl : public Decl {
|
|||||||
return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
|
return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NamedDecl *getMostRecentDecl() {
|
||||||
|
return cast<NamedDecl>(static_cast<Decl *>(this)->getMostRecentDecl());
|
||||||
|
}
|
||||||
|
const NamedDecl *getMostRecentDecl() const {
|
||||||
|
return const_cast<NamedDecl*>(this)->getMostRecentDecl();
|
||||||
|
}
|
||||||
|
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
|
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
|
||||||
};
|
};
|
||||||
@ -351,6 +375,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
/// \brief Returns true if this is an anonymous namespace declaration.
|
/// \brief Returns true if this is an anonymous namespace declaration.
|
||||||
///
|
///
|
||||||
@ -377,7 +402,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
|||||||
|
|
||||||
/// \brief Get the original (first) namespace declaration.
|
/// \brief Get the original (first) namespace declaration.
|
||||||
NamespaceDecl *getOriginalNamespace() {
|
NamespaceDecl *getOriginalNamespace() {
|
||||||
if (isFirstDeclaration())
|
if (isFirstDecl())
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
return AnonOrFirstNamespaceAndInline.getPointer();
|
return AnonOrFirstNamespaceAndInline.getPointer();
|
||||||
@ -385,7 +410,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
|||||||
|
|
||||||
/// \brief Get the original (first) namespace declaration.
|
/// \brief Get the original (first) namespace declaration.
|
||||||
const NamespaceDecl *getOriginalNamespace() const {
|
const NamespaceDecl *getOriginalNamespace() const {
|
||||||
if (isFirstDeclaration())
|
if (isFirstDecl())
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
return AnonOrFirstNamespaceAndInline.getPointer();
|
return AnonOrFirstNamespaceAndInline.getPointer();
|
||||||
@ -394,9 +419,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
|||||||
/// \brief Return true if this declaration is an original (first) declaration
|
/// \brief Return true if this declaration is an original (first) declaration
|
||||||
/// of the namespace. This is false for non-original (subsequent) namespace
|
/// of the namespace. This is false for non-original (subsequent) namespace
|
||||||
/// declarations and anonymous namespaces.
|
/// declarations and anonymous namespaces.
|
||||||
bool isOriginalNamespace() const {
|
bool isOriginalNamespace() const { return isFirstDecl(); }
|
||||||
return isFirstDeclaration();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Retrieve the anonymous namespace nested inside this namespace,
|
/// \brief Retrieve the anonymous namespace nested inside this namespace,
|
||||||
/// if any.
|
/// if any.
|
||||||
@ -689,11 +712,21 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
|
|
||||||
/// \brief Whether this variable is (C++0x) constexpr.
|
/// \brief Whether this variable is (C++0x) constexpr.
|
||||||
unsigned IsConstexpr : 1;
|
unsigned IsConstexpr : 1;
|
||||||
|
|
||||||
|
/// \brief Whether this variable is the implicit variable for a lambda
|
||||||
|
/// init-capture.
|
||||||
|
unsigned IsInitCapture : 1;
|
||||||
|
|
||||||
|
/// \brief Whether this local extern variable's previous declaration was
|
||||||
|
/// declared in the same block scope. This controls whether we should merge
|
||||||
|
/// the type of this declaration with its previous declaration.
|
||||||
|
unsigned PreviousDeclInSameBlockScope : 1;
|
||||||
};
|
};
|
||||||
enum { NumVarDeclBits = 12 };
|
enum { NumVarDeclBits = 14 };
|
||||||
|
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
friend class StmtIteratorBase;
|
friend class StmtIteratorBase;
|
||||||
|
friend class ASTNodeImporter;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum { NumParameterIndexBits = 8 };
|
enum { NumParameterIndexBits = 8 };
|
||||||
@ -732,15 +765,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
|
||||||
QualType T, TypeSourceInfo *TInfo, StorageClass SC)
|
TypeSourceInfo *TInfo, StorageClass SC);
|
||||||
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
|
|
||||||
assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
|
|
||||||
assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
|
|
||||||
AllBits = 0;
|
|
||||||
VarDeclBits.SClass = SC;
|
|
||||||
// Everything else is implicitly initialized to false.
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef Redeclarable<VarDecl> redeclarable_base;
|
typedef Redeclarable<VarDecl> redeclarable_base;
|
||||||
virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
|
virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
|
||||||
@ -757,6 +783,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
static VarDecl *Create(ASTContext &C, DeclContext *DC,
|
static VarDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||||
@ -797,7 +824,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
/// is a non-static local variable.
|
/// is a non-static local variable.
|
||||||
bool hasLocalStorage() const {
|
bool hasLocalStorage() const {
|
||||||
if (getStorageClass() == SC_None)
|
if (getStorageClass() == SC_None)
|
||||||
return !isFileVarDecl();
|
// Second check is for C++11 [dcl.stc]p4.
|
||||||
|
return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
|
||||||
|
|
||||||
// Return true for: Auto, Register.
|
// Return true for: Auto, Register.
|
||||||
// Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.
|
// Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.
|
||||||
@ -808,7 +836,10 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
/// isStaticLocal - Returns true if a variable with function scope is a
|
/// isStaticLocal - Returns true if a variable with function scope is a
|
||||||
/// static local variable.
|
/// static local variable.
|
||||||
bool isStaticLocal() const {
|
bool isStaticLocal() const {
|
||||||
return getStorageClass() == SC_Static && !isFileVarDecl();
|
return (getStorageClass() == SC_Static ||
|
||||||
|
// C++11 [dcl.stc]p4
|
||||||
|
(getStorageClass() == SC_None && getTSCSpec() == TSCS_thread_local))
|
||||||
|
&& !isFileVarDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns true if a variable has extern or __private_extern__
|
/// \brief Returns true if a variable has extern or __private_extern__
|
||||||
@ -818,12 +849,19 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
getStorageClass() == SC_PrivateExtern;
|
getStorageClass() == SC_PrivateExtern;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// hasGlobalStorage - Returns true for all variables that do not
|
/// \brief Returns true for all variables that do not have local storage.
|
||||||
/// have local storage. This includs all global variables as well
|
///
|
||||||
/// as static variables declared within a function.
|
/// This includes all global variables as well as static variables declared
|
||||||
|
/// within a function.
|
||||||
bool hasGlobalStorage() const { return !hasLocalStorage(); }
|
bool hasGlobalStorage() const { return !hasLocalStorage(); }
|
||||||
|
|
||||||
/// Compute the language linkage.
|
/// \brief Get the storage duration of this variable, per C++ [basic.stc].
|
||||||
|
StorageDuration getStorageDuration() const {
|
||||||
|
return hasLocalStorage() ? SD_Automatic :
|
||||||
|
getTSCSpec() ? SD_Thread : SD_Static;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Compute the language linkage.
|
||||||
LanguageLinkage getLanguageLinkage() const;
|
LanguageLinkage getLanguageLinkage() const;
|
||||||
|
|
||||||
/// \brief Determines whether this variable is a variable with
|
/// \brief Determines whether this variable is a variable with
|
||||||
@ -847,7 +885,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
bool isLocalVarDecl() const {
|
bool isLocalVarDecl() const {
|
||||||
if (getKind() != Decl::Var)
|
if (getKind() != Decl::Var)
|
||||||
return false;
|
return false;
|
||||||
if (const DeclContext *DC = getDeclContext())
|
if (const DeclContext *DC = getLexicalDeclContext())
|
||||||
return DC->getRedeclContext()->isFunctionOrMethod();
|
return DC->getRedeclContext()->isFunctionOrMethod();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -857,7 +895,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
bool isFunctionOrMethodVarDecl() const {
|
bool isFunctionOrMethodVarDecl() const {
|
||||||
if (getKind() != Decl::Var)
|
if (getKind() != Decl::Var)
|
||||||
return false;
|
return false;
|
||||||
const DeclContext *DC = getDeclContext()->getRedeclContext();
|
const DeclContext *DC = getLexicalDeclContext()->getRedeclContext();
|
||||||
return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;
|
return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,10 +946,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
return const_cast<VarDecl*>(this)->getActingDefinition();
|
return const_cast<VarDecl*>(this)->getActingDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine whether this is a tentative definition of a
|
|
||||||
/// variable in C.
|
|
||||||
bool isTentativeDefinitionNow() const;
|
|
||||||
|
|
||||||
/// \brief Get the real (not just tentative) definition for this declaration.
|
/// \brief Get the real (not just tentative) definition for this declaration.
|
||||||
VarDecl *getDefinition(ASTContext &);
|
VarDecl *getDefinition(ASTContext &);
|
||||||
const VarDecl *getDefinition(ASTContext &C) const {
|
const VarDecl *getDefinition(ASTContext &C) const {
|
||||||
@ -933,10 +967,11 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
|
|
||||||
/// isFileVarDecl - Returns true for file scoped variable declaration.
|
/// isFileVarDecl - Returns true for file scoped variable declaration.
|
||||||
bool isFileVarDecl() const {
|
bool isFileVarDecl() const {
|
||||||
if (getKind() != Decl::Var)
|
Kind K = getKind();
|
||||||
|
if (K == ParmVar || K == ImplicitParam)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (getDeclContext()->getRedeclContext()->isFileContext())
|
if (getLexicalDeclContext()->getRedeclContext()->isFileContext())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (isStaticDataMember())
|
if (isStaticDataMember())
|
||||||
@ -1000,20 +1035,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
|
|
||||||
void setInit(Expr *I);
|
void setInit(Expr *I);
|
||||||
|
|
||||||
/// \brief Determine whether this variable is a reference that
|
|
||||||
/// extends the lifetime of its temporary initializer.
|
|
||||||
///
|
|
||||||
/// A reference extends the lifetime of its temporary initializer if
|
|
||||||
/// it's initializer is an rvalue that would normally go out of scope
|
|
||||||
/// at the end of the initializer (a full expression). In such cases,
|
|
||||||
/// the reference itself takes ownership of the temporary, which will
|
|
||||||
/// be destroyed when the reference goes out of scope. For example:
|
|
||||||
///
|
|
||||||
/// \code
|
|
||||||
/// const int &r = 1.0; // creates a temporary of type 'int'
|
|
||||||
/// \endcode
|
|
||||||
bool extendsLifetimeOfTemporary() const;
|
|
||||||
|
|
||||||
/// \brief Determine whether this variable's value can be used in a
|
/// \brief Determine whether this variable's value can be used in a
|
||||||
/// constant expression, according to the relevant language standard.
|
/// constant expression, according to the relevant language standard.
|
||||||
/// This only checks properties of the declaration, and does not check
|
/// This only checks properties of the declaration, and does not check
|
||||||
@ -1123,15 +1144,34 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
|
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
|
||||||
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
|
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
|
||||||
|
|
||||||
|
/// Whether this variable is the implicit variable for a lambda init-capture.
|
||||||
|
bool isInitCapture() const { return VarDeclBits.IsInitCapture; }
|
||||||
|
void setInitCapture(bool IC) { VarDeclBits.IsInitCapture = IC; }
|
||||||
|
|
||||||
|
/// Whether this local extern variable declaration's previous declaration
|
||||||
|
/// was declared in the same block scope. Only correct in C++.
|
||||||
|
bool isPreviousDeclInSameBlockScope() const {
|
||||||
|
return VarDeclBits.PreviousDeclInSameBlockScope;
|
||||||
|
}
|
||||||
|
void setPreviousDeclInSameBlockScope(bool Same) {
|
||||||
|
VarDeclBits.PreviousDeclInSameBlockScope = Same;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief If this variable is an instantiated static data member of a
|
/// \brief If this variable is an instantiated static data member of a
|
||||||
/// class template specialization, returns the templated static data member
|
/// class template specialization, returns the templated static data member
|
||||||
/// from which it was instantiated.
|
/// from which it was instantiated.
|
||||||
VarDecl *getInstantiatedFromStaticDataMember() const;
|
VarDecl *getInstantiatedFromStaticDataMember() const;
|
||||||
|
|
||||||
/// \brief If this variable is a static data member, determine what kind of
|
/// \brief If this variable is an instantiation of a variable template or a
|
||||||
|
/// static data member of a class template, determine what kind of
|
||||||
/// template specialization or instantiation this is.
|
/// template specialization or instantiation this is.
|
||||||
TemplateSpecializationKind getTemplateSpecializationKind() const;
|
TemplateSpecializationKind getTemplateSpecializationKind() const;
|
||||||
|
|
||||||
|
/// \brief If this variable is an instantiation of a variable template or a
|
||||||
|
/// static data member of a class template, determine its point of
|
||||||
|
/// instantiation.
|
||||||
|
SourceLocation getPointOfInstantiation() const;
|
||||||
|
|
||||||
/// \brief If this variable is an instantiation of a static data member of a
|
/// \brief If this variable is an instantiation of a static data member of a
|
||||||
/// class template specialization, retrieves the member specialization
|
/// class template specialization, retrieves the member specialization
|
||||||
/// information.
|
/// information.
|
||||||
@ -1142,6 +1182,26 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
|||||||
void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
||||||
SourceLocation PointOfInstantiation = SourceLocation());
|
SourceLocation PointOfInstantiation = SourceLocation());
|
||||||
|
|
||||||
|
/// \brief Specify that this variable is an instantiation of the
|
||||||
|
/// static data member VD.
|
||||||
|
void setInstantiationOfStaticDataMember(VarDecl *VD,
|
||||||
|
TemplateSpecializationKind TSK);
|
||||||
|
|
||||||
|
/// \brief Retrieves the variable template that is described by this
|
||||||
|
/// variable declaration.
|
||||||
|
///
|
||||||
|
/// Every variable template is represented as a VarTemplateDecl and a
|
||||||
|
/// VarDecl. The former contains template properties (such as
|
||||||
|
/// the template parameter lists) while the latter contains the
|
||||||
|
/// actual description of the template's
|
||||||
|
/// contents. VarTemplateDecl::getTemplatedDecl() retrieves the
|
||||||
|
/// VarDecl that from a VarTemplateDecl, while
|
||||||
|
/// getDescribedVarTemplate() retrieves the VarTemplateDecl from
|
||||||
|
/// a VarDecl.
|
||||||
|
VarTemplateDecl *getDescribedVarTemplate() const;
|
||||||
|
|
||||||
|
void setDescribedVarTemplate(VarTemplateDecl *Template);
|
||||||
|
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
|
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
|
||||||
@ -1314,11 +1374,7 @@ class ParmVarDecl : public VarDecl {
|
|||||||
ParmVarDeclBits.HasInheritedDefaultArg = I;
|
ParmVarDeclBits.HasInheritedDefaultArg = I;
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType getOriginalType() const {
|
QualType getOriginalType() const;
|
||||||
if (getTypeSourceInfo())
|
|
||||||
return getTypeSourceInfo()->getType();
|
|
||||||
return getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Determine whether this parameter is actually a function
|
/// \brief Determine whether this parameter is actually a function
|
||||||
/// parameter pack.
|
/// parameter pack.
|
||||||
@ -1517,6 +1573,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
|
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation StartLoc, SourceLocation NLoc,
|
SourceLocation StartLoc, SourceLocation NLoc,
|
||||||
@ -1701,6 +1758,10 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
|||||||
/// entry point into an executable program.
|
/// entry point into an executable program.
|
||||||
bool isMain() const;
|
bool isMain() const;
|
||||||
|
|
||||||
|
/// \brief Determines whether this function is a MSVCRT user defined entry
|
||||||
|
/// point.
|
||||||
|
bool isMSVCRTEntryPoint() const;
|
||||||
|
|
||||||
/// \brief Determines whether this operator new or delete is one
|
/// \brief Determines whether this operator new or delete is one
|
||||||
/// of the reserved global placement operators:
|
/// of the reserved global placement operators:
|
||||||
/// void *operator new(size_t, void *);
|
/// void *operator new(size_t, void *);
|
||||||
@ -1716,6 +1777,28 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
|||||||
/// This function must be an allocation or deallocation function.
|
/// This function must be an allocation or deallocation function.
|
||||||
bool isReservedGlobalPlacementOperator() const;
|
bool isReservedGlobalPlacementOperator() const;
|
||||||
|
|
||||||
|
/// \brief Determines whether this function is one of the replaceable
|
||||||
|
/// global allocation functions:
|
||||||
|
/// void *operator new(size_t);
|
||||||
|
/// void *operator new(size_t, const std::nothrow_t &) noexcept;
|
||||||
|
/// void *operator new[](size_t);
|
||||||
|
/// void *operator new[](size_t, const std::nothrow_t &) noexcept;
|
||||||
|
/// void operator delete(void *) noexcept;
|
||||||
|
/// void operator delete(void *, std::size_t) noexcept; [C++1y]
|
||||||
|
/// void operator delete(void *, const std::nothrow_t &) noexcept;
|
||||||
|
/// void operator delete[](void *) noexcept;
|
||||||
|
/// void operator delete[](void *, std::size_t) noexcept; [C++1y]
|
||||||
|
/// void operator delete[](void *, const std::nothrow_t &) noexcept;
|
||||||
|
/// These functions have special behavior under C++1y [expr.new]:
|
||||||
|
/// An implementation is allowed to omit a call to a replaceable global
|
||||||
|
/// allocation function. [...]
|
||||||
|
bool isReplaceableGlobalAllocationFunction() const;
|
||||||
|
|
||||||
|
/// \brief Determine whether this function is a sized global deallocation
|
||||||
|
/// function in C++1y. If so, find and return the corresponding unsized
|
||||||
|
/// deallocation function.
|
||||||
|
FunctionDecl *getCorrespondingUnsizedGlobalDeallocationFunction() const;
|
||||||
|
|
||||||
/// Compute the language linkage.
|
/// Compute the language linkage.
|
||||||
LanguageLinkage getLanguageLinkage() const;
|
LanguageLinkage getLanguageLinkage() const;
|
||||||
|
|
||||||
@ -2039,7 +2122,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
|||||||
|
|
||||||
/// FieldDecl - An instance of this class is created by Sema::ActOnField to
|
/// FieldDecl - An instance of this class is created by Sema::ActOnField to
|
||||||
/// represent a member of a struct/union/class.
|
/// represent a member of a struct/union/class.
|
||||||
class FieldDecl : public DeclaratorDecl {
|
class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
|
||||||
// FIXME: This can be packed into the bitfields in Decl.
|
// FIXME: This can be packed into the bitfields in Decl.
|
||||||
bool Mutable : 1;
|
bool Mutable : 1;
|
||||||
mutable unsigned CachedFieldIndex : 31;
|
mutable unsigned CachedFieldIndex : 31;
|
||||||
@ -2153,6 +2236,10 @@ class FieldDecl : public DeclaratorDecl {
|
|||||||
|
|
||||||
SourceRange getSourceRange() const LLVM_READONLY;
|
SourceRange getSourceRange() const LLVM_READONLY;
|
||||||
|
|
||||||
|
/// Retrieves the canonical declaration of this field.
|
||||||
|
FieldDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||||
|
const FieldDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||||
|
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
|
static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
|
||||||
@ -2165,7 +2252,7 @@ class FieldDecl : public DeclaratorDecl {
|
|||||||
/// that is defined. For example, in "enum X {a,b}", each of a/b are
|
/// that is defined. For example, in "enum X {a,b}", each of a/b are
|
||||||
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
|
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
|
||||||
/// TagType for the X EnumDecl.
|
/// TagType for the X EnumDecl.
|
||||||
class EnumConstantDecl : public ValueDecl {
|
class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> {
|
||||||
Stmt *Init; // an integer constant expression
|
Stmt *Init; // an integer constant expression
|
||||||
llvm::APSInt Val; // The value.
|
llvm::APSInt Val; // The value.
|
||||||
protected:
|
protected:
|
||||||
@ -2191,6 +2278,10 @@ class EnumConstantDecl : public ValueDecl {
|
|||||||
|
|
||||||
SourceRange getSourceRange() const LLVM_READONLY;
|
SourceRange getSourceRange() const LLVM_READONLY;
|
||||||
|
|
||||||
|
/// Retrieves the canonical declaration of this enumerator.
|
||||||
|
EnumConstantDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||||
|
const EnumConstantDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||||
|
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
static bool classofKind(Kind K) { return K == EnumConstant; }
|
static bool classofKind(Kind K) { return K == EnumConstant; }
|
||||||
@ -2289,14 +2380,14 @@ class TypeDecl : public NamedDecl {
|
|||||||
/// Base class for declarations which introduce a typedef-name.
|
/// Base class for declarations which introduce a typedef-name.
|
||||||
class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
/// UnderlyingType - This is the type the typedef is set to.
|
typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
|
||||||
TypeSourceInfo *TInfo;
|
llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||||
TypeSourceInfo *TInfo)
|
TypeSourceInfo *TInfo)
|
||||||
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), TInfo(TInfo) {}
|
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), MaybeModedTInfo(TInfo) {}
|
||||||
|
|
||||||
typedef Redeclarable<TypedefNameDecl> redeclarable_base;
|
typedef Redeclarable<TypedefNameDecl> redeclarable_base;
|
||||||
virtual TypedefNameDecl *getNextRedeclaration() {
|
virtual TypedefNameDecl *getNextRedeclaration() {
|
||||||
@ -2315,25 +2406,30 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
|
bool isModed() const { return MaybeModedTInfo.is<ModedTInfo*>(); }
|
||||||
|
|
||||||
TypeSourceInfo *getTypeSourceInfo() const {
|
TypeSourceInfo *getTypeSourceInfo() const {
|
||||||
return TInfo;
|
return isModed()
|
||||||
|
? MaybeModedTInfo.get<ModedTInfo*>()->first
|
||||||
|
: MaybeModedTInfo.get<TypeSourceInfo*>();
|
||||||
|
}
|
||||||
|
QualType getUnderlyingType() const {
|
||||||
|
return isModed()
|
||||||
|
? MaybeModedTInfo.get<ModedTInfo*>()->second
|
||||||
|
: MaybeModedTInfo.get<TypeSourceInfo*>()->getType();
|
||||||
|
}
|
||||||
|
void setTypeSourceInfo(TypeSourceInfo *newType) {
|
||||||
|
MaybeModedTInfo = newType;
|
||||||
|
}
|
||||||
|
void setModedTypeSourceInfo(TypeSourceInfo *unmodedTSI, QualType modedTy) {
|
||||||
|
MaybeModedTInfo = new (getASTContext()) ModedTInfo(unmodedTSI, modedTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the canonical declaration of this typedef-name.
|
/// Retrieves the canonical declaration of this typedef-name.
|
||||||
TypedefNameDecl *getCanonicalDecl() {
|
TypedefNameDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||||
return getFirstDeclaration();
|
const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||||
}
|
|
||||||
const TypedefNameDecl *getCanonicalDecl() const {
|
|
||||||
return getFirstDeclaration();
|
|
||||||
}
|
|
||||||
|
|
||||||
QualType getUnderlyingType() const {
|
|
||||||
return TInfo->getType();
|
|
||||||
}
|
|
||||||
void setTypeSourceInfo(TypeSourceInfo *newType) {
|
|
||||||
TInfo = newType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
@ -2436,6 +2532,9 @@ class TagDecl
|
|||||||
/// This option is only enabled when modules are enabled.
|
/// This option is only enabled when modules are enabled.
|
||||||
bool MayHaveOutOfDateDef : 1;
|
bool MayHaveOutOfDateDef : 1;
|
||||||
|
|
||||||
|
/// Has the full definition of this type been required by a use somewhere in
|
||||||
|
/// the TU.
|
||||||
|
bool IsCompleteDefinitionRequired : 1;
|
||||||
private:
|
private:
|
||||||
SourceLocation RBraceLoc;
|
SourceLocation RBraceLoc;
|
||||||
|
|
||||||
@ -2443,33 +2542,33 @@ class TagDecl
|
|||||||
// to be used for the (uncommon) case of out-of-line declarations.
|
// to be used for the (uncommon) case of out-of-line declarations.
|
||||||
typedef QualifierInfo ExtInfo;
|
typedef QualifierInfo ExtInfo;
|
||||||
|
|
||||||
/// TypedefNameDeclOrQualifier - If the (out-of-line) tag declaration name
|
/// \brief If the (out-of-line) tag declaration name
|
||||||
/// is qualified, it points to the qualifier info (nns and range);
|
/// is qualified, it points to the qualifier info (nns and range);
|
||||||
/// otherwise, if the tag declaration is anonymous and it is part of
|
/// otherwise, if the tag declaration is anonymous and it is part of
|
||||||
/// a typedef or alias, it points to the TypedefNameDecl (used for mangling);
|
/// a typedef or alias, it points to the TypedefNameDecl (used for mangling);
|
||||||
|
/// otherwise, if the tag declaration is anonymous and it is used as a
|
||||||
|
/// declaration specifier for variables, it points to the first VarDecl (used
|
||||||
|
/// for mangling);
|
||||||
/// otherwise, it is a null (TypedefNameDecl) pointer.
|
/// otherwise, it is a null (TypedefNameDecl) pointer.
|
||||||
llvm::PointerUnion<TypedefNameDecl*, ExtInfo*> TypedefNameDeclOrQualifier;
|
llvm::PointerUnion<NamedDecl *, ExtInfo *> NamedDeclOrQualifier;
|
||||||
|
|
||||||
bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo*>(); }
|
bool hasExtInfo() const { return NamedDeclOrQualifier.is<ExtInfo *>(); }
|
||||||
ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo*>(); }
|
ExtInfo *getExtInfo() { return NamedDeclOrQualifier.get<ExtInfo *>(); }
|
||||||
const ExtInfo *getExtInfo() const {
|
const ExtInfo *getExtInfo() const {
|
||||||
return TypedefNameDeclOrQualifier.get<ExtInfo*>();
|
return NamedDeclOrQualifier.get<ExtInfo *>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TagDecl(Kind DK, TagKind TK, DeclContext *DC,
|
TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
|
||||||
SourceLocation L, IdentifierInfo *Id,
|
IdentifierInfo *Id, TagDecl *PrevDecl, SourceLocation StartL)
|
||||||
TagDecl *PrevDecl, SourceLocation StartL)
|
: TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), TagDeclKind(TK),
|
||||||
: TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK),
|
IsCompleteDefinition(false), IsBeingDefined(false),
|
||||||
TypedefNameDeclOrQualifier((TypedefNameDecl*) 0) {
|
IsEmbeddedInDeclarator(false), IsFreeStanding(false),
|
||||||
|
IsCompleteDefinitionRequired(false),
|
||||||
|
NamedDeclOrQualifier((NamedDecl *)0) {
|
||||||
assert((DK != Enum || TK == TTK_Enum) &&
|
assert((DK != Enum || TK == TTK_Enum) &&
|
||||||
"EnumDecl not matched with TTK_Enum");
|
"EnumDecl not matched with TTK_Enum");
|
||||||
TagDeclKind = TK;
|
setPreviousDecl(PrevDecl);
|
||||||
IsCompleteDefinition = false;
|
|
||||||
IsBeingDefined = false;
|
|
||||||
IsEmbeddedInDeclarator = false;
|
|
||||||
IsFreeStanding = false;
|
|
||||||
setPreviousDeclaration(PrevDecl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Redeclarable<TagDecl> redeclarable_base;
|
typedef Redeclarable<TagDecl> redeclarable_base;
|
||||||
@ -2492,6 +2591,7 @@ class TagDecl
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
SourceLocation getRBraceLoc() const { return RBraceLoc; }
|
SourceLocation getRBraceLoc() const { return RBraceLoc; }
|
||||||
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
|
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
|
||||||
@ -2522,6 +2622,12 @@ class TagDecl
|
|||||||
return IsCompleteDefinition;
|
return IsCompleteDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Return true if this complete decl is
|
||||||
|
/// required to be complete for some existing use.
|
||||||
|
bool isCompleteDefinitionRequired() const {
|
||||||
|
return IsCompleteDefinitionRequired;
|
||||||
|
}
|
||||||
|
|
||||||
/// isBeingDefined - Return true if this decl is currently being defined.
|
/// isBeingDefined - Return true if this decl is currently being defined.
|
||||||
bool isBeingDefined() const {
|
bool isBeingDefined() const {
|
||||||
return IsBeingDefined;
|
return IsBeingDefined;
|
||||||
@ -2563,6 +2669,10 @@ class TagDecl
|
|||||||
|
|
||||||
void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
|
void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
|
||||||
|
|
||||||
|
void setCompleteDefinitionRequired(bool V = true) {
|
||||||
|
IsCompleteDefinitionRequired = V;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Return StringRef;
|
// FIXME: Return StringRef;
|
||||||
const char *getKindName() const {
|
const char *getKindName() const {
|
||||||
return TypeWithKeyword::getTagTypeKindName(getTagKind());
|
return TypeWithKeyword::getTagTypeKindName(getTagKind());
|
||||||
@ -2599,10 +2709,21 @@ class TagDecl
|
|||||||
return (getDeclName() || getTypedefNameForAnonDecl());
|
return (getDeclName() || getTypedefNameForAnonDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedefNameDecl *getTypedefNameForAnonDecl() const {
|
bool hasDeclaratorForAnonDecl() const {
|
||||||
return hasExtInfo() ? 0 :
|
return dyn_cast_or_null<DeclaratorDecl>(
|
||||||
TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
|
NamedDeclOrQualifier.get<NamedDecl *>());
|
||||||
}
|
}
|
||||||
|
DeclaratorDecl *getDeclaratorForAnonDecl() const {
|
||||||
|
return hasExtInfo() ? 0 : dyn_cast_or_null<DeclaratorDecl>(
|
||||||
|
NamedDeclOrQualifier.get<NamedDecl *>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedefNameDecl *getTypedefNameForAnonDecl() const {
|
||||||
|
return hasExtInfo() ? 0 : dyn_cast_or_null<TypedefNameDecl>(
|
||||||
|
NamedDeclOrQualifier.get<NamedDecl *>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDeclaratorForAnonDecl(DeclaratorDecl *DD) { NamedDeclOrQualifier = DD; }
|
||||||
|
|
||||||
void setTypedefNameForAnonDecl(TypedefNameDecl *TDD);
|
void setTypedefNameForAnonDecl(TypedefNameDecl *TDD);
|
||||||
|
|
||||||
@ -2702,21 +2823,22 @@ class EnumDecl : public TagDecl {
|
|||||||
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
|
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
|
||||||
}
|
}
|
||||||
const EnumDecl *getCanonicalDecl() const {
|
const EnumDecl *getCanonicalDecl() const {
|
||||||
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
|
return const_cast<EnumDecl*>(this)->getCanonicalDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
const EnumDecl *getPreviousDecl() const {
|
|
||||||
return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl());
|
|
||||||
}
|
|
||||||
EnumDecl *getPreviousDecl() {
|
EnumDecl *getPreviousDecl() {
|
||||||
return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl());
|
return cast_or_null<EnumDecl>(
|
||||||
|
static_cast<TagDecl *>(this)->getPreviousDecl());
|
||||||
|
}
|
||||||
|
const EnumDecl *getPreviousDecl() const {
|
||||||
|
return const_cast<EnumDecl*>(this)->getPreviousDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
const EnumDecl *getMostRecentDecl() const {
|
|
||||||
return cast<EnumDecl>(TagDecl::getMostRecentDecl());
|
|
||||||
}
|
|
||||||
EnumDecl *getMostRecentDecl() {
|
EnumDecl *getMostRecentDecl() {
|
||||||
return cast<EnumDecl>(TagDecl::getMostRecentDecl());
|
return cast<EnumDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl());
|
||||||
|
}
|
||||||
|
const EnumDecl *getMostRecentDecl() const {
|
||||||
|
return const_cast<EnumDecl*>(this)->getMostRecentDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
EnumDecl *getDefinition() const {
|
EnumDecl *getDefinition() const {
|
||||||
@ -2912,18 +3034,19 @@ class RecordDecl : public TagDecl {
|
|||||||
IdentifierInfo *Id, RecordDecl* PrevDecl = 0);
|
IdentifierInfo *Id, RecordDecl* PrevDecl = 0);
|
||||||
static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
||||||
|
|
||||||
const RecordDecl *getPreviousDecl() const {
|
|
||||||
return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl());
|
|
||||||
}
|
|
||||||
RecordDecl *getPreviousDecl() {
|
RecordDecl *getPreviousDecl() {
|
||||||
return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl());
|
return cast_or_null<RecordDecl>(
|
||||||
|
static_cast<TagDecl *>(this)->getPreviousDecl());
|
||||||
|
}
|
||||||
|
const RecordDecl *getPreviousDecl() const {
|
||||||
|
return const_cast<RecordDecl*>(this)->getPreviousDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecordDecl *getMostRecentDecl() const {
|
|
||||||
return cast<RecordDecl>(TagDecl::getMostRecentDecl());
|
|
||||||
}
|
|
||||||
RecordDecl *getMostRecentDecl() {
|
RecordDecl *getMostRecentDecl() {
|
||||||
return cast<RecordDecl>(TagDecl::getMostRecentDecl());
|
return cast<RecordDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl());
|
||||||
|
}
|
||||||
|
const RecordDecl *getMostRecentDecl() const {
|
||||||
|
return const_cast<RecordDecl*>(this)->getMostRecentDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
|
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
|
||||||
@ -3106,13 +3229,17 @@ class BlockDecl : public Decl, public DeclContext {
|
|||||||
Capture *Captures;
|
Capture *Captures;
|
||||||
unsigned NumCaptures;
|
unsigned NumCaptures;
|
||||||
|
|
||||||
|
unsigned ManglingNumber;
|
||||||
|
Decl *ManglingContextDecl;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
|
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
|
||||||
: Decl(Block, DC, CaretLoc), DeclContext(Block),
|
: Decl(Block, DC, CaretLoc), DeclContext(Block),
|
||||||
IsVariadic(false), CapturesCXXThis(false),
|
IsVariadic(false), CapturesCXXThis(false),
|
||||||
BlockMissingReturnType(true), IsConversionFromLambda(false),
|
BlockMissingReturnType(true), IsConversionFromLambda(false),
|
||||||
ParamInfo(0), NumParams(0), Body(0),
|
ParamInfo(0), NumParams(0), Body(0),
|
||||||
SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
|
SignatureAsWritten(0), Captures(0), NumCaptures(0),
|
||||||
|
ManglingNumber(0), ManglingContextDecl(0) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
|
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
|
||||||
@ -3182,6 +3309,18 @@ class BlockDecl : public Decl, public DeclContext {
|
|||||||
const Capture *end,
|
const Capture *end,
|
||||||
bool capturesCXXThis);
|
bool capturesCXXThis);
|
||||||
|
|
||||||
|
unsigned getBlockManglingNumber() const {
|
||||||
|
return ManglingNumber;
|
||||||
|
}
|
||||||
|
Decl *getBlockManglingContextDecl() const {
|
||||||
|
return ManglingContextDecl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBlockMangling(unsigned Number, Decl *Ctx) {
|
||||||
|
ManglingNumber = Number;
|
||||||
|
ManglingContextDecl = Ctx;
|
||||||
|
}
|
||||||
|
|
||||||
virtual SourceRange getSourceRange() const LLVM_READONLY;
|
virtual SourceRange getSourceRange() const LLVM_READONLY;
|
||||||
|
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
@ -3354,7 +3493,7 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename decl_type>
|
template<typename decl_type>
|
||||||
void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
|
void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) {
|
||||||
// Note: This routine is implemented here because we need both NamedDecl
|
// Note: This routine is implemented here because we need both NamedDecl
|
||||||
// and Redeclarable to be defined.
|
// and Redeclarable to be defined.
|
||||||
|
|
||||||
@ -3364,10 +3503,16 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
|
|||||||
// Point to previous. Make sure that this is actually the most recent
|
// Point to previous. Make sure that this is actually the most recent
|
||||||
// redeclaration, or we can build invalid chains. If the most recent
|
// redeclaration, or we can build invalid chains. If the most recent
|
||||||
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
|
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
|
||||||
First = PrevDecl->getFirstDeclaration();
|
First = PrevDecl->getFirstDecl();
|
||||||
assert(First->RedeclLink.NextIsLatest() && "Expected first");
|
assert(First->RedeclLink.NextIsLatest() && "Expected first");
|
||||||
decl_type *MostRecent = First->RedeclLink.getNext();
|
decl_type *MostRecent = First->RedeclLink.getNext();
|
||||||
RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent));
|
RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent));
|
||||||
|
|
||||||
|
// If the declaration was previously visible, a redeclaration of it remains
|
||||||
|
// visible even if it wouldn't be visible by itself.
|
||||||
|
static_cast<decl_type*>(this)->IdentifierNamespace |=
|
||||||
|
MostRecent->getIdentifierNamespace() &
|
||||||
|
(Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
|
||||||
} else {
|
} else {
|
||||||
// Make this first.
|
// Make this first.
|
||||||
First = static_cast<decl_type*>(this);
|
First = static_cast<decl_type*>(this);
|
||||||
|
@ -28,7 +28,7 @@ class NamedDecl;
|
|||||||
/// A POD class for pairing a NamedDecl* with an access specifier.
|
/// A POD class for pairing a NamedDecl* with an access specifier.
|
||||||
/// Can be put into unions.
|
/// Can be put into unions.
|
||||||
class DeclAccessPair {
|
class DeclAccessPair {
|
||||||
NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
|
uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
|
||||||
|
|
||||||
enum { Mask = 0x3 };
|
enum { Mask = 0x3 };
|
||||||
|
|
||||||
@ -40,10 +40,10 @@ class DeclAccessPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NamedDecl *getDecl() const {
|
NamedDecl *getDecl() const {
|
||||||
return (NamedDecl*) (~Mask & (uintptr_t) Ptr);
|
return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
|
||||||
}
|
}
|
||||||
AccessSpecifier getAccess() const {
|
AccessSpecifier getAccess() const {
|
||||||
return AccessSpecifier(Mask & (uintptr_t) Ptr);
|
return AccessSpecifier(Mask & Ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDecl(NamedDecl *D) {
|
void setDecl(NamedDecl *D) {
|
||||||
@ -53,8 +53,7 @@ class DeclAccessPair {
|
|||||||
set(getDecl(), AS);
|
set(getDecl(), AS);
|
||||||
}
|
}
|
||||||
void set(NamedDecl *D, AccessSpecifier AS) {
|
void set(NamedDecl *D, AccessSpecifier AS) {
|
||||||
Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) |
|
Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D);
|
||||||
reinterpret_cast<uintptr_t>(D));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator NamedDecl*() const { return getDecl(); }
|
operator NamedDecl*() const { return getDecl(); }
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "clang/AST/AttrIterator.h"
|
#include "clang/AST/AttrIterator.h"
|
||||||
#include "clang/AST/DeclarationName.h"
|
#include "clang/AST/DeclarationName.h"
|
||||||
|
#include "clang/Basic/Linkage.h"
|
||||||
#include "clang/Basic/Specifiers.h"
|
#include "clang/Basic/Specifiers.h"
|
||||||
#include "llvm/ADT/PointerUnion.h"
|
#include "llvm/ADT/PointerUnion.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
@ -31,6 +32,7 @@ class DeclarationName;
|
|||||||
class DependentDiagnostic;
|
class DependentDiagnostic;
|
||||||
class EnumDecl;
|
class EnumDecl;
|
||||||
class FunctionDecl;
|
class FunctionDecl;
|
||||||
|
class LinkageComputer;
|
||||||
class LinkageSpecDecl;
|
class LinkageSpecDecl;
|
||||||
class Module;
|
class Module;
|
||||||
class NamedDecl;
|
class NamedDecl;
|
||||||
@ -157,7 +159,12 @@ class Decl {
|
|||||||
/// This declaration is a C++ operator declared in a non-class
|
/// This declaration is a C++ operator declared in a non-class
|
||||||
/// context. All such operators are also in IDNS_Ordinary.
|
/// context. All such operators are also in IDNS_Ordinary.
|
||||||
/// C++ lexical operator lookup looks for these.
|
/// C++ lexical operator lookup looks for these.
|
||||||
IDNS_NonMemberOperator = 0x0400
|
IDNS_NonMemberOperator = 0x0400,
|
||||||
|
|
||||||
|
/// This declaration is a function-local extern declaration of a
|
||||||
|
/// variable or function. This may also be IDNS_Ordinary if it
|
||||||
|
/// has been declared outside any function.
|
||||||
|
IDNS_LocalExtern = 0x0800
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ObjCDeclQualifier - 'Qualifiers' written next to the return and
|
/// ObjCDeclQualifier - 'Qualifiers' written next to the return and
|
||||||
@ -284,19 +291,16 @@ class Decl {
|
|||||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||||
unsigned IdentifierNamespace : 12;
|
unsigned IdentifierNamespace : 12;
|
||||||
|
|
||||||
/// \brief Whether the \c CachedLinkage field is active.
|
/// \brief If 0, we have not computed the linkage of this declaration.
|
||||||
///
|
/// Otherwise, it is the linkage + 1.
|
||||||
/// This field is only valid for NamedDecls subclasses.
|
mutable unsigned CacheValidAndLinkage : 3;
|
||||||
mutable unsigned HasCachedLinkage : 1;
|
|
||||||
|
|
||||||
/// \brief If \c HasCachedLinkage, the linkage of this declaration.
|
|
||||||
///
|
|
||||||
/// This field is only valid for NamedDecls subclasses.
|
|
||||||
mutable unsigned CachedLinkage : 2;
|
|
||||||
|
|
||||||
friend class ASTDeclWriter;
|
friend class ASTDeclWriter;
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
friend class ASTReader;
|
friend class ASTReader;
|
||||||
|
friend class LinkageComputer;
|
||||||
|
|
||||||
|
template<typename decl_type> friend class Redeclarable;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CheckAccessDeclContext() const;
|
void CheckAccessDeclContext() const;
|
||||||
@ -309,7 +313,7 @@ class Decl {
|
|||||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||||
HasCachedLinkage(0)
|
CacheValidAndLinkage(0)
|
||||||
{
|
{
|
||||||
if (StatisticsEnabled) add(DK);
|
if (StatisticsEnabled) add(DK);
|
||||||
}
|
}
|
||||||
@ -319,7 +323,7 @@ class Decl {
|
|||||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||||
HasCachedLinkage(0)
|
CacheValidAndLinkage(0)
|
||||||
{
|
{
|
||||||
if (StatisticsEnabled) add(DK);
|
if (StatisticsEnabled) add(DK);
|
||||||
}
|
}
|
||||||
@ -341,6 +345,18 @@ class Decl {
|
|||||||
/// \brief Update a potentially out-of-date declaration.
|
/// \brief Update a potentially out-of-date declaration.
|
||||||
void updateOutOfDate(IdentifierInfo &II) const;
|
void updateOutOfDate(IdentifierInfo &II) const;
|
||||||
|
|
||||||
|
Linkage getCachedLinkage() const {
|
||||||
|
return Linkage(CacheValidAndLinkage - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCachedLinkage(Linkage L) const {
|
||||||
|
CacheValidAndLinkage = L + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasCachedLinkage() const {
|
||||||
|
return CacheValidAndLinkage;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// \brief Source range that this declaration covers.
|
/// \brief Source range that this declaration covers.
|
||||||
@ -419,7 +435,6 @@ class Decl {
|
|||||||
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
|
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
|
||||||
}
|
}
|
||||||
const AttrVec &getAttrs() const;
|
const AttrVec &getAttrs() const;
|
||||||
void swapAttrs(Decl *D);
|
|
||||||
void dropAttrs();
|
void dropAttrs();
|
||||||
|
|
||||||
void addAttr(Attr *A) {
|
void addAttr(Attr *A) {
|
||||||
@ -490,7 +505,16 @@ class Decl {
|
|||||||
/// whether the function is used.
|
/// whether the function is used.
|
||||||
bool isUsed(bool CheckUsedAttr = true) const;
|
bool isUsed(bool CheckUsedAttr = true) const;
|
||||||
|
|
||||||
void setUsed(bool U = true) { Used = U; }
|
/// \brief Set whether the declaration is used, in the sense of odr-use.
|
||||||
|
///
|
||||||
|
/// This should only be used immediately after creating a declaration.
|
||||||
|
void setIsUsed() { Used = true; }
|
||||||
|
|
||||||
|
/// \brief Mark the declaration used, in the sense of odr-use.
|
||||||
|
///
|
||||||
|
/// This notifies any mutation listeners in addition to setting a bit
|
||||||
|
/// indicating the declaration is used.
|
||||||
|
void markUsed(ASTContext &C);
|
||||||
|
|
||||||
/// \brief Whether this declaration was referenced.
|
/// \brief Whether this declaration was referenced.
|
||||||
bool isReferenced() const;
|
bool isReferenced() const;
|
||||||
@ -513,13 +537,13 @@ class Decl {
|
|||||||
NextInContextAndBits.setInt(Bits);
|
NextInContextAndBits.setInt(Bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
/// \brief Whether this declaration was marked as being private to the
|
/// \brief Whether this declaration was marked as being private to the
|
||||||
/// module in which it was defined.
|
/// module in which it was defined.
|
||||||
bool isModulePrivate() const {
|
bool isModulePrivate() const {
|
||||||
return NextInContextAndBits.getInt() & ModulePrivateFlag;
|
return NextInContextAndBits.getInt() & ModulePrivateFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
/// \brief Specify whether this declaration was marked as being private
|
/// \brief Specify whether this declaration was marked as being private
|
||||||
/// to the module in which it was defined.
|
/// to the module in which it was defined.
|
||||||
void setModulePrivate(bool MP = true) {
|
void setModulePrivate(bool MP = true) {
|
||||||
@ -761,7 +785,12 @@ class Decl {
|
|||||||
const Decl *getPreviousDecl() const {
|
const Decl *getPreviousDecl() const {
|
||||||
return const_cast<Decl *>(this)->getPreviousDeclImpl();
|
return const_cast<Decl *>(this)->getPreviousDeclImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief True if this is the first declaration in its redeclaration chain.
|
||||||
|
bool isFirstDecl() const {
|
||||||
|
return getPreviousDecl() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the most recent declaration that declares the same entity
|
/// \brief Retrieve the most recent declaration that declares the same entity
|
||||||
/// as this declaration (which may be this declaration).
|
/// as this declaration (which may be this declaration).
|
||||||
Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); }
|
Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); }
|
||||||
@ -777,8 +806,10 @@ class Decl {
|
|||||||
/// top-level Stmt* of that body. Otherwise this method returns null.
|
/// top-level Stmt* of that body. Otherwise this method returns null.
|
||||||
virtual Stmt* getBody() const { return 0; }
|
virtual Stmt* getBody() const { return 0; }
|
||||||
|
|
||||||
/// \brief Returns true if this Decl represents a declaration for a body of
|
/// \brief Returns true if this \c Decl represents a declaration for a body of
|
||||||
/// code, such as a function or method definition.
|
/// code, such as a function or method definition.
|
||||||
|
/// Note that \c hasBody can also return true if any redeclaration of this
|
||||||
|
/// \c Decl represents a declaration for a body of code.
|
||||||
virtual bool hasBody() const { return getBody() != 0; }
|
virtual bool hasBody() const { return getBody() != 0; }
|
||||||
|
|
||||||
/// getBodyRBrace - Gets the right brace of the body, if a body exists.
|
/// getBodyRBrace - Gets the right brace of the body, if a body exists.
|
||||||
@ -807,6 +838,32 @@ class Decl {
|
|||||||
/// \brief Whether this declaration is a function or function template.
|
/// \brief Whether this declaration is a function or function template.
|
||||||
bool isFunctionOrFunctionTemplate() const;
|
bool isFunctionOrFunctionTemplate() const;
|
||||||
|
|
||||||
|
/// \brief Changes the namespace of this declaration to reflect that it's
|
||||||
|
/// a function-local extern declaration.
|
||||||
|
///
|
||||||
|
/// These declarations appear in the lexical context of the extern
|
||||||
|
/// declaration, but in the semantic context of the enclosing namespace
|
||||||
|
/// scope.
|
||||||
|
void setLocalExternDecl() {
|
||||||
|
assert((IdentifierNamespace == IDNS_Ordinary ||
|
||||||
|
IdentifierNamespace == IDNS_OrdinaryFriend) &&
|
||||||
|
"namespace is not ordinary");
|
||||||
|
|
||||||
|
Decl *Prev = getPreviousDecl();
|
||||||
|
IdentifierNamespace &= ~IDNS_Ordinary;
|
||||||
|
|
||||||
|
IdentifierNamespace |= IDNS_LocalExtern;
|
||||||
|
if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)
|
||||||
|
IdentifierNamespace |= IDNS_Ordinary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Determine whether this is a block-scope declaration with linkage.
|
||||||
|
/// This will either be a local variable declaration declared 'extern', or a
|
||||||
|
/// local function declaration.
|
||||||
|
bool isLocalExternDecl() {
|
||||||
|
return IdentifierNamespace & IDNS_LocalExtern;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Changes the namespace of this declaration to reflect that it's
|
/// \brief Changes the namespace of this declaration to reflect that it's
|
||||||
/// the object of a friend declaration.
|
/// the object of a friend declaration.
|
||||||
///
|
///
|
||||||
@ -814,31 +871,39 @@ class Decl {
|
|||||||
/// class, but in the semantic context of the actual entity. This property
|
/// class, but in the semantic context of the actual entity. This property
|
||||||
/// applies only to a specific decl object; other redeclarations of the
|
/// applies only to a specific decl object; other redeclarations of the
|
||||||
/// same entity may not (and probably don't) share this property.
|
/// same entity may not (and probably don't) share this property.
|
||||||
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
|
void setObjectOfFriendDecl(bool PerformFriendInjection = false) {
|
||||||
unsigned OldNS = IdentifierNamespace;
|
unsigned OldNS = IdentifierNamespace;
|
||||||
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
|
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
|
||||||
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
|
IDNS_TagFriend | IDNS_OrdinaryFriend |
|
||||||
|
IDNS_LocalExtern)) &&
|
||||||
"namespace includes neither ordinary nor tag");
|
"namespace includes neither ordinary nor tag");
|
||||||
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
|
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
|
||||||
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
|
IDNS_TagFriend | IDNS_OrdinaryFriend |
|
||||||
|
IDNS_LocalExtern)) &&
|
||||||
"namespace includes other than ordinary or tag");
|
"namespace includes other than ordinary or tag");
|
||||||
|
|
||||||
IdentifierNamespace = 0;
|
Decl *Prev = getPreviousDecl();
|
||||||
|
IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type);
|
||||||
|
|
||||||
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
|
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
|
||||||
IdentifierNamespace |= IDNS_TagFriend;
|
IdentifierNamespace |= IDNS_TagFriend;
|
||||||
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type;
|
if (PerformFriendInjection ||
|
||||||
|
(Prev && Prev->getIdentifierNamespace() & IDNS_Tag))
|
||||||
|
IdentifierNamespace |= IDNS_Tag | IDNS_Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
|
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) {
|
||||||
IdentifierNamespace |= IDNS_OrdinaryFriend;
|
IdentifierNamespace |= IDNS_OrdinaryFriend;
|
||||||
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
|
if (PerformFriendInjection ||
|
||||||
|
(Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
|
||||||
|
IdentifierNamespace |= IDNS_Ordinary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FriendObjectKind {
|
enum FriendObjectKind {
|
||||||
FOK_None, // not a friend object
|
FOK_None, ///< Not a friend object.
|
||||||
FOK_Declared, // a friend of a previously-declared entity
|
FOK_Declared, ///< A friend of a previously-declared entity.
|
||||||
FOK_Undeclared // a friend of a previously-undeclared entity
|
FOK_Undeclared ///< A friend of a previously-undeclared entity.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Determines whether this declaration is the object of a
|
/// \brief Determines whether this declaration is the object of a
|
||||||
@ -846,11 +911,11 @@ class Decl {
|
|||||||
///
|
///
|
||||||
/// There is currently no direct way to find the associated FriendDecl.
|
/// There is currently no direct way to find the associated FriendDecl.
|
||||||
FriendObjectKind getFriendObjectKind() const {
|
FriendObjectKind getFriendObjectKind() const {
|
||||||
unsigned mask
|
unsigned mask =
|
||||||
= (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
|
(IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
|
||||||
if (!mask) return FOK_None;
|
if (!mask) return FOK_None;
|
||||||
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
|
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared
|
||||||
FOK_Declared : FOK_Undeclared);
|
: FOK_Undeclared);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies that this declaration is a C++ overloaded non-member.
|
/// Specifies that this declaration is a C++ overloaded non-member.
|
||||||
@ -877,9 +942,6 @@ class Decl {
|
|||||||
// Same as dump(), but forces color printing.
|
// Same as dump(), but forces color printing.
|
||||||
LLVM_ATTRIBUTE_USED void dumpColor() const;
|
LLVM_ATTRIBUTE_USED void dumpColor() const;
|
||||||
void dump(raw_ostream &Out) const;
|
void dump(raw_ostream &Out) const;
|
||||||
// Debuggers don't usually respect default arguments.
|
|
||||||
LLVM_ATTRIBUTE_USED void dumpXML() const;
|
|
||||||
void dumpXML(raw_ostream &OS) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
|
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
|
||||||
@ -974,6 +1036,7 @@ class DeclContext {
|
|||||||
mutable Decl *LastDecl;
|
mutable Decl *LastDecl;
|
||||||
|
|
||||||
friend class ExternalASTSource;
|
friend class ExternalASTSource;
|
||||||
|
friend class ASTDeclReader;
|
||||||
friend class ASTWriter;
|
friend class ASTWriter;
|
||||||
|
|
||||||
/// \brief Build up a chain of declarations.
|
/// \brief Build up a chain of declarations.
|
||||||
@ -1096,6 +1159,14 @@ class DeclContext {
|
|||||||
/// C++0x scoped enums), and C++ linkage specifications.
|
/// C++0x scoped enums), and C++ linkage specifications.
|
||||||
bool isTransparentContext() const;
|
bool isTransparentContext() const;
|
||||||
|
|
||||||
|
/// \brief Determines whether this context or some of its ancestors is a
|
||||||
|
/// linkage specification context that specifies C linkage.
|
||||||
|
bool isExternCContext() const;
|
||||||
|
|
||||||
|
/// \brief Determines whether this context or some of its ancestors is a
|
||||||
|
/// linkage specification context that specifies C++ linkage.
|
||||||
|
bool isExternCXXContext() const;
|
||||||
|
|
||||||
/// \brief Determine whether this declaration context is equivalent
|
/// \brief Determine whether this declaration context is equivalent
|
||||||
/// to the declaration context DC.
|
/// to the declaration context DC.
|
||||||
bool Equals(const DeclContext *DC) const {
|
bool Equals(const DeclContext *DC) const {
|
||||||
@ -1429,12 +1500,20 @@ class DeclContext {
|
|||||||
return const_cast<DeclContext*>(this)->lookup(Name);
|
return const_cast<DeclContext*>(this)->lookup(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Find the declarations with the given name that are visible
|
||||||
|
/// within this context; don't attempt to retrieve anything from an
|
||||||
|
/// external source.
|
||||||
|
lookup_result noload_lookup(DeclarationName Name);
|
||||||
|
|
||||||
/// \brief A simplistic name lookup mechanism that performs name lookup
|
/// \brief A simplistic name lookup mechanism that performs name lookup
|
||||||
/// into this declaration context without consulting the external source.
|
/// into this declaration context without consulting the external source.
|
||||||
///
|
///
|
||||||
/// This function should almost never be used, because it subverts the
|
/// This function should almost never be used, because it subverts the
|
||||||
/// usual relationship between a DeclContext and the external source.
|
/// usual relationship between a DeclContext and the external source.
|
||||||
/// See the ASTImporter for the (few, but important) use cases.
|
/// See the ASTImporter for the (few, but important) use cases.
|
||||||
|
///
|
||||||
|
/// FIXME: This is very inefficient; replace uses of it with uses of
|
||||||
|
/// noload_lookup.
|
||||||
void localUncachedLookup(DeclarationName Name,
|
void localUncachedLookup(DeclarationName Name,
|
||||||
SmallVectorImpl<NamedDecl *> &Results);
|
SmallVectorImpl<NamedDecl *> &Results);
|
||||||
|
|
||||||
@ -1458,10 +1537,16 @@ class DeclContext {
|
|||||||
/// of looking up every possible name.
|
/// of looking up every possible name.
|
||||||
class all_lookups_iterator;
|
class all_lookups_iterator;
|
||||||
|
|
||||||
|
/// \brief Iterators over all possible lookups within this context.
|
||||||
all_lookups_iterator lookups_begin() const;
|
all_lookups_iterator lookups_begin() const;
|
||||||
|
|
||||||
all_lookups_iterator lookups_end() const;
|
all_lookups_iterator lookups_end() const;
|
||||||
|
|
||||||
|
/// \brief Iterators over all possible lookups within this context that are
|
||||||
|
/// currently loaded; don't attempt to retrieve anything from an external
|
||||||
|
/// source.
|
||||||
|
all_lookups_iterator noload_lookups_begin() const;
|
||||||
|
all_lookups_iterator noload_lookups_end() const;
|
||||||
|
|
||||||
/// udir_iterator - Iterates through the using-directives stored
|
/// udir_iterator - Iterates through the using-directives stored
|
||||||
/// within this context.
|
/// within this context.
|
||||||
typedef UsingDirectiveDecl * const * udir_iterator;
|
typedef UsingDirectiveDecl * const * udir_iterator;
|
||||||
@ -1532,6 +1617,8 @@ class DeclContext {
|
|||||||
static bool classof(const DeclContext *D) { return true; }
|
static bool classof(const DeclContext *D) { return true; }
|
||||||
|
|
||||||
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
|
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
|
||||||
|
LLVM_ATTRIBUTE_USED void dumpLookups() const;
|
||||||
|
LLVM_ATTRIBUTE_USED void dumpLookups(llvm::raw_ostream &OS) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reconcileExternalVisibleStorage();
|
void reconcileExternalVisibleStorage();
|
||||||
@ -1548,6 +1635,8 @@ class DeclContext {
|
|||||||
friend class DependentDiagnostic;
|
friend class DependentDiagnostic;
|
||||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||||
|
|
||||||
|
template<decl_iterator (DeclContext::*Begin)() const,
|
||||||
|
decl_iterator (DeclContext::*End)() const>
|
||||||
void buildLookupImpl(DeclContext *DCtx);
|
void buildLookupImpl(DeclContext *DCtx);
|
||||||
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||||
bool Rediscoverable);
|
bool Rediscoverable);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
|||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
#include "clang/AST/DeclarationName.h"
|
#include "clang/AST/DeclarationName.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/PointerIntPair.h"
|
||||||
#include "llvm/ADT/PointerUnion.h"
|
#include "llvm/ADT/PointerUnion.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -26,23 +27,29 @@ namespace clang {
|
|||||||
|
|
||||||
class DependentDiagnostic;
|
class DependentDiagnostic;
|
||||||
|
|
||||||
/// StoredDeclsList - This is an array of decls optimized a common case of only
|
/// \brief An array of decls optimized for the common case of only containing
|
||||||
/// containing one entry.
|
/// one entry.
|
||||||
struct StoredDeclsList {
|
struct StoredDeclsList {
|
||||||
|
|
||||||
/// DeclsTy - When in vector form, this is what the Data pointer points to.
|
/// \brief When in vector form, this is what the Data pointer points to.
|
||||||
typedef SmallVector<NamedDecl *, 4> DeclsTy;
|
typedef SmallVector<NamedDecl *, 4> DeclsTy;
|
||||||
|
|
||||||
|
/// \brief A collection of declarations, with a flag to indicate if we have
|
||||||
|
/// further external declarations.
|
||||||
|
typedef llvm::PointerIntPair<DeclsTy *, 1, bool> DeclsAndHasExternalTy;
|
||||||
|
|
||||||
/// \brief The stored data, which will be either a pointer to a NamedDecl,
|
/// \brief The stored data, which will be either a pointer to a NamedDecl,
|
||||||
/// or a pointer to a vector.
|
/// or a pointer to a vector with a flag to indicate if there are further
|
||||||
llvm::PointerUnion<NamedDecl *, DeclsTy *> Data;
|
/// external declarations.
|
||||||
|
llvm::PointerUnion<NamedDecl*, DeclsAndHasExternalTy> Data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StoredDeclsList() {}
|
StoredDeclsList() {}
|
||||||
|
|
||||||
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
|
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
|
||||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||||
Data = new DeclsTy(*RHSVec);
|
Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec),
|
||||||
|
RHS.hasExternalDecls());
|
||||||
}
|
}
|
||||||
|
|
||||||
~StoredDeclsList() {
|
~StoredDeclsList() {
|
||||||
@ -56,7 +63,7 @@ struct StoredDeclsList {
|
|||||||
delete Vector;
|
delete Vector;
|
||||||
Data = RHS.Data;
|
Data = RHS.Data;
|
||||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||||
Data = new DeclsTy(*RHSVec);
|
Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec), hasExternalDecls());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,8 +73,27 @@ struct StoredDeclsList {
|
|||||||
return Data.dyn_cast<NamedDecl *>();
|
return Data.dyn_cast<NamedDecl *>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeclsAndHasExternalTy getAsVectorAndHasExternal() const {
|
||||||
|
return Data.dyn_cast<DeclsAndHasExternalTy>();
|
||||||
|
}
|
||||||
|
|
||||||
DeclsTy *getAsVector() const {
|
DeclsTy *getAsVector() const {
|
||||||
return Data.dyn_cast<DeclsTy *>();
|
return getAsVectorAndHasExternal().getPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasExternalDecls() const {
|
||||||
|
return getAsVectorAndHasExternal().getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHasExternalDecls() {
|
||||||
|
if (DeclsTy *Vec = getAsVector())
|
||||||
|
Data = DeclsAndHasExternalTy(Vec, true);
|
||||||
|
else {
|
||||||
|
DeclsTy *VT = new DeclsTy();
|
||||||
|
if (NamedDecl *OldD = getAsDecl())
|
||||||
|
VT->push_back(OldD);
|
||||||
|
Data = DeclsAndHasExternalTy(VT, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOnlyValue(NamedDecl *ND) {
|
void setOnlyValue(NamedDecl *ND) {
|
||||||
@ -110,6 +136,8 @@ struct StoredDeclsList {
|
|||||||
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
|
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
|
||||||
std::mem_fun(&Decl::isFromASTFile)),
|
std::mem_fun(&Decl::isFromASTFile)),
|
||||||
Vec.end());
|
Vec.end());
|
||||||
|
// Don't have any external decls any more.
|
||||||
|
Data = DeclsAndHasExternalTy(&Vec, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,12 +193,14 @@ struct StoredDeclsList {
|
|||||||
/// not a redeclaration to merge it into the appropriate place in our list.
|
/// not a redeclaration to merge it into the appropriate place in our list.
|
||||||
///
|
///
|
||||||
void AddSubsequentDecl(NamedDecl *D) {
|
void AddSubsequentDecl(NamedDecl *D) {
|
||||||
|
assert(!isNull() && "don't AddSubsequentDecl when we have no decls");
|
||||||
|
|
||||||
// If this is the second decl added to the list, convert this to vector
|
// If this is the second decl added to the list, convert this to vector
|
||||||
// form.
|
// form.
|
||||||
if (NamedDecl *OldD = getAsDecl()) {
|
if (NamedDecl *OldD = getAsDecl()) {
|
||||||
DeclsTy *VT = new DeclsTy();
|
DeclsTy *VT = new DeclsTy();
|
||||||
VT->push_back(OldD);
|
VT->push_back(OldD);
|
||||||
Data = VT;
|
Data = DeclsAndHasExternalTy(VT, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclsTy &Vec = *getAsVector();
|
DeclsTy &Vec = *getAsVector();
|
||||||
|
@ -220,7 +220,7 @@ class CXXRecordDecl::friend_iterator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
|
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
|
||||||
return friend_iterator(data().FirstFriend);
|
return friend_iterator(getFirstFriend());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
|
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
|
||||||
@ -228,7 +228,7 @@ inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
|
inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
|
||||||
assert(FD->NextFriend == 0 && "friend already has next friend?");
|
assert(!FD->NextFriend && "friend already has next friend?");
|
||||||
FD->NextFriend = data().FirstFriend;
|
FD->NextFriend = data().FirstFriend;
|
||||||
data().FirstFriend = FD;
|
data().FirstFriend = FD;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ class DeclContext::all_lookups_iterator {
|
|||||||
StoredDeclsMap::iterator End)
|
StoredDeclsMap::iterator End)
|
||||||
: It(It), End(End) {}
|
: It(It), End(End) {}
|
||||||
|
|
||||||
|
DeclarationName getLookupName() const { return It->first; }
|
||||||
|
|
||||||
reference operator*() const { return It->second.getLookupResult(); }
|
reference operator*() const { return It->second.getLookupResult(); }
|
||||||
pointer operator->() const { return It->second.getLookupResult(); }
|
pointer operator->() const { return It->second.getLookupResult(); }
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ class DeclContext::all_lookups_iterator {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
inline DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
||||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||||
if (Primary->hasExternalVisibleStorage())
|
if (Primary->hasExternalVisibleStorage())
|
||||||
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
||||||
@ -75,7 +77,7 @@ DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
|||||||
return all_lookups_iterator();
|
return all_lookups_iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
|
inline DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
|
||||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||||
if (Primary->hasExternalVisibleStorage())
|
if (Primary->hasExternalVisibleStorage())
|
||||||
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
||||||
@ -84,6 +86,22 @@ DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
|
|||||||
return all_lookups_iterator();
|
return all_lookups_iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
DeclContext::all_lookups_iterator DeclContext::noload_lookups_begin() const {
|
||||||
|
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||||
|
if (StoredDeclsMap *Map = Primary->getLookupPtr())
|
||||||
|
return all_lookups_iterator(Map->begin(), Map->end());
|
||||||
|
return all_lookups_iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
DeclContext::all_lookups_iterator DeclContext::noload_lookups_end() const {
|
||||||
|
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||||
|
if (StoredDeclsMap *Map = Primary->getLookupPtr())
|
||||||
|
return all_lookups_iterator(Map->end(), Map->end());
|
||||||
|
return all_lookups_iterator();
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -452,7 +452,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine whether this method has a body.
|
/// \brief Determine whether this method has a body.
|
||||||
virtual bool hasBody() const { return Body; }
|
virtual bool hasBody() const { return Body.isValid(); }
|
||||||
|
|
||||||
/// \brief Retrieve the body of this method, if it has one.
|
/// \brief Retrieve the body of this method, if it has one.
|
||||||
virtual Stmt *getBody() const;
|
virtual Stmt *getBody() const;
|
||||||
@ -463,7 +463,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
|||||||
void setBody(Stmt *B) { Body = B; }
|
void setBody(Stmt *B) { Body = B; }
|
||||||
|
|
||||||
/// \brief Returns whether this specific method is a definition.
|
/// \brief Returns whether this specific method is a definition.
|
||||||
bool isThisDeclarationADefinition() const { return Body; }
|
bool isThisDeclarationADefinition() const { return hasBody(); }
|
||||||
|
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
@ -553,6 +553,9 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
|||||||
|
|
||||||
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
|
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
|
||||||
|
|
||||||
|
typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
|
||||||
|
ProtocolPropertyMap;
|
||||||
|
|
||||||
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
|
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
|
||||||
|
|
||||||
/// This routine collects list of properties to be implemented in the class.
|
/// This routine collects list of properties to be implemented in the class.
|
||||||
@ -1133,6 +1136,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
|||||||
return lookupInstanceVariable(IVarName, ClassDeclared);
|
return lookupInstanceVariable(IVarName, ClassDeclared);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjCProtocolDecl *lookupNestedProtocol(IdentifierInfo *Name);
|
||||||
|
|
||||||
// Lookup a method. First, we search locally. If a method isn't
|
// Lookup a method. First, we search locally. If a method isn't
|
||||||
// found, we search referenced protocols and class categories.
|
// found, we search referenced protocols and class categories.
|
||||||
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
|
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
|
||||||
@ -1196,14 +1201,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
/// Retrieves the canonical declaration of this Objective-C class.
|
/// Retrieves the canonical declaration of this Objective-C class.
|
||||||
ObjCInterfaceDecl *getCanonicalDecl() {
|
ObjCInterfaceDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||||
return getFirstDeclaration();
|
const ObjCInterfaceDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||||
}
|
|
||||||
const ObjCInterfaceDecl *getCanonicalDecl() const {
|
|
||||||
return getFirstDeclaration();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Low-level accessor
|
// Low-level accessor
|
||||||
const Type *getTypeForDecl() const { return TypeForDecl; }
|
const Type *getTypeForDecl() const { return TypeForDecl; }
|
||||||
@ -1244,10 +1246,12 @@ class ObjCIvarDecl : public FieldDecl {
|
|||||||
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
|
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
|
||||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||||
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
|
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
|
||||||
bool synthesized)
|
bool synthesized,
|
||||||
|
bool backingIvarReferencedInAccessor)
|
||||||
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
|
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
|
||||||
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
|
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
|
||||||
NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
|
NextIvar(0), DeclAccess(ac), Synthesized(synthesized),
|
||||||
|
BackingIvarReferencedInAccessor(backingIvarReferencedInAccessor) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
|
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
|
||||||
@ -1255,7 +1259,8 @@ class ObjCIvarDecl : public FieldDecl {
|
|||||||
IdentifierInfo *Id, QualType T,
|
IdentifierInfo *Id, QualType T,
|
||||||
TypeSourceInfo *TInfo,
|
TypeSourceInfo *TInfo,
|
||||||
AccessControl ac, Expr *BW = NULL,
|
AccessControl ac, Expr *BW = NULL,
|
||||||
bool synthesized=false);
|
bool synthesized=false,
|
||||||
|
bool backingIvarReferencedInAccessor=false);
|
||||||
|
|
||||||
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||||
|
|
||||||
@ -1277,6 +1282,13 @@ class ObjCIvarDecl : public FieldDecl {
|
|||||||
return DeclAccess == None ? Protected : AccessControl(DeclAccess);
|
return DeclAccess == None ? Protected : AccessControl(DeclAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBackingIvarReferencedInAccessor(bool val) {
|
||||||
|
BackingIvarReferencedInAccessor = val;
|
||||||
|
}
|
||||||
|
bool getBackingIvarReferencedInAccessor() const {
|
||||||
|
return BackingIvarReferencedInAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
void setSynthesize(bool synth) { Synthesized = synth; }
|
void setSynthesize(bool synth) { Synthesized = synth; }
|
||||||
bool getSynthesize() const { return Synthesized; }
|
bool getSynthesize() const { return Synthesized; }
|
||||||
|
|
||||||
@ -1291,6 +1303,7 @@ class ObjCIvarDecl : public FieldDecl {
|
|||||||
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
|
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
|
||||||
unsigned DeclAccess : 3;
|
unsigned DeclAccess : 3;
|
||||||
unsigned Synthesized : 1;
|
unsigned Synthesized : 1;
|
||||||
|
unsigned BackingIvarReferencedInAccessor : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1502,17 +1515,17 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
/// Retrieves the canonical declaration of this Objective-C protocol.
|
/// Retrieves the canonical declaration of this Objective-C protocol.
|
||||||
ObjCProtocolDecl *getCanonicalDecl() {
|
ObjCProtocolDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||||
return getFirstDeclaration();
|
const ObjCProtocolDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||||
}
|
|
||||||
const ObjCProtocolDecl *getCanonicalDecl() const {
|
|
||||||
return getFirstDeclaration();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void collectPropertiesToImplement(PropertyMap &PM,
|
virtual void collectPropertiesToImplement(PropertyMap &PM,
|
||||||
PropertyDeclOrder &PO) const;
|
PropertyDeclOrder &PO) const;
|
||||||
|
|
||||||
|
void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
|
||||||
|
ProtocolPropertyMap &PM) const;
|
||||||
|
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
static bool classofKind(Kind K) { return K == ObjCProtocol; }
|
static bool classofKind(Kind K) { return K == ObjCProtocol; }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===//
|
//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -8,7 +8,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
///
|
///
|
||||||
/// \file
|
/// \file
|
||||||
/// \brief This file defines OpenMP nodes.
|
/// \brief This file defines OpenMP nodes for declarative directives.
|
||||||
///
|
///
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
class DeclRefExpr;
|
|
||||||
|
|
||||||
/// \brief This represents '#pragma omp threadprivate ...' directive.
|
/// \brief This represents '#pragma omp threadprivate ...' directive.
|
||||||
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
|
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
|
||||||
///
|
///
|
||||||
@ -43,29 +41,29 @@ class OMPThreadPrivateDecl : public Decl {
|
|||||||
OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
|
OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
|
||||||
Decl(DK, DC, L), NumVars(0) { }
|
Decl(DK, DC, L), NumVars(0) { }
|
||||||
|
|
||||||
ArrayRef<const DeclRefExpr *> getVars() const {
|
ArrayRef<const Expr *> getVars() const {
|
||||||
return ArrayRef<const DeclRefExpr *>(
|
return ArrayRef<const Expr *>(
|
||||||
reinterpret_cast<const DeclRefExpr * const *>(this + 1),
|
reinterpret_cast<const Expr * const *>(this + 1),
|
||||||
NumVars);
|
NumVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::MutableArrayRef<DeclRefExpr *> getVars() {
|
llvm::MutableArrayRef<Expr *> getVars() {
|
||||||
return llvm::MutableArrayRef<DeclRefExpr *>(
|
return llvm::MutableArrayRef<Expr *>(
|
||||||
reinterpret_cast<DeclRefExpr **>(this + 1),
|
reinterpret_cast<Expr **>(this + 1),
|
||||||
NumVars);
|
NumVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setVars(ArrayRef<DeclRefExpr *> VL);
|
void setVars(ArrayRef<Expr *> VL);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
|
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation L,
|
SourceLocation L,
|
||||||
ArrayRef<DeclRefExpr *> VL);
|
ArrayRef<Expr *> VL);
|
||||||
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
|
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
|
||||||
unsigned ID, unsigned N);
|
unsigned ID, unsigned N);
|
||||||
|
|
||||||
typedef llvm::MutableArrayRef<DeclRefExpr *>::iterator varlist_iterator;
|
typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator;
|
||||||
typedef ArrayRef<const DeclRefExpr *>::iterator varlist_const_iterator;
|
typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
|
||||||
|
|
||||||
unsigned varlist_size() const { return NumVars; }
|
unsigned varlist_size() const { return NumVars; }
|
||||||
bool varlist_empty() const { return NumVars == 0; }
|
bool varlist_empty() const { return NumVars == 0; }
|
||||||
|
@ -34,6 +34,8 @@ class TemplateTypeParmDecl;
|
|||||||
class NonTypeTemplateParmDecl;
|
class NonTypeTemplateParmDecl;
|
||||||
class TemplateTemplateParmDecl;
|
class TemplateTemplateParmDecl;
|
||||||
class TypeAliasTemplateDecl;
|
class TypeAliasTemplateDecl;
|
||||||
|
class VarTemplateDecl;
|
||||||
|
class VarTemplatePartialSpecializationDecl;
|
||||||
|
|
||||||
/// \brief Stores a template parameter of any kind.
|
/// \brief Stores a template parameter of any kind.
|
||||||
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
|
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
|
||||||
@ -629,9 +631,9 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
|||||||
template <class decl_type> friend class RedeclarableTemplate;
|
template <class decl_type> friend class RedeclarableTemplate;
|
||||||
|
|
||||||
/// \brief Retrieves the canonical declaration of this template.
|
/// \brief Retrieves the canonical declaration of this template.
|
||||||
RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDeclaration(); }
|
RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||||
const RedeclarableTemplateDecl *getCanonicalDecl() const {
|
const RedeclarableTemplateDecl *getCanonicalDecl() const {
|
||||||
return getFirstDeclaration();
|
return getFirstDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determines whether this template was a specialization of a
|
/// \brief Determines whether this template was a specialization of a
|
||||||
@ -713,6 +715,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
|||||||
using redeclarable_base::redecls_end;
|
using redeclarable_base::redecls_end;
|
||||||
using redeclarable_base::getPreviousDecl;
|
using redeclarable_base::getPreviousDecl;
|
||||||
using redeclarable_base::getMostRecentDecl;
|
using redeclarable_base::getMostRecentDecl;
|
||||||
|
using redeclarable_base::isFirstDecl;
|
||||||
|
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
@ -743,7 +746,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
/// \brief Data that is common to all of the declarations of a given
|
/// \brief Data that is common to all of the declarations of a given
|
||||||
/// function template.
|
/// function template.
|
||||||
struct Common : CommonBase {
|
struct Common : CommonBase {
|
||||||
Common() : InjectedArgs(0) { }
|
Common() : InjectedArgs(), LazySpecializations() { }
|
||||||
|
|
||||||
/// \brief The function template specializations for this function
|
/// \brief The function template specializations for this function
|
||||||
/// template, including explicit specializations and instantiations.
|
/// template, including explicit specializations and instantiations.
|
||||||
@ -757,6 +760,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
/// template, and is allocated lazily, since most function templates do not
|
/// template, and is allocated lazily, since most function templates do not
|
||||||
/// require the use of this information.
|
/// require the use of this information.
|
||||||
TemplateArgument *InjectedArgs;
|
TemplateArgument *InjectedArgs;
|
||||||
|
|
||||||
|
/// \brief If non-null, points to an array of specializations known only
|
||||||
|
/// by their external declaration IDs.
|
||||||
|
///
|
||||||
|
/// The first value in the array is the number of of specializations
|
||||||
|
/// that follow.
|
||||||
|
uint32_t *LazySpecializations;
|
||||||
};
|
};
|
||||||
|
|
||||||
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||||
@ -771,12 +781,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
|
|
||||||
friend class FunctionDecl;
|
friend class FunctionDecl;
|
||||||
|
|
||||||
|
/// \brief Load any lazily-loaded specializations from the external source.
|
||||||
|
void LoadLazySpecializations() const;
|
||||||
|
|
||||||
/// \brief Retrieve the set of function template specializations of this
|
/// \brief Retrieve the set of function template specializations of this
|
||||||
/// function template.
|
/// function template.
|
||||||
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
|
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
|
||||||
getSpecializations() const {
|
getSpecializations() const;
|
||||||
return getCommonPtr()->Specializations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Add a specialization of this function template.
|
/// \brief Add a specialization of this function template.
|
||||||
///
|
///
|
||||||
@ -815,14 +826,14 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
/// NULL if no such declaration exists.
|
/// NULL if no such declaration exists.
|
||||||
FunctionTemplateDecl *getPreviousDecl() {
|
FunctionTemplateDecl *getPreviousDecl() {
|
||||||
return cast_or_null<FunctionTemplateDecl>(
|
return cast_or_null<FunctionTemplateDecl>(
|
||||||
RedeclarableTemplateDecl::getPreviousDecl());
|
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the previous declaration of this function template, or
|
/// \brief Retrieve the previous declaration of this function template, or
|
||||||
/// NULL if no such declaration exists.
|
/// NULL if no such declaration exists.
|
||||||
const FunctionTemplateDecl *getPreviousDecl() const {
|
const FunctionTemplateDecl *getPreviousDecl() const {
|
||||||
return cast_or_null<FunctionTemplateDecl>(
|
return cast_or_null<FunctionTemplateDecl>(
|
||||||
RedeclarableTemplateDecl::getPreviousDecl());
|
static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
|
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||||
@ -847,7 +858,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
/// arguments for a function template, the notion is convenient when
|
/// arguments for a function template, the notion is convenient when
|
||||||
/// we need to perform substitutions inside the definition of a function
|
/// we need to perform substitutions inside the definition of a function
|
||||||
/// template.
|
/// template.
|
||||||
std::pair<const TemplateArgument *, unsigned> getInjectedTemplateArgs();
|
ArrayRef<TemplateArgument> getInjectedTemplateArgs();
|
||||||
|
|
||||||
/// \brief Create a function template node.
|
/// \brief Create a function template node.
|
||||||
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
@ -1377,7 +1388,7 @@ class ClassTemplateSpecializationDecl
|
|||||||
|
|
||||||
/// \brief The template argument list deduced for the class template
|
/// \brief The template argument list deduced for the class template
|
||||||
/// partial specialization itself.
|
/// partial specialization itself.
|
||||||
TemplateArgumentList *TemplateArgs;
|
const TemplateArgumentList *TemplateArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief The template that this specialization specializes
|
/// \brief The template that this specialization specializes
|
||||||
@ -1402,7 +1413,7 @@ class ClassTemplateSpecializationDecl
|
|||||||
ExplicitSpecializationInfo *ExplicitInfo;
|
ExplicitSpecializationInfo *ExplicitInfo;
|
||||||
|
|
||||||
/// \brief The template arguments used to describe this specialization.
|
/// \brief The template arguments used to describe this specialization.
|
||||||
TemplateArgumentList *TemplateArgs;
|
const TemplateArgumentList *TemplateArgs;
|
||||||
|
|
||||||
/// \brief The point where this template was instantiated (if any)
|
/// \brief The point where this template was instantiated (if any)
|
||||||
SourceLocation PointOfInstantiation;
|
SourceLocation PointOfInstantiation;
|
||||||
@ -1438,9 +1449,9 @@ class ClassTemplateSpecializationDecl
|
|||||||
bool Qualified) const;
|
bool Qualified) const;
|
||||||
|
|
||||||
ClassTemplateSpecializationDecl *getMostRecentDecl() {
|
ClassTemplateSpecializationDecl *getMostRecentDecl() {
|
||||||
CXXRecordDecl *Recent
|
CXXRecordDecl *Recent = static_cast<CXXRecordDecl *>(
|
||||||
= cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDecl());
|
this)->getMostRecentDecl();
|
||||||
if (!isa<ClassTemplateSpecializationDecl>(Recent)) {
|
while (!isa<ClassTemplateSpecializationDecl>(Recent)) {
|
||||||
// FIXME: Does injected class name need to be in the redeclarations chain?
|
// FIXME: Does injected class name need to be in the redeclarations chain?
|
||||||
assert(Recent->isInjectedClassName() && Recent->getPreviousDecl());
|
assert(Recent->isInjectedClassName() && Recent->getPreviousDecl());
|
||||||
Recent = Recent->getPreviousDecl();
|
Recent = Recent->getPreviousDecl();
|
||||||
@ -1553,7 +1564,7 @@ class ClassTemplateSpecializationDecl
|
|||||||
/// instantiation of the given class template partial specialization whose
|
/// instantiation of the given class template partial specialization whose
|
||||||
/// template arguments have been deduced.
|
/// template arguments have been deduced.
|
||||||
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
|
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
|
||||||
TemplateArgumentList *TemplateArgs) {
|
const TemplateArgumentList *TemplateArgs) {
|
||||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
|
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
|
||||||
"Already set to a class template partial specialization!");
|
"Already set to a class template partial specialization!");
|
||||||
SpecializedPartialSpecialization *PS
|
SpecializedPartialSpecialization *PS
|
||||||
@ -1639,13 +1650,7 @@ class ClassTemplatePartialSpecializationDecl
|
|||||||
|
|
||||||
/// \brief The source info for the template arguments as written.
|
/// \brief The source info for the template arguments as written.
|
||||||
/// FIXME: redundant with TypeAsWritten?
|
/// FIXME: redundant with TypeAsWritten?
|
||||||
TemplateArgumentLoc *ArgsAsWritten;
|
const ASTTemplateArgumentListInfo *ArgsAsWritten;
|
||||||
unsigned NumArgsAsWritten;
|
|
||||||
|
|
||||||
/// \brief Sequence number indicating when this class template partial
|
|
||||||
/// specialization was added to the set of partial specializations for
|
|
||||||
/// its owning class template.
|
|
||||||
unsigned SequenceNumber;
|
|
||||||
|
|
||||||
/// \brief The class template partial specialization from which this
|
/// \brief The class template partial specialization from which this
|
||||||
/// class template partial specialization was instantiated.
|
/// class template partial specialization was instantiated.
|
||||||
@ -1663,16 +1668,12 @@ class ClassTemplatePartialSpecializationDecl
|
|||||||
ClassTemplateDecl *SpecializedTemplate,
|
ClassTemplateDecl *SpecializedTemplate,
|
||||||
const TemplateArgument *Args,
|
const TemplateArgument *Args,
|
||||||
unsigned NumArgs,
|
unsigned NumArgs,
|
||||||
TemplateArgumentLoc *ArgInfos,
|
const ASTTemplateArgumentListInfo *ArgsAsWritten,
|
||||||
unsigned NumArgInfos,
|
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||||
ClassTemplatePartialSpecializationDecl *PrevDecl,
|
|
||||||
unsigned SequenceNumber);
|
|
||||||
|
|
||||||
ClassTemplatePartialSpecializationDecl()
|
ClassTemplatePartialSpecializationDecl()
|
||||||
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
|
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
|
||||||
TemplateParams(0), ArgsAsWritten(0),
|
TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) { }
|
||||||
NumArgsAsWritten(0), SequenceNumber(0),
|
|
||||||
InstantiatedFromMember(0, false) { }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ClassTemplatePartialSpecializationDecl *
|
static ClassTemplatePartialSpecializationDecl *
|
||||||
@ -1684,15 +1685,15 @@ class ClassTemplatePartialSpecializationDecl
|
|||||||
unsigned NumArgs,
|
unsigned NumArgs,
|
||||||
const TemplateArgumentListInfo &ArgInfos,
|
const TemplateArgumentListInfo &ArgInfos,
|
||||||
QualType CanonInjectedType,
|
QualType CanonInjectedType,
|
||||||
ClassTemplatePartialSpecializationDecl *PrevDecl,
|
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||||
unsigned SequenceNumber);
|
|
||||||
|
|
||||||
static ClassTemplatePartialSpecializationDecl *
|
static ClassTemplatePartialSpecializationDecl *
|
||||||
CreateDeserialized(ASTContext &C, unsigned ID);
|
CreateDeserialized(ASTContext &C, unsigned ID);
|
||||||
|
|
||||||
ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
|
ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
|
||||||
return cast<ClassTemplatePartialSpecializationDecl>(
|
return cast<ClassTemplatePartialSpecializationDecl>(
|
||||||
ClassTemplateSpecializationDecl::getMostRecentDecl());
|
static_cast<ClassTemplateSpecializationDecl *>(
|
||||||
|
this)->getMostRecentDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the list of template parameters
|
/// Get the list of template parameters
|
||||||
@ -1701,19 +1702,10 @@ class ClassTemplatePartialSpecializationDecl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the template arguments as written.
|
/// Get the template arguments as written.
|
||||||
TemplateArgumentLoc *getTemplateArgsAsWritten() const {
|
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
|
||||||
return ArgsAsWritten;
|
return ArgsAsWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of template arguments as written.
|
|
||||||
unsigned getNumTemplateArgsAsWritten() const {
|
|
||||||
return NumArgsAsWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Get the sequence number for this class template partial
|
|
||||||
/// specialization.
|
|
||||||
unsigned getSequenceNumber() const { return SequenceNumber; }
|
|
||||||
|
|
||||||
/// \brief Retrieve the member class template partial specialization from
|
/// \brief Retrieve the member class template partial specialization from
|
||||||
/// which this particular class template partial specialization was
|
/// which this particular class template partial specialization was
|
||||||
/// instantiated.
|
/// instantiated.
|
||||||
@ -1735,15 +1727,15 @@ class ClassTemplatePartialSpecializationDecl
|
|||||||
/// \c Outer<float>::Inner<U*>, this function would return
|
/// \c Outer<float>::Inner<U*>, this function would return
|
||||||
/// \c Outer<T>::Inner<U*>.
|
/// \c Outer<T>::Inner<U*>.
|
||||||
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
|
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
|
||||||
ClassTemplatePartialSpecializationDecl *First
|
ClassTemplatePartialSpecializationDecl *First =
|
||||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
return First->InstantiatedFromMember.getPointer();
|
return First->InstantiatedFromMember.getPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInstantiatedFromMember(
|
void setInstantiatedFromMember(
|
||||||
ClassTemplatePartialSpecializationDecl *PartialSpec) {
|
ClassTemplatePartialSpecializationDecl *PartialSpec) {
|
||||||
ClassTemplatePartialSpecializationDecl *First
|
ClassTemplatePartialSpecializationDecl *First =
|
||||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
First->InstantiatedFromMember.setPointer(PartialSpec);
|
First->InstantiatedFromMember.setPointer(PartialSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1764,15 +1756,15 @@ class ClassTemplatePartialSpecializationDecl
|
|||||||
/// struct X<int>::Inner<T*> { /* ... */ };
|
/// struct X<int>::Inner<T*> { /* ... */ };
|
||||||
/// \endcode
|
/// \endcode
|
||||||
bool isMemberSpecialization() {
|
bool isMemberSpecialization() {
|
||||||
ClassTemplatePartialSpecializationDecl *First
|
ClassTemplatePartialSpecializationDecl *First =
|
||||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
return First->InstantiatedFromMember.getInt();
|
return First->InstantiatedFromMember.getInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Note that this member template is a specialization.
|
/// \brief Note that this member template is a specialization.
|
||||||
void setMemberSpecialization() {
|
void setMemberSpecialization() {
|
||||||
ClassTemplatePartialSpecializationDecl *First
|
ClassTemplatePartialSpecializationDecl *First =
|
||||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
assert(First->InstantiatedFromMember.getPointer() &&
|
assert(First->InstantiatedFromMember.getPointer() &&
|
||||||
"Only member templates can be member template specializations");
|
"Only member templates can be member template specializations");
|
||||||
return First->InstantiatedFromMember.setInt(true);
|
return First->InstantiatedFromMember.setInt(true);
|
||||||
@ -1821,7 +1813,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
QualType InjectedClassNameType;
|
QualType InjectedClassNameType;
|
||||||
|
|
||||||
/// \brief If non-null, points to an array of specializations (including
|
/// \brief If non-null, points to an array of specializations (including
|
||||||
/// partial specializations) known ownly by their external declaration IDs.
|
/// partial specializations) known only by their external declaration IDs.
|
||||||
///
|
///
|
||||||
/// The first value in the array is the number of of specializations/
|
/// The first value in the array is the number of of specializations/
|
||||||
/// partial specializations that follow.
|
/// partial specializations that follow.
|
||||||
@ -1900,14 +1892,23 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
/// NULL if no such declaration exists.
|
/// NULL if no such declaration exists.
|
||||||
ClassTemplateDecl *getPreviousDecl() {
|
ClassTemplateDecl *getPreviousDecl() {
|
||||||
return cast_or_null<ClassTemplateDecl>(
|
return cast_or_null<ClassTemplateDecl>(
|
||||||
RedeclarableTemplateDecl::getPreviousDecl());
|
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the previous declaration of this class template, or
|
/// \brief Retrieve the previous declaration of this class template, or
|
||||||
/// NULL if no such declaration exists.
|
/// NULL if no such declaration exists.
|
||||||
const ClassTemplateDecl *getPreviousDecl() const {
|
const ClassTemplateDecl *getPreviousDecl() const {
|
||||||
return cast_or_null<ClassTemplateDecl>(
|
return cast_or_null<ClassTemplateDecl>(
|
||||||
RedeclarableTemplateDecl::getPreviousDecl());
|
static_cast<const RedeclarableTemplateDecl *>(
|
||||||
|
this)->getPreviousDecl());
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassTemplateDecl *getMostRecentDecl() {
|
||||||
|
return cast<ClassTemplateDecl>(
|
||||||
|
static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl());
|
||||||
|
}
|
||||||
|
const ClassTemplateDecl *getMostRecentDecl() const {
|
||||||
|
return const_cast<ClassTemplateDecl*>(this)->getMostRecentDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassTemplateDecl *getInstantiatedFromMemberTemplate() {
|
ClassTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||||
@ -1926,11 +1927,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D,
|
void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D,
|
||||||
void *InsertPos);
|
void *InsertPos);
|
||||||
|
|
||||||
/// \brief Return the next partial specialization sequence number.
|
|
||||||
unsigned getNextPartialSpecSequenceNumber() {
|
|
||||||
return getPartialSpecializations().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Retrieve the partial specializations as an ordered list.
|
/// \brief Retrieve the partial specializations as an ordered list.
|
||||||
void getPartialSpecializations(
|
void getPartialSpecializations(
|
||||||
SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
|
SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
|
||||||
@ -2139,14 +2135,15 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
|||||||
/// NULL if no such declaration exists.
|
/// NULL if no such declaration exists.
|
||||||
TypeAliasTemplateDecl *getPreviousDecl() {
|
TypeAliasTemplateDecl *getPreviousDecl() {
|
||||||
return cast_or_null<TypeAliasTemplateDecl>(
|
return cast_or_null<TypeAliasTemplateDecl>(
|
||||||
RedeclarableTemplateDecl::getPreviousDecl());
|
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the previous declaration of this function template, or
|
/// \brief Retrieve the previous declaration of this function template, or
|
||||||
/// NULL if no such declaration exists.
|
/// NULL if no such declaration exists.
|
||||||
const TypeAliasTemplateDecl *getPreviousDecl() const {
|
const TypeAliasTemplateDecl *getPreviousDecl() const {
|
||||||
return cast_or_null<TypeAliasTemplateDecl>(
|
return cast_or_null<TypeAliasTemplateDecl>(
|
||||||
RedeclarableTemplateDecl::getPreviousDecl());
|
static_cast<const RedeclarableTemplateDecl *>(
|
||||||
|
this)->getPreviousDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
|
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||||
@ -2239,6 +2236,578 @@ class ClassScopeFunctionSpecializationDecl : public Decl {
|
|||||||
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
|
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
|
||||||
: Function(FTD) { }
|
: Function(FTD) { }
|
||||||
|
|
||||||
|
/// \brief Represents a variable template specialization, which refers to
|
||||||
|
/// a variable template with a given set of template arguments.
|
||||||
|
///
|
||||||
|
/// Variable template specializations represent both explicit
|
||||||
|
/// specializations of variable templates, as in the example below, and
|
||||||
|
/// implicit instantiations of variable templates.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// template<typename T> constexpr T pi = T(3.1415926535897932385);
|
||||||
|
///
|
||||||
|
/// template<>
|
||||||
|
/// constexpr float pi<float>; // variable template specialization pi<float>
|
||||||
|
/// \endcode
|
||||||
|
class VarTemplateSpecializationDecl : public VarDecl,
|
||||||
|
public llvm::FoldingSetNode {
|
||||||
|
|
||||||
|
/// \brief Structure that stores information about a variable template
|
||||||
|
/// specialization that was instantiated from a variable template partial
|
||||||
|
/// specialization.
|
||||||
|
struct SpecializedPartialSpecialization {
|
||||||
|
/// \brief The variable template partial specialization from which this
|
||||||
|
/// variable template specialization was instantiated.
|
||||||
|
VarTemplatePartialSpecializationDecl *PartialSpecialization;
|
||||||
|
|
||||||
|
/// \brief The template argument list deduced for the variable template
|
||||||
|
/// partial specialization itself.
|
||||||
|
const TemplateArgumentList *TemplateArgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief The template that this specialization specializes.
|
||||||
|
llvm::PointerUnion<VarTemplateDecl *, SpecializedPartialSpecialization *>
|
||||||
|
SpecializedTemplate;
|
||||||
|
|
||||||
|
/// \brief Further info for explicit template specialization/instantiation.
|
||||||
|
struct ExplicitSpecializationInfo {
|
||||||
|
/// \brief The type-as-written.
|
||||||
|
TypeSourceInfo *TypeAsWritten;
|
||||||
|
/// \brief The location of the extern keyword.
|
||||||
|
SourceLocation ExternLoc;
|
||||||
|
/// \brief The location of the template keyword.
|
||||||
|
SourceLocation TemplateKeywordLoc;
|
||||||
|
|
||||||
|
ExplicitSpecializationInfo()
|
||||||
|
: TypeAsWritten(0), ExternLoc(), TemplateKeywordLoc() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Further info for explicit template specialization/instantiation.
|
||||||
|
/// Does not apply to implicit specializations.
|
||||||
|
ExplicitSpecializationInfo *ExplicitInfo;
|
||||||
|
|
||||||
|
/// \brief The template arguments used to describe this specialization.
|
||||||
|
const TemplateArgumentList *TemplateArgs;
|
||||||
|
TemplateArgumentListInfo TemplateArgsInfo;
|
||||||
|
|
||||||
|
/// \brief The point where this template was instantiated (if any).
|
||||||
|
SourceLocation PointOfInstantiation;
|
||||||
|
|
||||||
|
/// \brief The kind of specialization this declaration refers to.
|
||||||
|
/// Really a value of type TemplateSpecializationKind.
|
||||||
|
unsigned SpecializationKind : 3;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
VarTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC,
|
||||||
|
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||||
|
VarTemplateDecl *SpecializedTemplate,
|
||||||
|
QualType T, TypeSourceInfo *TInfo,
|
||||||
|
StorageClass S, const TemplateArgument *Args,
|
||||||
|
unsigned NumArgs);
|
||||||
|
|
||||||
|
explicit VarTemplateSpecializationDecl(Kind DK);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static VarTemplateSpecializationDecl *
|
||||||
|
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
|
||||||
|
SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
|
||||||
|
TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
|
||||||
|
unsigned NumArgs);
|
||||||
|
static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
|
||||||
|
unsigned ID);
|
||||||
|
|
||||||
|
virtual void getNameForDiagnostic(raw_ostream &OS,
|
||||||
|
const PrintingPolicy &Policy,
|
||||||
|
bool Qualified) const;
|
||||||
|
|
||||||
|
VarTemplateSpecializationDecl *getMostRecentDecl() {
|
||||||
|
VarDecl *Recent = static_cast<VarDecl *>(this)->getMostRecentDecl();
|
||||||
|
return cast<VarTemplateSpecializationDecl>(Recent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the template that this specialization specializes.
|
||||||
|
VarTemplateDecl *getSpecializedTemplate() const;
|
||||||
|
|
||||||
|
/// \brief Retrieve the template arguments of the variable template
|
||||||
|
/// specialization.
|
||||||
|
const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; }
|
||||||
|
|
||||||
|
// TODO: Always set this when creating the new specialization?
|
||||||
|
void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo);
|
||||||
|
|
||||||
|
const TemplateArgumentListInfo &getTemplateArgsInfo() const {
|
||||||
|
return TemplateArgsInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Determine the kind of specialization that this
|
||||||
|
/// declaration represents.
|
||||||
|
TemplateSpecializationKind getSpecializationKind() const {
|
||||||
|
return static_cast<TemplateSpecializationKind>(SpecializationKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isExplicitSpecialization() const {
|
||||||
|
return getSpecializationKind() == TSK_ExplicitSpecialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief True if this declaration is an explicit specialization,
|
||||||
|
/// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSpecializationKind(TemplateSpecializationKind TSK) {
|
||||||
|
SpecializationKind = TSK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Get the point of instantiation (if any), or null if none.
|
||||||
|
SourceLocation getPointOfInstantiation() const {
|
||||||
|
return PointOfInstantiation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPointOfInstantiation(SourceLocation Loc) {
|
||||||
|
assert(Loc.isValid() && "point of instantiation must be valid!");
|
||||||
|
PointOfInstantiation = Loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief If this variable template specialization is an instantiation of
|
||||||
|
/// a template (rather than an explicit specialization), return the
|
||||||
|
/// variable template or variable template partial specialization from which
|
||||||
|
/// it was instantiated.
|
||||||
|
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
|
||||||
|
getInstantiatedFrom() const {
|
||||||
|
if (getSpecializationKind() != TSK_ImplicitInstantiation &&
|
||||||
|
getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
|
||||||
|
getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
|
||||||
|
return llvm::PointerUnion<VarTemplateDecl *,
|
||||||
|
VarTemplatePartialSpecializationDecl *>();
|
||||||
|
|
||||||
|
if (SpecializedPartialSpecialization *PartialSpec =
|
||||||
|
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
|
||||||
|
return PartialSpec->PartialSpecialization;
|
||||||
|
|
||||||
|
return SpecializedTemplate.get<VarTemplateDecl *>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the variable template or variable template partial
|
||||||
|
/// specialization which was specialized by this.
|
||||||
|
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
|
||||||
|
getSpecializedTemplateOrPartial() const {
|
||||||
|
if (SpecializedPartialSpecialization *PartialSpec =
|
||||||
|
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
|
||||||
|
return PartialSpec->PartialSpecialization;
|
||||||
|
|
||||||
|
return SpecializedTemplate.get<VarTemplateDecl *>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the set of template arguments that should be used
|
||||||
|
/// to instantiate the initializer of the variable template or variable
|
||||||
|
/// template partial specialization from which this variable template
|
||||||
|
/// specialization was instantiated.
|
||||||
|
///
|
||||||
|
/// \returns For a variable template specialization instantiated from the
|
||||||
|
/// primary template, this function will return the same template arguments
|
||||||
|
/// as getTemplateArgs(). For a variable template specialization instantiated
|
||||||
|
/// from a variable template partial specialization, this function will the
|
||||||
|
/// return deduced template arguments for the variable template partial
|
||||||
|
/// specialization itself.
|
||||||
|
const TemplateArgumentList &getTemplateInstantiationArgs() const {
|
||||||
|
if (SpecializedPartialSpecialization *PartialSpec =
|
||||||
|
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
|
||||||
|
return *PartialSpec->TemplateArgs;
|
||||||
|
|
||||||
|
return getTemplateArgs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Note that this variable template specialization is actually an
|
||||||
|
/// instantiation of the given variable template partial specialization whose
|
||||||
|
/// template arguments have been deduced.
|
||||||
|
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
|
||||||
|
const TemplateArgumentList *TemplateArgs) {
|
||||||
|
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
|
||||||
|
"Already set to a variable template partial specialization!");
|
||||||
|
SpecializedPartialSpecialization *PS =
|
||||||
|
new (getASTContext()) SpecializedPartialSpecialization();
|
||||||
|
PS->PartialSpecialization = PartialSpec;
|
||||||
|
PS->TemplateArgs = TemplateArgs;
|
||||||
|
SpecializedTemplate = PS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Note that this variable template specialization is an instantiation
|
||||||
|
/// of the given variable template.
|
||||||
|
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
|
||||||
|
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
|
||||||
|
"Previously set to a variable template partial specialization!");
|
||||||
|
SpecializedTemplate = TemplDecl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Sets the type of this specialization as it was written by
|
||||||
|
/// the user.
|
||||||
|
void setTypeAsWritten(TypeSourceInfo *T) {
|
||||||
|
if (!ExplicitInfo)
|
||||||
|
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
|
||||||
|
ExplicitInfo->TypeAsWritten = T;
|
||||||
|
}
|
||||||
|
/// \brief Gets the type of this specialization as it was written by
|
||||||
|
/// the user, if it was so written.
|
||||||
|
TypeSourceInfo *getTypeAsWritten() const {
|
||||||
|
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Gets the location of the extern keyword, if present.
|
||||||
|
SourceLocation getExternLoc() const {
|
||||||
|
return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
|
||||||
|
}
|
||||||
|
/// \brief Sets the location of the extern keyword.
|
||||||
|
void setExternLoc(SourceLocation Loc) {
|
||||||
|
if (!ExplicitInfo)
|
||||||
|
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
|
||||||
|
ExplicitInfo->ExternLoc = Loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Sets the location of the template keyword.
|
||||||
|
void setTemplateKeywordLoc(SourceLocation Loc) {
|
||||||
|
if (!ExplicitInfo)
|
||||||
|
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
|
||||||
|
ExplicitInfo->TemplateKeywordLoc = Loc;
|
||||||
|
}
|
||||||
|
/// \brief Gets the location of the template keyword, if present.
|
||||||
|
SourceLocation getTemplateKeywordLoc() const {
|
||||||
|
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||||
|
Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||||
|
const TemplateArgument *TemplateArgs,
|
||||||
|
unsigned NumTemplateArgs, ASTContext &Context) {
|
||||||
|
ID.AddInteger(NumTemplateArgs);
|
||||||
|
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
|
||||||
|
TemplateArgs[Arg].Profile(ID, Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
|
static bool classofKind(Kind K) {
|
||||||
|
return K >= firstVarTemplateSpecialization &&
|
||||||
|
K <= lastVarTemplateSpecialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class ASTDeclReader;
|
||||||
|
friend class ASTDeclWriter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VarTemplatePartialSpecializationDecl
|
||||||
|
: public VarTemplateSpecializationDecl {
|
||||||
|
virtual void anchor();
|
||||||
|
|
||||||
|
/// \brief The list of template parameters
|
||||||
|
TemplateParameterList *TemplateParams;
|
||||||
|
|
||||||
|
/// \brief The source info for the template arguments as written.
|
||||||
|
/// FIXME: redundant with TypeAsWritten?
|
||||||
|
const ASTTemplateArgumentListInfo *ArgsAsWritten;
|
||||||
|
|
||||||
|
/// \brief The variable template partial specialization from which this
|
||||||
|
/// variable template partial specialization was instantiated.
|
||||||
|
///
|
||||||
|
/// The boolean value will be true to indicate that this variable template
|
||||||
|
/// partial specialization was specialized at this level.
|
||||||
|
llvm::PointerIntPair<VarTemplatePartialSpecializationDecl *, 1, bool>
|
||||||
|
InstantiatedFromMember;
|
||||||
|
|
||||||
|
VarTemplatePartialSpecializationDecl(
|
||||||
|
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
|
||||||
|
SourceLocation IdLoc, TemplateParameterList *Params,
|
||||||
|
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
|
||||||
|
StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
|
||||||
|
const ASTTemplateArgumentListInfo *ArgInfos);
|
||||||
|
|
||||||
|
VarTemplatePartialSpecializationDecl()
|
||||||
|
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization),
|
||||||
|
TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static VarTemplatePartialSpecializationDecl *
|
||||||
|
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
|
||||||
|
SourceLocation IdLoc, TemplateParameterList *Params,
|
||||||
|
VarTemplateDecl *SpecializedTemplate, QualType T,
|
||||||
|
TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
|
||||||
|
unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos);
|
||||||
|
|
||||||
|
static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C,
|
||||||
|
unsigned ID);
|
||||||
|
|
||||||
|
VarTemplatePartialSpecializationDecl *getMostRecentDecl() {
|
||||||
|
return cast<VarTemplatePartialSpecializationDecl>(
|
||||||
|
static_cast<VarTemplateSpecializationDecl *>(
|
||||||
|
this)->getMostRecentDecl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the list of template parameters
|
||||||
|
TemplateParameterList *getTemplateParameters() const {
|
||||||
|
return TemplateParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the template arguments as written.
|
||||||
|
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
|
||||||
|
return ArgsAsWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the member variable template partial specialization from
|
||||||
|
/// which this particular variable template partial specialization was
|
||||||
|
/// instantiated.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// template<typename T>
|
||||||
|
/// struct Outer {
|
||||||
|
/// template<typename U> U Inner;
|
||||||
|
/// template<typename U> U* Inner<U*> = (U*)(0); // #1
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// template int* Outer<float>::Inner<int*>;
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// In this example, the instantiation of \c Outer<float>::Inner<int*> will
|
||||||
|
/// end up instantiating the partial specialization
|
||||||
|
/// \c Outer<float>::Inner<U*>, which itself was instantiated from the
|
||||||
|
/// 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 =
|
||||||
|
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
|
return First->InstantiatedFromMember.getPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setInstantiatedFromMember(VarTemplatePartialSpecializationDecl *PartialSpec) {
|
||||||
|
VarTemplatePartialSpecializationDecl *First =
|
||||||
|
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
|
First->InstantiatedFromMember.setPointer(PartialSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Determines whether this variable template partial specialization
|
||||||
|
/// was a specialization of a member partial specialization.
|
||||||
|
///
|
||||||
|
/// In the following example, the member template partial specialization
|
||||||
|
/// \c X<int>::Inner<T*> is a member specialization.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// template<typename T>
|
||||||
|
/// struct X {
|
||||||
|
/// template<typename U> U Inner;
|
||||||
|
/// template<typename U> U* Inner<U*> = (U*)(0);
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// template<> template<typename T>
|
||||||
|
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
|
||||||
|
/// \endcode
|
||||||
|
bool isMemberSpecialization() {
|
||||||
|
VarTemplatePartialSpecializationDecl *First =
|
||||||
|
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
|
return First->InstantiatedFromMember.getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Note that this member template is a specialization.
|
||||||
|
void setMemberSpecialization() {
|
||||||
|
VarTemplatePartialSpecializationDecl *First =
|
||||||
|
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||||
|
assert(First->InstantiatedFromMember.getPointer() &&
|
||||||
|
"Only member templates can be member template specializations");
|
||||||
|
return First->InstantiatedFromMember.setInt(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
|
static bool classofKind(Kind K) {
|
||||||
|
return K == VarTemplatePartialSpecialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class ASTDeclReader;
|
||||||
|
friend class ASTDeclWriter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Declaration of a variable template.
|
||||||
|
class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||||
|
static void DeallocateCommon(void *Ptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// \brief Data that is common to all of the declarations of a given
|
||||||
|
/// variable template.
|
||||||
|
struct Common : CommonBase {
|
||||||
|
Common() : LazySpecializations() {}
|
||||||
|
|
||||||
|
/// \brief The variable template specializations for this variable
|
||||||
|
/// template, including explicit specializations and instantiations.
|
||||||
|
llvm::FoldingSetVector<VarTemplateSpecializationDecl> Specializations;
|
||||||
|
|
||||||
|
/// \brief The variable template partial specializations for this variable
|
||||||
|
/// template.
|
||||||
|
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>
|
||||||
|
PartialSpecializations;
|
||||||
|
|
||||||
|
/// \brief If non-null, points to an array of specializations (including
|
||||||
|
/// partial specializations) known ownly by their external declaration IDs.
|
||||||
|
///
|
||||||
|
/// The first value in the array is the number of of specializations/
|
||||||
|
/// partial specializations that follow.
|
||||||
|
uint32_t *LazySpecializations;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Load any lazily-loaded specializations from the external source.
|
||||||
|
void LoadLazySpecializations() const;
|
||||||
|
|
||||||
|
/// \brief Retrieve the set of specializations of this variable template.
|
||||||
|
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
|
||||||
|
getSpecializations() const;
|
||||||
|
|
||||||
|
/// \brief Retrieve the set of partial specializations of this class
|
||||||
|
/// template.
|
||||||
|
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
|
||||||
|
getPartialSpecializations();
|
||||||
|
|
||||||
|
VarTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||||
|
TemplateParameterList *Params, NamedDecl *Decl)
|
||||||
|
: RedeclarableTemplateDecl(VarTemplate, DC, L, Name, Params, Decl) {}
|
||||||
|
|
||||||
|
VarTemplateDecl(EmptyShell Empty)
|
||||||
|
: RedeclarableTemplateDecl(VarTemplate, 0, SourceLocation(),
|
||||||
|
DeclarationName(), 0, 0) {}
|
||||||
|
|
||||||
|
CommonBase *newCommon(ASTContext &C) const;
|
||||||
|
|
||||||
|
Common *getCommonPtr() const {
|
||||||
|
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// \brief Get the underlying variable declarations of the template.
|
||||||
|
VarDecl *getTemplatedDecl() const {
|
||||||
|
return static_cast<VarDecl *>(TemplatedDecl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns whether this template declaration defines the primary
|
||||||
|
/// variable pattern.
|
||||||
|
bool isThisDeclarationADefinition() const {
|
||||||
|
return getTemplatedDecl()->isThisDeclarationADefinition();
|
||||||
|
}
|
||||||
|
|
||||||
|
VarTemplateDecl *getDefinition();
|
||||||
|
|
||||||
|
/// \brief Create a variable template node.
|
||||||
|
static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
|
SourceLocation L, DeclarationName Name,
|
||||||
|
TemplateParameterList *Params, NamedDecl *Decl,
|
||||||
|
VarTemplateDecl *PrevDecl);
|
||||||
|
|
||||||
|
/// \brief Create an empty variable template node.
|
||||||
|
static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||||
|
|
||||||
|
/// \brief Return the specialization with the provided arguments if it exists,
|
||||||
|
/// otherwise return the insertion point.
|
||||||
|
VarTemplateSpecializationDecl *
|
||||||
|
findSpecialization(const TemplateArgument *Args, unsigned NumArgs,
|
||||||
|
void *&InsertPos);
|
||||||
|
|
||||||
|
/// \brief Insert the specified specialization knowing that it is not already
|
||||||
|
/// in. InsertPos must be obtained from findSpecialization.
|
||||||
|
void AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos);
|
||||||
|
|
||||||
|
VarTemplateDecl *getCanonicalDecl() {
|
||||||
|
return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
|
||||||
|
}
|
||||||
|
const VarTemplateDecl *getCanonicalDecl() const {
|
||||||
|
return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the previous declaration of this variable template, or
|
||||||
|
/// NULL if no such declaration exists.
|
||||||
|
VarTemplateDecl *getPreviousDecl() {
|
||||||
|
return cast_or_null<VarTemplateDecl>(
|
||||||
|
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the previous declaration of this variable template, or
|
||||||
|
/// NULL if no such declaration exists.
|
||||||
|
const VarTemplateDecl *getPreviousDecl() const {
|
||||||
|
return cast_or_null<VarTemplateDecl>(
|
||||||
|
static_cast<const RedeclarableTemplateDecl *>(
|
||||||
|
this)->getPreviousDecl());
|
||||||
|
}
|
||||||
|
|
||||||
|
VarTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||||
|
return cast_or_null<VarTemplateDecl>(
|
||||||
|
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Return the partial specialization with the provided arguments if it
|
||||||
|
/// exists, otherwise return the insertion point.
|
||||||
|
VarTemplatePartialSpecializationDecl *
|
||||||
|
findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs,
|
||||||
|
void *&InsertPos);
|
||||||
|
|
||||||
|
/// \brief Insert the specified partial specialization knowing that it is not
|
||||||
|
/// already in. InsertPos must be obtained from findPartialSpecialization.
|
||||||
|
void AddPartialSpecialization(VarTemplatePartialSpecializationDecl *D,
|
||||||
|
void *InsertPos);
|
||||||
|
|
||||||
|
/// \brief Retrieve the partial specializations as an ordered list.
|
||||||
|
void getPartialSpecializations(
|
||||||
|
SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS);
|
||||||
|
|
||||||
|
/// \brief Find a variable template partial specialization which was
|
||||||
|
/// instantiated
|
||||||
|
/// from the given member partial specialization.
|
||||||
|
///
|
||||||
|
/// \param D a member variable template partial specialization.
|
||||||
|
///
|
||||||
|
/// \returns the variable template partial specialization which was
|
||||||
|
/// instantiated
|
||||||
|
/// from the given member partial specialization, or NULL if no such partial
|
||||||
|
/// specialization exists.
|
||||||
|
VarTemplatePartialSpecializationDecl *findPartialSpecInstantiatedFromMember(
|
||||||
|
VarTemplatePartialSpecializationDecl *D);
|
||||||
|
|
||||||
|
typedef SpecIterator<VarTemplateSpecializationDecl> spec_iterator;
|
||||||
|
|
||||||
|
spec_iterator spec_begin() const {
|
||||||
|
return makeSpecIterator(getSpecializations(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
spec_iterator spec_end() const {
|
||||||
|
return makeSpecIterator(getSpecializations(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef SpecIterator<VarTemplatePartialSpecializationDecl>
|
||||||
|
partial_spec_iterator;
|
||||||
|
|
||||||
|
partial_spec_iterator partial_spec_begin() {
|
||||||
|
return makeSpecIterator(getPartialSpecializations(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial_spec_iterator partial_spec_end() {
|
||||||
|
return makeSpecIterator(getPartialSpecializations(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement isa/cast/dyncast support
|
||||||
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
|
static bool classofKind(Kind K) { return K == VarTemplate; }
|
||||||
|
|
||||||
|
friend class ASTDeclReader;
|
||||||
|
friend class ASTDeclWriter;
|
||||||
|
};
|
||||||
|
|
||||||
} /* end of namespace clang */
|
} /* end of namespace clang */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -182,11 +182,16 @@ class DeclarationName {
|
|||||||
|
|
||||||
// operator bool() - Evaluates true when this declaration name is
|
// operator bool() - Evaluates true when this declaration name is
|
||||||
// non-empty.
|
// non-empty.
|
||||||
operator bool() const {
|
LLVM_EXPLICIT operator bool() const {
|
||||||
return ((Ptr & PtrMask) != 0) ||
|
return ((Ptr & PtrMask) != 0) ||
|
||||||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
|
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Evaluates true when this declaration name is empty.
|
||||||
|
bool isEmpty() const {
|
||||||
|
return !*this;
|
||||||
|
}
|
||||||
|
|
||||||
/// Predicate functions for querying what type of name this is.
|
/// Predicate functions for querying what type of name this is.
|
||||||
bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
|
bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
|
||||||
bool isObjCZeroArgSelector() const {
|
bool isObjCZeroArgSelector() const {
|
||||||
@ -210,9 +215,6 @@ class DeclarationName {
|
|||||||
/// getNameAsString - Retrieve the human-readable string for this name.
|
/// getNameAsString - Retrieve the human-readable string for this name.
|
||||||
std::string getAsString() const;
|
std::string getAsString() const;
|
||||||
|
|
||||||
/// printName - Print the human-readable name to a stream.
|
|
||||||
void printName(raw_ostream &OS) const;
|
|
||||||
|
|
||||||
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
||||||
/// this declaration name, or NULL if this declaration name isn't a
|
/// this declaration name, or NULL if this declaration name isn't a
|
||||||
/// simple identifier.
|
/// simple identifier.
|
||||||
@ -302,6 +304,8 @@ class DeclarationName {
|
|||||||
void dump() const;
|
void dump() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
raw_ostream &operator<<(raw_ostream &OS, DeclarationName N);
|
||||||
|
|
||||||
/// Ordering on two declaration names. If both names are identifiers,
|
/// Ordering on two declaration names. If both names are identifiers,
|
||||||
/// this provides a lexicographical ordering.
|
/// this provides a lexicographical ordering.
|
||||||
inline bool operator<(DeclarationName LHS, DeclarationName RHS) {
|
inline bool operator<(DeclarationName LHS, DeclarationName RHS) {
|
||||||
|
@ -53,7 +53,7 @@ class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
|||||||
if (E->getCond()->isValueDependent())
|
if (E->getCond()->isValueDependent())
|
||||||
return;
|
return;
|
||||||
// Only the selected subexpression matters; the other one is not evaluated.
|
// Only the selected subexpression matters; the other one is not evaluated.
|
||||||
return this->Visit(E->getChosenSubExpr(Context));
|
return this->Visit(E->getChosenSubExpr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
|
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
|
||||||
|
@ -277,7 +277,6 @@ class Expr : public Stmt {
|
|||||||
MLV_IncompleteType,
|
MLV_IncompleteType,
|
||||||
MLV_ConstQualified,
|
MLV_ConstQualified,
|
||||||
MLV_ArrayType,
|
MLV_ArrayType,
|
||||||
MLV_ReadonlyProperty,
|
|
||||||
MLV_NoSetterProperty,
|
MLV_NoSetterProperty,
|
||||||
MLV_MemberFunction,
|
MLV_MemberFunction,
|
||||||
MLV_SubObjCPropertySetting,
|
MLV_SubObjCPropertySetting,
|
||||||
@ -483,21 +482,22 @@ class Expr : public Stmt {
|
|||||||
///
|
///
|
||||||
/// Note: This does not perform the implicit conversions required by C++11
|
/// Note: This does not perform the implicit conversions required by C++11
|
||||||
/// [expr.const]p5.
|
/// [expr.const]p5.
|
||||||
bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
|
bool isIntegerConstantExpr(llvm::APSInt &Result, const ASTContext &Ctx,
|
||||||
SourceLocation *Loc = 0,
|
SourceLocation *Loc = 0,
|
||||||
bool isEvaluated = true) const;
|
bool isEvaluated = true) const;
|
||||||
bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const;
|
bool isIntegerConstantExpr(const ASTContext &Ctx,
|
||||||
|
SourceLocation *Loc = 0) const;
|
||||||
|
|
||||||
/// isCXX98IntegralConstantExpr - Return true if this expression is an
|
/// isCXX98IntegralConstantExpr - Return true if this expression is an
|
||||||
/// integral constant expression in C++98. Can only be used in C++.
|
/// integral constant expression in C++98. Can only be used in C++.
|
||||||
bool isCXX98IntegralConstantExpr(ASTContext &Ctx) const;
|
bool isCXX98IntegralConstantExpr(const ASTContext &Ctx) const;
|
||||||
|
|
||||||
/// isCXX11ConstantExpr - Return true if this expression is a constant
|
/// isCXX11ConstantExpr - Return true if this expression is a constant
|
||||||
/// expression in C++11. Can only be used in C++.
|
/// expression in C++11. Can only be used in C++.
|
||||||
///
|
///
|
||||||
/// Note: This does not perform the implicit conversions required by C++11
|
/// Note: This does not perform the implicit conversions required by C++11
|
||||||
/// [expr.const]p5.
|
/// [expr.const]p5.
|
||||||
bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0,
|
bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = 0,
|
||||||
SourceLocation *Loc = 0) const;
|
SourceLocation *Loc = 0) const;
|
||||||
|
|
||||||
/// isPotentialConstantExpr - Return true if this function's definition
|
/// isPotentialConstantExpr - Return true if this function's definition
|
||||||
@ -579,15 +579,14 @@ class Expr : public Stmt {
|
|||||||
/// \brief Determine whether this expression involves a call to any function
|
/// \brief Determine whether this expression involves a call to any function
|
||||||
/// that is not trivial.
|
/// that is not trivial.
|
||||||
bool hasNonTrivialCall(ASTContext &Ctx);
|
bool hasNonTrivialCall(ASTContext &Ctx);
|
||||||
|
|
||||||
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
|
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
|
||||||
/// integer. This must be called on an expression that constant folds to an
|
/// integer. This must be called on an expression that constant folds to an
|
||||||
/// integer.
|
/// integer.
|
||||||
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
|
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
|
||||||
SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
|
SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
|
||||||
|
|
||||||
void EvaluateForOverflow(const ASTContext &Ctx,
|
void EvaluateForOverflow(const ASTContext &Ctx) const;
|
||||||
SmallVectorImpl<PartialDiagnosticAt> *Diag) const;
|
|
||||||
|
|
||||||
/// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
|
/// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
|
||||||
/// lvalue with link time known address, with no side-effects.
|
/// lvalue with link time known address, with no side-effects.
|
||||||
@ -760,10 +759,10 @@ class Expr : public Stmt {
|
|||||||
|
|
||||||
/// Walk outwards from an expression we want to bind a reference to and
|
/// Walk outwards from an expression we want to bind a reference to and
|
||||||
/// find the expression whose lifetime needs to be extended. Record
|
/// find the expression whose lifetime needs to be extended. Record
|
||||||
/// the adjustments needed along the path.
|
/// the LHSs of comma expressions and adjustments needed along the path.
|
||||||
const Expr *
|
const Expr *skipRValueSubobjectAdjustments(
|
||||||
skipRValueSubobjectAdjustments(
|
SmallVectorImpl<const Expr *> &CommaLHS,
|
||||||
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
|
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
|
||||||
|
|
||||||
/// Skip irrelevant expressions to find what should be materialize for
|
/// Skip irrelevant expressions to find what should be materialize for
|
||||||
/// binding with a reference.
|
/// binding with a reference.
|
||||||
@ -893,7 +892,7 @@ class DeclRefExpr : public Expr {
|
|||||||
bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
|
bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
|
||||||
|
|
||||||
/// \brief Helper to retrieve the optional NamedDecl through which this
|
/// \brief Helper to retrieve the optional NamedDecl through which this
|
||||||
/// reference occured.
|
/// reference occurred.
|
||||||
NamedDecl *&getInternalFoundDecl() {
|
NamedDecl *&getInternalFoundDecl() {
|
||||||
assert(hasFoundDecl());
|
assert(hasFoundDecl());
|
||||||
if (hasQualifier())
|
if (hasQualifier())
|
||||||
@ -902,12 +901,12 @@ class DeclRefExpr : public Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Helper to retrieve the optional NamedDecl through which this
|
/// \brief Helper to retrieve the optional NamedDecl through which this
|
||||||
/// reference occured.
|
/// reference occurred.
|
||||||
NamedDecl *getInternalFoundDecl() const {
|
NamedDecl *getInternalFoundDecl() const {
|
||||||
return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
|
return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclRefExpr(ASTContext &Ctx,
|
DeclRefExpr(const ASTContext &Ctx,
|
||||||
NestedNameSpecifierLoc QualifierLoc,
|
NestedNameSpecifierLoc QualifierLoc,
|
||||||
SourceLocation TemplateKWLoc,
|
SourceLocation TemplateKWLoc,
|
||||||
ValueDecl *D, bool refersToEnclosingLocal,
|
ValueDecl *D, bool refersToEnclosingLocal,
|
||||||
@ -922,7 +921,7 @@ class DeclRefExpr : public Expr {
|
|||||||
|
|
||||||
/// \brief Computes the type- and value-dependence flags for this
|
/// \brief Computes the type- and value-dependence flags for this
|
||||||
/// declaration reference expression.
|
/// declaration reference expression.
|
||||||
void computeDependence(ASTContext &C);
|
void computeDependence(const ASTContext &C);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T,
|
DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T,
|
||||||
@ -938,7 +937,7 @@ class DeclRefExpr : public Expr {
|
|||||||
computeDependence(D->getASTContext());
|
computeDependence(D->getASTContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
static DeclRefExpr *Create(ASTContext &Context,
|
static DeclRefExpr *Create(const ASTContext &Context,
|
||||||
NestedNameSpecifierLoc QualifierLoc,
|
NestedNameSpecifierLoc QualifierLoc,
|
||||||
SourceLocation TemplateKWLoc,
|
SourceLocation TemplateKWLoc,
|
||||||
ValueDecl *D,
|
ValueDecl *D,
|
||||||
@ -948,7 +947,7 @@ class DeclRefExpr : public Expr {
|
|||||||
NamedDecl *FoundD = 0,
|
NamedDecl *FoundD = 0,
|
||||||
const TemplateArgumentListInfo *TemplateArgs = 0);
|
const TemplateArgumentListInfo *TemplateArgs = 0);
|
||||||
|
|
||||||
static DeclRefExpr *Create(ASTContext &Context,
|
static DeclRefExpr *Create(const ASTContext &Context,
|
||||||
NestedNameSpecifierLoc QualifierLoc,
|
NestedNameSpecifierLoc QualifierLoc,
|
||||||
SourceLocation TemplateKWLoc,
|
SourceLocation TemplateKWLoc,
|
||||||
ValueDecl *D,
|
ValueDecl *D,
|
||||||
@ -959,7 +958,7 @@ class DeclRefExpr : public Expr {
|
|||||||
const TemplateArgumentListInfo *TemplateArgs = 0);
|
const TemplateArgumentListInfo *TemplateArgs = 0);
|
||||||
|
|
||||||
/// \brief Construct an empty declaration reference expression.
|
/// \brief Construct an empty declaration reference expression.
|
||||||
static DeclRefExpr *CreateEmpty(ASTContext &Context,
|
static DeclRefExpr *CreateEmpty(const ASTContext &Context,
|
||||||
bool HasQualifier,
|
bool HasQualifier,
|
||||||
bool HasFoundDecl,
|
bool HasFoundDecl,
|
||||||
bool HasTemplateKWAndArgsInfo,
|
bool HasTemplateKWAndArgsInfo,
|
||||||
@ -1000,7 +999,7 @@ class DeclRefExpr : public Expr {
|
|||||||
return getInternalQualifierLoc();
|
return getInternalQualifierLoc();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Get the NamedDecl through which this reference occured.
|
/// \brief Get the NamedDecl through which this reference occurred.
|
||||||
///
|
///
|
||||||
/// This Decl may be different from the ValueDecl actually referred to in the
|
/// This Decl may be different from the ValueDecl actually referred to in the
|
||||||
/// presence of using declarations, etc. It always returns non-NULL, and may
|
/// presence of using declarations, etc. It always returns non-NULL, and may
|
||||||
@ -1151,6 +1150,7 @@ class PredefinedExpr : public Expr {
|
|||||||
Func,
|
Func,
|
||||||
Function,
|
Function,
|
||||||
LFunction, // Same as Function, but as wide string.
|
LFunction, // Same as Function, but as wide string.
|
||||||
|
FuncDName,
|
||||||
PrettyFunction,
|
PrettyFunction,
|
||||||
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
|
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
|
||||||
/// 'virtual' keyword is omitted for virtual member functions.
|
/// 'virtual' keyword is omitted for virtual member functions.
|
||||||
@ -1221,13 +1221,15 @@ class APNumericStorage {
|
|||||||
else
|
else
|
||||||
return llvm::APInt(BitWidth, VAL);
|
return llvm::APInt(BitWidth, VAL);
|
||||||
}
|
}
|
||||||
void setIntValue(ASTContext &C, const llvm::APInt &Val);
|
void setIntValue(const ASTContext &C, const llvm::APInt &Val);
|
||||||
};
|
};
|
||||||
|
|
||||||
class APIntStorage : private APNumericStorage {
|
class APIntStorage : private APNumericStorage {
|
||||||
public:
|
public:
|
||||||
llvm::APInt getValue() const { return getIntValue(); }
|
llvm::APInt getValue() const { return getIntValue(); }
|
||||||
void setValue(ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); }
|
void setValue(const ASTContext &C, const llvm::APInt &Val) {
|
||||||
|
setIntValue(C, Val);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class APFloatStorage : private APNumericStorage {
|
class APFloatStorage : private APNumericStorage {
|
||||||
@ -1235,7 +1237,7 @@ class APFloatStorage : private APNumericStorage {
|
|||||||
llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const {
|
llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const {
|
||||||
return llvm::APFloat(Semantics, getIntValue());
|
return llvm::APFloat(Semantics, getIntValue());
|
||||||
}
|
}
|
||||||
void setValue(ASTContext &C, const llvm::APFloat &Val) {
|
void setValue(const ASTContext &C, const llvm::APFloat &Val) {
|
||||||
setIntValue(C, Val.bitcastToAPInt());
|
setIntValue(C, Val.bitcastToAPInt());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1250,17 +1252,17 @@ class IntegerLiteral : public Expr, public APIntStorage {
|
|||||||
public:
|
public:
|
||||||
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
||||||
// or UnsignedLongLongTy
|
// or UnsignedLongLongTy
|
||||||
IntegerLiteral(ASTContext &C, const llvm::APInt &V, QualType type,
|
IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type,
|
||||||
SourceLocation l);
|
SourceLocation l);
|
||||||
|
|
||||||
/// \brief Returns a new integer literal with value 'V' and type 'type'.
|
/// \brief Returns a new integer literal with value 'V' and type 'type'.
|
||||||
/// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy,
|
/// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy,
|
||||||
/// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V
|
/// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V
|
||||||
/// \param V - the value that the returned integer literal contains.
|
/// \param V - the value that the returned integer literal contains.
|
||||||
static IntegerLiteral *Create(ASTContext &C, const llvm::APInt &V,
|
static IntegerLiteral *Create(const ASTContext &C, const llvm::APInt &V,
|
||||||
QualType type, SourceLocation l);
|
QualType type, SourceLocation l);
|
||||||
/// \brief Returns a new empty integer literal.
|
/// \brief Returns a new empty integer literal.
|
||||||
static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty);
|
static IntegerLiteral *Create(const ASTContext &C, EmptyShell Empty);
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
|
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
|
||||||
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
|
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
|
||||||
@ -1328,21 +1330,21 @@ class CharacterLiteral : public Expr {
|
|||||||
class FloatingLiteral : public Expr, private APFloatStorage {
|
class FloatingLiteral : public Expr, private APFloatStorage {
|
||||||
SourceLocation Loc;
|
SourceLocation Loc;
|
||||||
|
|
||||||
FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact,
|
FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact,
|
||||||
QualType Type, SourceLocation L);
|
QualType Type, SourceLocation L);
|
||||||
|
|
||||||
/// \brief Construct an empty floating-point literal.
|
/// \brief Construct an empty floating-point literal.
|
||||||
explicit FloatingLiteral(ASTContext &C, EmptyShell Empty);
|
explicit FloatingLiteral(const ASTContext &C, EmptyShell Empty);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FloatingLiteral *Create(ASTContext &C, const llvm::APFloat &V,
|
static FloatingLiteral *Create(const ASTContext &C, const llvm::APFloat &V,
|
||||||
bool isexact, QualType Type, SourceLocation L);
|
bool isexact, QualType Type, SourceLocation L);
|
||||||
static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty);
|
static FloatingLiteral *Create(const ASTContext &C, EmptyShell Empty);
|
||||||
|
|
||||||
llvm::APFloat getValue() const {
|
llvm::APFloat getValue() const {
|
||||||
return APFloatStorage::getValue(getSemantics());
|
return APFloatStorage::getValue(getSemantics());
|
||||||
}
|
}
|
||||||
void setValue(ASTContext &C, const llvm::APFloat &Val) {
|
void setValue(const ASTContext &C, const llvm::APFloat &Val) {
|
||||||
assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics");
|
assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics");
|
||||||
APFloatStorage::setValue(C, Val);
|
APFloatStorage::setValue(C, Val);
|
||||||
}
|
}
|
||||||
@ -1420,7 +1422,7 @@ class ImaginaryLiteral : public Expr {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// StringLiteral - This represents a string literal expression, e.g. "foo"
|
/// StringLiteral - This represents a string literal expression, e.g. "foo"
|
||||||
/// or L"bar" (wide strings). The actual string is returned by getStrData()
|
/// or L"bar" (wide strings). The actual string is returned by getBytes()
|
||||||
/// is NOT null-terminated, and the length of the string is determined by
|
/// is NOT null-terminated, and the length of the string is determined by
|
||||||
/// calling getByteLength(). The C type for a string is always a
|
/// calling getByteLength(). The C type for a string is always a
|
||||||
/// ConstantArrayType. In C++, the char type is const qualified, in C it is
|
/// ConstantArrayType. In C++, the char type is const qualified, in C it is
|
||||||
@ -1469,19 +1471,19 @@ class StringLiteral : public Expr {
|
|||||||
public:
|
public:
|
||||||
/// This is the "fully general" constructor that allows representation of
|
/// This is the "fully general" constructor that allows representation of
|
||||||
/// strings formed from multiple concatenated tokens.
|
/// strings formed from multiple concatenated tokens.
|
||||||
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
|
static StringLiteral *Create(const ASTContext &C, StringRef Str,
|
||||||
bool Pascal, QualType Ty,
|
StringKind Kind, bool Pascal, QualType Ty,
|
||||||
const SourceLocation *Loc, unsigned NumStrs);
|
const SourceLocation *Loc, unsigned NumStrs);
|
||||||
|
|
||||||
/// Simple constructor for string literals made from one token.
|
/// Simple constructor for string literals made from one token.
|
||||||
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
|
static StringLiteral *Create(const ASTContext &C, StringRef Str,
|
||||||
bool Pascal, QualType Ty,
|
StringKind Kind, bool Pascal, QualType Ty,
|
||||||
SourceLocation Loc) {
|
SourceLocation Loc) {
|
||||||
return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
|
return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Construct an empty string literal.
|
/// \brief Construct an empty string literal.
|
||||||
static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
|
static StringLiteral *CreateEmpty(const ASTContext &C, unsigned NumStrs);
|
||||||
|
|
||||||
StringRef getString() const {
|
StringRef getString() const {
|
||||||
assert(CharByteWidth==1
|
assert(CharByteWidth==1
|
||||||
@ -1520,7 +1522,7 @@ class StringLiteral : public Expr {
|
|||||||
unsigned getCharByteWidth() const { return CharByteWidth; }
|
unsigned getCharByteWidth() const { return CharByteWidth; }
|
||||||
|
|
||||||
/// \brief Sets the string data to the given string data.
|
/// \brief Sets the string data to the given string data.
|
||||||
void setString(ASTContext &C, StringRef Str,
|
void setString(const ASTContext &C, StringRef Str,
|
||||||
StringKind Kind, bool IsPascal);
|
StringKind Kind, bool IsPascal);
|
||||||
|
|
||||||
StringKind getKind() const { return static_cast<StringKind>(Kind); }
|
StringKind getKind() const { return static_cast<StringKind>(Kind); }
|
||||||
@ -1853,7 +1855,7 @@ class OffsetOfExpr : public Expr {
|
|||||||
// Number of sub-expressions (i.e. array subscript expressions).
|
// Number of sub-expressions (i.e. array subscript expressions).
|
||||||
unsigned NumExprs;
|
unsigned NumExprs;
|
||||||
|
|
||||||
OffsetOfExpr(ASTContext &C, QualType type,
|
OffsetOfExpr(const ASTContext &C, QualType type,
|
||||||
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
||||||
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
|
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
|
||||||
SourceLocation RParenLoc);
|
SourceLocation RParenLoc);
|
||||||
@ -1864,12 +1866,12 @@ class OffsetOfExpr : public Expr {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static OffsetOfExpr *Create(ASTContext &C, QualType type,
|
static OffsetOfExpr *Create(const ASTContext &C, QualType type,
|
||||||
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
||||||
ArrayRef<OffsetOfNode> comps,
|
ArrayRef<OffsetOfNode> comps,
|
||||||
ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
|
ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
|
||||||
|
|
||||||
static OffsetOfExpr *CreateEmpty(ASTContext &C,
|
static OffsetOfExpr *CreateEmpty(const ASTContext &C,
|
||||||
unsigned NumComps, unsigned NumExprs);
|
unsigned NumComps, unsigned NumExprs);
|
||||||
|
|
||||||
/// getOperatorLoc - Return the location of the operator.
|
/// getOperatorLoc - Return the location of the operator.
|
||||||
@ -2133,10 +2135,11 @@ class CallExpr : public Expr {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// These versions of the constructor are for derived classes.
|
// These versions of the constructor are for derived classes.
|
||||||
CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
|
CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
|
||||||
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
|
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
|
||||||
SourceLocation rparenloc);
|
SourceLocation rparenloc);
|
||||||
CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty);
|
CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
|
||||||
|
EmptyShell Empty);
|
||||||
|
|
||||||
Stmt *getPreArg(unsigned i) {
|
Stmt *getPreArg(unsigned i) {
|
||||||
assert(i < getNumPreArgs() && "Prearg access out of range!");
|
assert(i < getNumPreArgs() && "Prearg access out of range!");
|
||||||
@ -2154,11 +2157,11 @@ class CallExpr : public Expr {
|
|||||||
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
|
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
|
CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
|
||||||
ExprValueKind VK, SourceLocation rparenloc);
|
ExprValueKind VK, SourceLocation rparenloc);
|
||||||
|
|
||||||
/// \brief Build an empty call expression.
|
/// \brief Build an empty call expression.
|
||||||
CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty);
|
CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty);
|
||||||
|
|
||||||
const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); }
|
const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); }
|
||||||
Expr *getCallee() { return cast<Expr>(SubExprs[FN]); }
|
Expr *getCallee() { return cast<Expr>(SubExprs[FN]); }
|
||||||
@ -2206,7 +2209,7 @@ class CallExpr : public Expr {
|
|||||||
/// setNumArgs - This changes the number of arguments present in this call.
|
/// setNumArgs - This changes the number of arguments present in this call.
|
||||||
/// Any orphaned expressions are deleted by this, and any new operands are set
|
/// Any orphaned expressions are deleted by this, and any new operands are set
|
||||||
/// to null.
|
/// to null.
|
||||||
void setNumArgs(ASTContext& C, unsigned NumArgs);
|
void setNumArgs(const ASTContext& C, unsigned NumArgs);
|
||||||
|
|
||||||
typedef ExprIterator arg_iterator;
|
typedef ExprIterator arg_iterator;
|
||||||
typedef ConstExprIterator const_arg_iterator;
|
typedef ConstExprIterator const_arg_iterator;
|
||||||
@ -2360,7 +2363,7 @@ class MemberExpr : public Expr {
|
|||||||
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
|
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
|
||||||
HadMultipleCandidates(false) {}
|
HadMultipleCandidates(false) {}
|
||||||
|
|
||||||
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
|
static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow,
|
||||||
NestedNameSpecifierLoc QualifierLoc,
|
NestedNameSpecifierLoc QualifierLoc,
|
||||||
SourceLocation TemplateKWLoc,
|
SourceLocation TemplateKWLoc,
|
||||||
ValueDecl *memberdecl, DeclAccessPair founddecl,
|
ValueDecl *memberdecl, DeclAccessPair founddecl,
|
||||||
@ -2747,12 +2750,13 @@ class ImplicitCastExpr : public CastExpr {
|
|||||||
: CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) {
|
: CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ImplicitCastExpr *Create(ASTContext &Context, QualType T,
|
static ImplicitCastExpr *Create(const ASTContext &Context, QualType T,
|
||||||
CastKind Kind, Expr *Operand,
|
CastKind Kind, Expr *Operand,
|
||||||
const CXXCastPath *BasePath,
|
const CXXCastPath *BasePath,
|
||||||
ExprValueKind Cat);
|
ExprValueKind Cat);
|
||||||
|
|
||||||
static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
|
static ImplicitCastExpr *CreateEmpty(const ASTContext &Context,
|
||||||
|
unsigned PathSize);
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY {
|
SourceLocation getLocStart() const LLVM_READONLY {
|
||||||
return getSubExpr()->getLocStart();
|
return getSubExpr()->getLocStart();
|
||||||
@ -2838,13 +2842,14 @@ class CStyleCastExpr : public ExplicitCastExpr {
|
|||||||
: ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { }
|
: ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CStyleCastExpr *Create(ASTContext &Context, QualType T,
|
static CStyleCastExpr *Create(const ASTContext &Context, QualType T,
|
||||||
ExprValueKind VK, CastKind K,
|
ExprValueKind VK, CastKind K,
|
||||||
Expr *Op, const CXXCastPath *BasePath,
|
Expr *Op, const CXXCastPath *BasePath,
|
||||||
TypeSourceInfo *WrittenTy, SourceLocation L,
|
TypeSourceInfo *WrittenTy, SourceLocation L,
|
||||||
SourceLocation R);
|
SourceLocation R);
|
||||||
|
|
||||||
static CStyleCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
|
static CStyleCastExpr *CreateEmpty(const ASTContext &Context,
|
||||||
|
unsigned PathSize);
|
||||||
|
|
||||||
SourceLocation getLParenLoc() const { return LPLoc; }
|
SourceLocation getLParenLoc() const { return LPLoc; }
|
||||||
void setLParenLoc(SourceLocation L) { LPLoc = L; }
|
void setLParenLoc(SourceLocation L) { LPLoc = L; }
|
||||||
@ -3412,7 +3417,7 @@ class ShuffleVectorExpr : public Expr {
|
|||||||
unsigned NumExprs;
|
unsigned NumExprs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type,
|
ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type,
|
||||||
SourceLocation BLoc, SourceLocation RP);
|
SourceLocation BLoc, SourceLocation RP);
|
||||||
|
|
||||||
/// \brief Build an empty vector-shuffle expression.
|
/// \brief Build an empty vector-shuffle expression.
|
||||||
@ -3450,11 +3455,11 @@ class ShuffleVectorExpr : public Expr {
|
|||||||
return cast<Expr>(SubExprs[Index]);
|
return cast<Expr>(SubExprs[Index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs);
|
void setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs);
|
||||||
|
|
||||||
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) const {
|
llvm::APSInt getShuffleMaskIdx(const ASTContext &Ctx, unsigned N) const {
|
||||||
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
|
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
|
||||||
return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
|
return getExpr(N+2)->EvaluateKnownConstInt(Ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterators
|
// Iterators
|
||||||
@ -3463,6 +3468,60 @@ class ShuffleVectorExpr : public Expr {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
|
||||||
|
/// This AST node provides support for converting a vector type to another
|
||||||
|
/// vector type of the same arity.
|
||||||
|
class ConvertVectorExpr : public Expr {
|
||||||
|
private:
|
||||||
|
Stmt *SrcExpr;
|
||||||
|
TypeSourceInfo *TInfo;
|
||||||
|
SourceLocation BuiltinLoc, RParenLoc;
|
||||||
|
|
||||||
|
friend class ASTReader;
|
||||||
|
friend class ASTStmtReader;
|
||||||
|
explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConvertVectorExpr(Expr* SrcExpr, TypeSourceInfo *TI, QualType DstType,
|
||||||
|
ExprValueKind VK, ExprObjectKind OK,
|
||||||
|
SourceLocation BuiltinLoc, SourceLocation RParenLoc)
|
||||||
|
: Expr(ConvertVectorExprClass, DstType, VK, OK,
|
||||||
|
DstType->isDependentType(),
|
||||||
|
DstType->isDependentType() || SrcExpr->isValueDependent(),
|
||||||
|
(DstType->isInstantiationDependentType() ||
|
||||||
|
SrcExpr->isInstantiationDependent()),
|
||||||
|
(DstType->containsUnexpandedParameterPack() ||
|
||||||
|
SrcExpr->containsUnexpandedParameterPack())),
|
||||||
|
SrcExpr(SrcExpr), TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {}
|
||||||
|
|
||||||
|
/// getSrcExpr - Return the Expr to be converted.
|
||||||
|
Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); }
|
||||||
|
|
||||||
|
/// getTypeSourceInfo - Return the destination type.
|
||||||
|
TypeSourceInfo *getTypeSourceInfo() const {
|
||||||
|
return TInfo;
|
||||||
|
}
|
||||||
|
void setTypeSourceInfo(TypeSourceInfo *ti) {
|
||||||
|
TInfo = ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// getBuiltinLoc - Return the location of the __builtin_convertvector token.
|
||||||
|
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
|
||||||
|
|
||||||
|
/// getRParenLoc - Return the location of final right parenthesis.
|
||||||
|
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||||
|
|
||||||
|
SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
|
||||||
|
SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
|
||||||
|
|
||||||
|
static bool classof(const Stmt *T) {
|
||||||
|
return T->getStmtClass() == ConvertVectorExprClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterators
|
||||||
|
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
|
||||||
|
};
|
||||||
|
|
||||||
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
|
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
|
||||||
/// This AST node is similar to the conditional operator (?:) in C, with
|
/// This AST node is similar to the conditional operator (?:) in C, with
|
||||||
/// the following exceptions:
|
/// the following exceptions:
|
||||||
@ -3476,10 +3535,12 @@ class ChooseExpr : public Expr {
|
|||||||
enum { COND, LHS, RHS, END_EXPR };
|
enum { COND, LHS, RHS, END_EXPR };
|
||||||
Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
|
Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
|
||||||
SourceLocation BuiltinLoc, RParenLoc;
|
SourceLocation BuiltinLoc, RParenLoc;
|
||||||
|
bool CondIsTrue;
|
||||||
public:
|
public:
|
||||||
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs,
|
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs,
|
||||||
QualType t, ExprValueKind VK, ExprObjectKind OK,
|
QualType t, ExprValueKind VK, ExprObjectKind OK,
|
||||||
SourceLocation RP, bool TypeDependent, bool ValueDependent)
|
SourceLocation RP, bool condIsTrue,
|
||||||
|
bool TypeDependent, bool ValueDependent)
|
||||||
: Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent,
|
: Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent,
|
||||||
(cond->isInstantiationDependent() ||
|
(cond->isInstantiationDependent() ||
|
||||||
lhs->isInstantiationDependent() ||
|
lhs->isInstantiationDependent() ||
|
||||||
@ -3487,7 +3548,7 @@ class ChooseExpr : public Expr {
|
|||||||
(cond->containsUnexpandedParameterPack() ||
|
(cond->containsUnexpandedParameterPack() ||
|
||||||
lhs->containsUnexpandedParameterPack() ||
|
lhs->containsUnexpandedParameterPack() ||
|
||||||
rhs->containsUnexpandedParameterPack())),
|
rhs->containsUnexpandedParameterPack())),
|
||||||
BuiltinLoc(BLoc), RParenLoc(RP) {
|
BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) {
|
||||||
SubExprs[COND] = cond;
|
SubExprs[COND] = cond;
|
||||||
SubExprs[LHS] = lhs;
|
SubExprs[LHS] = lhs;
|
||||||
SubExprs[RHS] = rhs;
|
SubExprs[RHS] = rhs;
|
||||||
@ -3498,12 +3559,21 @@ class ChooseExpr : public Expr {
|
|||||||
|
|
||||||
/// isConditionTrue - Return whether the condition is true (i.e. not
|
/// isConditionTrue - Return whether the condition is true (i.e. not
|
||||||
/// equal to zero).
|
/// equal to zero).
|
||||||
bool isConditionTrue(const ASTContext &C) const;
|
bool isConditionTrue() const {
|
||||||
|
assert(!isConditionDependent() &&
|
||||||
|
"Dependent condition isn't true or false");
|
||||||
|
return CondIsTrue;
|
||||||
|
}
|
||||||
|
void setIsConditionTrue(bool isTrue) { CondIsTrue = isTrue; }
|
||||||
|
|
||||||
|
bool isConditionDependent() const {
|
||||||
|
return getCond()->isTypeDependent() || getCond()->isValueDependent();
|
||||||
|
}
|
||||||
|
|
||||||
/// getChosenSubExpr - Return the subexpression chosen according to the
|
/// getChosenSubExpr - Return the subexpression chosen according to the
|
||||||
/// condition.
|
/// condition.
|
||||||
Expr *getChosenSubExpr(const ASTContext &C) const {
|
Expr *getChosenSubExpr() const {
|
||||||
return isConditionTrue(C) ? getLHS() : getRHS();
|
return isConditionTrue() ? getLHS() : getRHS();
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
|
Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
|
||||||
@ -3663,7 +3733,7 @@ class InitListExpr : public Expr {
|
|||||||
SourceLocation LBraceLoc, RBraceLoc;
|
SourceLocation LBraceLoc, RBraceLoc;
|
||||||
|
|
||||||
/// The alternative form of the initializer list (if it exists).
|
/// The alternative form of the initializer list (if it exists).
|
||||||
/// The int part of the pair stores whether this initalizer list is
|
/// The int part of the pair stores whether this initializer list is
|
||||||
/// in semantic form. If not null, the pointer points to:
|
/// in semantic form. If not null, the pointer points to:
|
||||||
/// - the syntactic form, if this is in semantic form;
|
/// - the syntactic form, if this is in semantic form;
|
||||||
/// - the semantic form, if this is in syntactic form.
|
/// - the semantic form, if this is in syntactic form.
|
||||||
@ -3679,7 +3749,7 @@ class InitListExpr : public Expr {
|
|||||||
llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
|
llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InitListExpr(ASTContext &C, SourceLocation lbraceloc,
|
InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
|
||||||
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
|
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
|
||||||
|
|
||||||
/// \brief Build an empty initializer list.
|
/// \brief Build an empty initializer list.
|
||||||
@ -3707,7 +3777,7 @@ class InitListExpr : public Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Reserve space for some number of initializers.
|
/// \brief Reserve space for some number of initializers.
|
||||||
void reserveInits(ASTContext &C, unsigned NumInits);
|
void reserveInits(const ASTContext &C, unsigned NumInits);
|
||||||
|
|
||||||
/// @brief Specify the number of initializers
|
/// @brief Specify the number of initializers
|
||||||
///
|
///
|
||||||
@ -3715,7 +3785,7 @@ class InitListExpr : public Expr {
|
|||||||
/// initializers will be destroyed. If there are fewer than @p
|
/// initializers will be destroyed. If there are fewer than @p
|
||||||
/// NumInits initializers, NULL expressions will be added for the
|
/// NumInits initializers, NULL expressions will be added for the
|
||||||
/// unknown initializers.
|
/// unknown initializers.
|
||||||
void resizeInits(ASTContext &Context, unsigned NumInits);
|
void resizeInits(const ASTContext &Context, unsigned NumInits);
|
||||||
|
|
||||||
/// @brief Updates the initializer at index @p Init with the new
|
/// @brief Updates the initializer at index @p Init with the new
|
||||||
/// expression @p expr, and returns the old expression at that
|
/// expression @p expr, and returns the old expression at that
|
||||||
@ -3724,7 +3794,7 @@ class InitListExpr : public Expr {
|
|||||||
/// When @p Init is out of range for this initializer list, the
|
/// When @p Init is out of range for this initializer list, the
|
||||||
/// initializer list will be extended with NULL expressions to
|
/// initializer list will be extended with NULL expressions to
|
||||||
/// accommodate the new entry.
|
/// accommodate the new entry.
|
||||||
Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr);
|
Expr *updateInit(const ASTContext &C, unsigned Init, Expr *expr);
|
||||||
|
|
||||||
/// \brief If this initializer list initializes an array with more elements
|
/// \brief If this initializer list initializes an array with more elements
|
||||||
/// than there are initializers in the list, specifies an expression to be
|
/// than there are initializers in the list, specifies an expression to be
|
||||||
@ -3754,6 +3824,10 @@ class InitListExpr : public Expr {
|
|||||||
return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
|
return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
|
||||||
}
|
}
|
||||||
void setInitializedFieldInUnion(FieldDecl *FD) {
|
void setInitializedFieldInUnion(FieldDecl *FD) {
|
||||||
|
assert((FD == 0
|
||||||
|
|| getInitializedFieldInUnion() == 0
|
||||||
|
|| getInitializedFieldInUnion() == FD)
|
||||||
|
&& "Only one field of a union may be initialized at a time!");
|
||||||
ArrayFillerOrUnionFieldInit = FD;
|
ArrayFillerOrUnionFieldInit = FD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3794,13 +3868,6 @@ class InitListExpr : public Expr {
|
|||||||
InitListExprBits.HadArrayRangeDesignator = ARD;
|
InitListExprBits.HadArrayRangeDesignator = ARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initializesStdInitializerList() const {
|
|
||||||
return InitListExprBits.InitializesStdInitializerList != 0;
|
|
||||||
}
|
|
||||||
void setInitializesStdInitializerList(bool ISIL = true) {
|
|
||||||
InitListExprBits.InitializesStdInitializerList = ISIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY;
|
SourceLocation getLocStart() const LLVM_READONLY;
|
||||||
SourceLocation getLocEnd() const LLVM_READONLY;
|
SourceLocation getLocEnd() const LLVM_READONLY;
|
||||||
|
|
||||||
@ -3851,7 +3918,7 @@ class InitListExpr : public Expr {
|
|||||||
/// The InitListExpr contains three DesignatedInitExprs, the first of
|
/// The InitListExpr contains three DesignatedInitExprs, the first of
|
||||||
/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
|
/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
|
||||||
/// designators, one array designator for @c [2] followed by one field
|
/// designators, one array designator for @c [2] followed by one field
|
||||||
/// designator for @c .y. The initalization expression will be 1.0.
|
/// designator for @c .y. The initialization expression will be 1.0.
|
||||||
class DesignatedInitExpr : public Expr {
|
class DesignatedInitExpr : public Expr {
|
||||||
public:
|
public:
|
||||||
/// \brief Forward declaration of the Designator class.
|
/// \brief Forward declaration of the Designator class.
|
||||||
@ -3879,7 +3946,7 @@ class DesignatedInitExpr : public Expr {
|
|||||||
Designator *Designators;
|
Designator *Designators;
|
||||||
|
|
||||||
|
|
||||||
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
|
DesignatedInitExpr(const ASTContext &C, QualType Ty, unsigned NumDesignators,
|
||||||
const Designator *Designators,
|
const Designator *Designators,
|
||||||
SourceLocation EqualOrColonLoc, bool GNUSyntax,
|
SourceLocation EqualOrColonLoc, bool GNUSyntax,
|
||||||
ArrayRef<Expr*> IndexExprs, Expr *Init);
|
ArrayRef<Expr*> IndexExprs, Expr *Init);
|
||||||
@ -4041,13 +4108,15 @@ class DesignatedInitExpr : public Expr {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
|
static DesignatedInitExpr *Create(const ASTContext &C,
|
||||||
|
Designator *Designators,
|
||||||
unsigned NumDesignators,
|
unsigned NumDesignators,
|
||||||
ArrayRef<Expr*> IndexExprs,
|
ArrayRef<Expr*> IndexExprs,
|
||||||
SourceLocation EqualOrColonLoc,
|
SourceLocation EqualOrColonLoc,
|
||||||
bool GNUSyntax, Expr *Init);
|
bool GNUSyntax, Expr *Init);
|
||||||
|
|
||||||
static DesignatedInitExpr *CreateEmpty(ASTContext &C, unsigned NumIndexExprs);
|
static DesignatedInitExpr *CreateEmpty(const ASTContext &C,
|
||||||
|
unsigned NumIndexExprs);
|
||||||
|
|
||||||
/// @brief Returns the number of designators in this initializer.
|
/// @brief Returns the number of designators in this initializer.
|
||||||
unsigned size() const { return NumDesignators; }
|
unsigned size() const { return NumDesignators; }
|
||||||
@ -4085,7 +4154,7 @@ class DesignatedInitExpr : public Expr {
|
|||||||
|
|
||||||
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
|
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
|
||||||
|
|
||||||
void setDesignators(ASTContext &C, const Designator *Desigs,
|
void setDesignators(const ASTContext &C, const Designator *Desigs,
|
||||||
unsigned NumDesigs);
|
unsigned NumDesigs);
|
||||||
|
|
||||||
Expr *getArrayIndex(const Designator &D) const;
|
Expr *getArrayIndex(const Designator &D) const;
|
||||||
@ -4133,8 +4202,8 @@ class DesignatedInitExpr : public Expr {
|
|||||||
|
|
||||||
/// \brief Replaces the designator at index @p Idx with the series
|
/// \brief Replaces the designator at index @p Idx with the series
|
||||||
/// of designators in [First, Last).
|
/// of designators in [First, Last).
|
||||||
void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First,
|
void ExpandDesignator(const ASTContext &C, unsigned Idx,
|
||||||
const Designator *Last);
|
const Designator *First, const Designator *Last);
|
||||||
|
|
||||||
SourceRange getDesignatorsSourceRange() const;
|
SourceRange getDesignatorsSourceRange() const;
|
||||||
|
|
||||||
@ -4188,8 +4257,8 @@ class ParenListExpr : public Expr {
|
|||||||
SourceLocation LParenLoc, RParenLoc;
|
SourceLocation LParenLoc, RParenLoc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ParenListExpr(ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs,
|
ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
|
||||||
SourceLocation rparenloc);
|
ArrayRef<Expr*> exprs, SourceLocation rparenloc);
|
||||||
|
|
||||||
/// \brief Build an empty paren list.
|
/// \brief Build an empty paren list.
|
||||||
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
|
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
|
||||||
@ -4262,7 +4331,7 @@ class GenericSelectionExpr : public Expr {
|
|||||||
SourceLocation GenericLoc, DefaultLoc, RParenLoc;
|
SourceLocation GenericLoc, DefaultLoc, RParenLoc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GenericSelectionExpr(ASTContext &Context,
|
GenericSelectionExpr(const ASTContext &Context,
|
||||||
SourceLocation GenericLoc, Expr *ControllingExpr,
|
SourceLocation GenericLoc, Expr *ControllingExpr,
|
||||||
ArrayRef<TypeSourceInfo*> AssocTypes,
|
ArrayRef<TypeSourceInfo*> AssocTypes,
|
||||||
ArrayRef<Expr*> AssocExprs,
|
ArrayRef<Expr*> AssocExprs,
|
||||||
@ -4271,7 +4340,7 @@ class GenericSelectionExpr : public Expr {
|
|||||||
unsigned ResultIndex);
|
unsigned ResultIndex);
|
||||||
|
|
||||||
/// This constructor is used in the result-dependent case.
|
/// This constructor is used in the result-dependent case.
|
||||||
GenericSelectionExpr(ASTContext &Context,
|
GenericSelectionExpr(const ASTContext &Context,
|
||||||
SourceLocation GenericLoc, Expr *ControllingExpr,
|
SourceLocation GenericLoc, Expr *ControllingExpr,
|
||||||
ArrayRef<TypeSourceInfo*> AssocTypes,
|
ArrayRef<TypeSourceInfo*> AssocTypes,
|
||||||
ArrayRef<Expr*> AssocExprs,
|
ArrayRef<Expr*> AssocExprs,
|
||||||
@ -4450,7 +4519,7 @@ class BlockExpr : public Expr {
|
|||||||
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
|
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
|
||||||
/// This AST node provides support for reinterpreting a type to another
|
/// This AST node provides support for reinterpreting a type to another
|
||||||
/// type of the same size.
|
/// type of the same size.
|
||||||
class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr?
|
class AsTypeExpr : public Expr {
|
||||||
private:
|
private:
|
||||||
Stmt *SrcExpr;
|
Stmt *SrcExpr;
|
||||||
SourceLocation BuiltinLoc, RParenLoc;
|
SourceLocation BuiltinLoc, RParenLoc;
|
||||||
@ -4552,13 +4621,13 @@ class PseudoObjectExpr : public Expr {
|
|||||||
public:
|
public:
|
||||||
/// NoResult - A value for the result index indicating that there is
|
/// NoResult - A value for the result index indicating that there is
|
||||||
/// no semantic result.
|
/// no semantic result.
|
||||||
enum { NoResult = ~0U };
|
enum LLVM_ENUM_INT_TYPE(unsigned) { NoResult = ~0U };
|
||||||
|
|
||||||
static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic,
|
static PseudoObjectExpr *Create(const ASTContext &Context, Expr *syntactic,
|
||||||
ArrayRef<Expr*> semantic,
|
ArrayRef<Expr*> semantic,
|
||||||
unsigned resultIndex);
|
unsigned resultIndex);
|
||||||
|
|
||||||
static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell,
|
static PseudoObjectExpr *Create(const ASTContext &Context, EmptyShell shell,
|
||||||
unsigned numSemanticExprs);
|
unsigned numSemanticExprs);
|
||||||
|
|
||||||
/// Return the syntactic form of this expression, i.e. the
|
/// Return the syntactic form of this expression, i.e. the
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -143,12 +143,13 @@ class ObjCArrayLiteral : public Expr {
|
|||||||
: Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {}
|
: Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ObjCArrayLiteral *Create(ASTContext &C,
|
static ObjCArrayLiteral *Create(const ASTContext &C,
|
||||||
ArrayRef<Expr *> Elements,
|
ArrayRef<Expr *> Elements,
|
||||||
QualType T, ObjCMethodDecl * Method,
|
QualType T, ObjCMethodDecl * Method,
|
||||||
SourceRange SR);
|
SourceRange SR);
|
||||||
|
|
||||||
static ObjCArrayLiteral *CreateEmpty(ASTContext &C, unsigned NumElements);
|
static ObjCArrayLiteral *CreateEmpty(const ASTContext &C,
|
||||||
|
unsigned NumElements);
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
|
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
|
||||||
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
|
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
|
||||||
@ -289,13 +290,13 @@ class ObjCDictionaryLiteral : public Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ObjCDictionaryLiteral *Create(ASTContext &C,
|
static ObjCDictionaryLiteral *Create(const ASTContext &C,
|
||||||
ArrayRef<ObjCDictionaryElement> VK,
|
ArrayRef<ObjCDictionaryElement> VK,
|
||||||
bool HasPackExpansions,
|
bool HasPackExpansions,
|
||||||
QualType T, ObjCMethodDecl *method,
|
QualType T, ObjCMethodDecl *method,
|
||||||
SourceRange SR);
|
SourceRange SR);
|
||||||
|
|
||||||
static ObjCDictionaryLiteral *CreateEmpty(ASTContext &C,
|
static ObjCDictionaryLiteral *CreateEmpty(const ASTContext &C,
|
||||||
unsigned NumElements,
|
unsigned NumElements,
|
||||||
bool HasPackExpansions);
|
bool HasPackExpansions);
|
||||||
|
|
||||||
@ -807,7 +808,7 @@ class ObjCSubscriptRefExpr : public Expr {
|
|||||||
explicit ObjCSubscriptRefExpr(EmptyShell Empty)
|
explicit ObjCSubscriptRefExpr(EmptyShell Empty)
|
||||||
: Expr(ObjCSubscriptRefExprClass, Empty) {}
|
: Expr(ObjCSubscriptRefExprClass, Empty) {}
|
||||||
|
|
||||||
static ObjCSubscriptRefExpr *Create(ASTContext &C,
|
static ObjCSubscriptRefExpr *Create(const ASTContext &C,
|
||||||
Expr *base,
|
Expr *base,
|
||||||
Expr *key, QualType T,
|
Expr *key, QualType T,
|
||||||
ObjCMethodDecl *getMethod,
|
ObjCMethodDecl *getMethod,
|
||||||
@ -1003,13 +1004,13 @@ class ObjCMessageExpr : public Expr {
|
|||||||
return getNumSelectorLocs();
|
return getNumSelectorLocs();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ObjCMessageExpr *alloc(ASTContext &C,
|
static ObjCMessageExpr *alloc(const ASTContext &C,
|
||||||
ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
SourceLocation RBraceLoc,
|
SourceLocation RBraceLoc,
|
||||||
ArrayRef<SourceLocation> SelLocs,
|
ArrayRef<SourceLocation> SelLocs,
|
||||||
Selector Sel,
|
Selector Sel,
|
||||||
SelectorLocationsKind &SelLocsK);
|
SelectorLocationsKind &SelLocsK);
|
||||||
static ObjCMessageExpr *alloc(ASTContext &C,
|
static ObjCMessageExpr *alloc(const ASTContext &C,
|
||||||
unsigned NumArgs,
|
unsigned NumArgs,
|
||||||
unsigned NumStoredSelLocs);
|
unsigned NumStoredSelLocs);
|
||||||
|
|
||||||
@ -1051,7 +1052,7 @@ class ObjCMessageExpr : public Expr {
|
|||||||
/// \param Args The message send arguments.
|
/// \param Args The message send arguments.
|
||||||
///
|
///
|
||||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
|
||||||
ExprValueKind VK,
|
ExprValueKind VK,
|
||||||
SourceLocation LBracLoc,
|
SourceLocation LBracLoc,
|
||||||
SourceLocation SuperLoc,
|
SourceLocation SuperLoc,
|
||||||
@ -1087,7 +1088,7 @@ class ObjCMessageExpr : public Expr {
|
|||||||
/// \param Args The message send arguments.
|
/// \param Args The message send arguments.
|
||||||
///
|
///
|
||||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
|
||||||
ExprValueKind VK,
|
ExprValueKind VK,
|
||||||
SourceLocation LBracLoc,
|
SourceLocation LBracLoc,
|
||||||
TypeSourceInfo *Receiver,
|
TypeSourceInfo *Receiver,
|
||||||
@ -1121,7 +1122,7 @@ class ObjCMessageExpr : public Expr {
|
|||||||
/// \param Args The message send arguments.
|
/// \param Args The message send arguments.
|
||||||
///
|
///
|
||||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
|
||||||
ExprValueKind VK,
|
ExprValueKind VK,
|
||||||
SourceLocation LBracLoc,
|
SourceLocation LBracLoc,
|
||||||
Expr *Receiver,
|
Expr *Receiver,
|
||||||
@ -1139,7 +1140,7 @@ class ObjCMessageExpr : public Expr {
|
|||||||
///
|
///
|
||||||
/// \param NumArgs The number of message arguments, not including
|
/// \param NumArgs The number of message arguments, not including
|
||||||
/// the receiver.
|
/// the receiver.
|
||||||
static ObjCMessageExpr *CreateEmpty(ASTContext &Context,
|
static ObjCMessageExpr *CreateEmpty(const ASTContext &Context,
|
||||||
unsigned NumArgs,
|
unsigned NumArgs,
|
||||||
unsigned NumStoredSelLocs);
|
unsigned NumStoredSelLocs);
|
||||||
|
|
||||||
|
@ -329,7 +329,12 @@ struct LazyOffsetPtr {
|
|||||||
/// \brief Whether this pointer is non-NULL.
|
/// \brief Whether this pointer is non-NULL.
|
||||||
///
|
///
|
||||||
/// This operation does not require the AST node to be deserialized.
|
/// This operation does not require the AST node to be deserialized.
|
||||||
operator bool() const { return Ptr != 0; }
|
LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
|
||||||
|
|
||||||
|
/// \brief Whether this pointer is non-NULL.
|
||||||
|
///
|
||||||
|
/// This operation does not require the AST node to be deserialized.
|
||||||
|
bool isValid() const { return Ptr != 0; }
|
||||||
|
|
||||||
/// \brief Whether this pointer is currently stored as an offset.
|
/// \brief Whether this pointer is currently stored as an offset.
|
||||||
bool isOffset() const { return Ptr & 0x01; }
|
bool isOffset() const { return Ptr & 0x01; }
|
||||||
|
@ -41,6 +41,7 @@ class GlobalDecl {
|
|||||||
GlobalDecl(const VarDecl *D) { Init(D);}
|
GlobalDecl(const VarDecl *D) { Init(D);}
|
||||||
GlobalDecl(const FunctionDecl *D) { Init(D); }
|
GlobalDecl(const FunctionDecl *D) { Init(D); }
|
||||||
GlobalDecl(const BlockDecl *D) { Init(D); }
|
GlobalDecl(const BlockDecl *D) { Init(D); }
|
||||||
|
GlobalDecl(const CapturedDecl *D) { Init(D); }
|
||||||
GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
|
GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
|
||||||
|
|
||||||
GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
|
GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- 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 LambdaMangleContext interface, which keeps track of
|
|
||||||
// the Itanium C++ ABI mangling numbers for lambda expressions.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H
|
|
||||||
#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H
|
|
||||||
|
|
||||||
#include "clang/Basic/LLVM.h"
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
|
||||||
|
|
||||||
namespace clang {
|
|
||||||
|
|
||||||
class CXXMethodDecl;
|
|
||||||
class FunctionProtoType;
|
|
||||||
|
|
||||||
/// \brief Keeps track of the mangled names of lambda expressions within a
|
|
||||||
/// particular context.
|
|
||||||
class LambdaMangleContext : public RefCountedBase<LambdaMangleContext> {
|
|
||||||
llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// \brief Retrieve the mangling number of a new lambda expression with the
|
|
||||||
/// given call operator within this lambda context.
|
|
||||||
unsigned getManglingNumber(CXXMethodDecl *CallOperator);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace clang
|
|
||||||
#endif
|
|
@ -19,6 +19,7 @@
|
|||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/Support/Casting.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
@ -64,18 +65,29 @@ class MangleBuffer {
|
|||||||
/// MangleContext - Context for tracking state which persists across multiple
|
/// MangleContext - Context for tracking state which persists across multiple
|
||||||
/// calls to the C++ name mangler.
|
/// calls to the C++ name mangler.
|
||||||
class MangleContext {
|
class MangleContext {
|
||||||
|
public:
|
||||||
|
enum ManglerKind {
|
||||||
|
MK_Itanium,
|
||||||
|
MK_Microsoft
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
|
|
||||||
ASTContext &Context;
|
ASTContext &Context;
|
||||||
DiagnosticsEngine &Diags;
|
DiagnosticsEngine &Diags;
|
||||||
|
const ManglerKind Kind;
|
||||||
|
|
||||||
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
|
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
|
||||||
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
|
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
ManglerKind getKind() const { return Kind; }
|
||||||
|
|
||||||
explicit MangleContext(ASTContext &Context,
|
explicit MangleContext(ASTContext &Context,
|
||||||
DiagnosticsEngine &Diags)
|
DiagnosticsEngine &Diags,
|
||||||
: Context(Context), Diags(Diags) { }
|
ManglerKind Kind)
|
||||||
|
: Context(Context), Diags(Diags), Kind(Kind) {}
|
||||||
|
|
||||||
virtual ~MangleContext() { }
|
virtual ~MangleContext() { }
|
||||||
|
|
||||||
@ -96,8 +108,12 @@ class MangleContext {
|
|||||||
/// @name Mangler Entry Points
|
/// @name Mangler Entry Points
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
|
bool shouldMangleDeclName(const NamedDecl *D);
|
||||||
virtual void mangleName(const NamedDecl *D, raw_ostream &)=0;
|
virtual bool shouldMangleCXXName(const NamedDecl *D) = 0;
|
||||||
|
|
||||||
|
// FIXME: consider replacing raw_ostream & with something like SmallString &.
|
||||||
|
void mangleName(const NamedDecl *D, raw_ostream &);
|
||||||
|
virtual void mangleCXXName(const NamedDecl *D, raw_ostream &) = 0;
|
||||||
virtual void mangleThunk(const CXXMethodDecl *MD,
|
virtual void mangleThunk(const CXXMethodDecl *MD,
|
||||||
const ThunkInfo &Thunk,
|
const ThunkInfo &Thunk,
|
||||||
raw_ostream &) = 0;
|
raw_ostream &) = 0;
|
||||||
@ -106,13 +122,6 @@ class MangleContext {
|
|||||||
raw_ostream &) = 0;
|
raw_ostream &) = 0;
|
||||||
virtual void mangleReferenceTemporary(const VarDecl *D,
|
virtual void mangleReferenceTemporary(const VarDecl *D,
|
||||||
raw_ostream &) = 0;
|
raw_ostream &) = 0;
|
||||||
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
|
|
||||||
raw_ostream &) = 0;
|
|
||||||
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
|
|
||||||
raw_ostream &) = 0;
|
|
||||||
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
|
|
||||||
const CXXRecordDecl *Type,
|
|
||||||
raw_ostream &) = 0;
|
|
||||||
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
|
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
|
||||||
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
|
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
|
||||||
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
|
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
|
||||||
@ -129,36 +138,78 @@ class MangleContext {
|
|||||||
const BlockDecl *BD, raw_ostream &Out);
|
const BlockDecl *BD, raw_ostream &Out);
|
||||||
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
||||||
raw_ostream &Out);
|
raw_ostream &Out);
|
||||||
// Do the right thing.
|
|
||||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out,
|
|
||||||
const NamedDecl *ID=0);
|
|
||||||
|
|
||||||
void mangleObjCMethodName(const ObjCMethodDecl *MD,
|
void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &);
|
||||||
raw_ostream &);
|
|
||||||
|
|
||||||
// This is pretty lame.
|
virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) = 0;
|
||||||
virtual void mangleItaniumGuardVariable(const VarDecl *D,
|
|
||||||
raw_ostream &) {
|
virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &) = 0;
|
||||||
llvm_unreachable("Target does not support mangling guard variables");
|
|
||||||
}
|
virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
|
||||||
// FIXME: Revisit this once we know what we need to do for MSVC compatibility.
|
raw_ostream &) = 0;
|
||||||
virtual void mangleItaniumThreadLocalInit(const VarDecl *D,
|
|
||||||
raw_ostream &) {
|
/// Generates a unique string for an externally visible type for use with TBAA
|
||||||
llvm_unreachable("Target does not support mangling thread_local variables");
|
/// or type uniquing.
|
||||||
}
|
/// TODO: Extend this to internal types by generating names that are unique
|
||||||
virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D,
|
/// across translation units so it can be used with LTO.
|
||||||
raw_ostream &) {
|
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
|
||||||
llvm_unreachable("Target does not support mangling thread_local variables");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
};
|
};
|
||||||
|
|
||||||
MangleContext *createItaniumMangleContext(ASTContext &Context,
|
class ItaniumMangleContext : public MangleContext {
|
||||||
DiagnosticsEngine &Diags);
|
public:
|
||||||
MangleContext *createMicrosoftMangleContext(ASTContext &Context,
|
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
|
||||||
DiagnosticsEngine &Diags);
|
: MangleContext(C, D, MK_Itanium) {}
|
||||||
|
|
||||||
|
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
|
||||||
|
virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0;
|
||||||
|
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
|
||||||
|
const CXXRecordDecl *Type,
|
||||||
|
raw_ostream &) = 0;
|
||||||
|
virtual void mangleItaniumThreadLocalInit(const VarDecl *D,
|
||||||
|
raw_ostream &) = 0;
|
||||||
|
virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D,
|
||||||
|
raw_ostream &) = 0;
|
||||||
|
|
||||||
|
static bool classof(const MangleContext *C) {
|
||||||
|
return C->getKind() == MK_Itanium;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ItaniumMangleContext *create(ASTContext &Context,
|
||||||
|
DiagnosticsEngine &Diags);
|
||||||
|
};
|
||||||
|
|
||||||
|
class MicrosoftMangleContext : public MangleContext {
|
||||||
|
public:
|
||||||
|
explicit MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D)
|
||||||
|
: MangleContext(C, D, MK_Microsoft) {}
|
||||||
|
|
||||||
|
/// \brief Mangle vftable symbols. Only a subset of the bases along the path
|
||||||
|
/// to the vftable are included in the name. It's up to the caller to pick
|
||||||
|
/// them correctly.
|
||||||
|
virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
|
||||||
|
ArrayRef<const CXXRecordDecl *> BasePath,
|
||||||
|
raw_ostream &Out) = 0;
|
||||||
|
|
||||||
|
/// \brief Mangle vbtable symbols. Only a subset of the bases along the path
|
||||||
|
/// to the vbtable are included in the name. It's up to the caller to pick
|
||||||
|
/// them correctly.
|
||||||
|
virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
|
||||||
|
ArrayRef<const CXXRecordDecl *> BasePath,
|
||||||
|
raw_ostream &Out) = 0;
|
||||||
|
|
||||||
|
virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
|
||||||
|
uint64_t OffsetInVFTable,
|
||||||
|
raw_ostream &) = 0;
|
||||||
|
|
||||||
|
static bool classof(const MangleContext *C) {
|
||||||
|
return C->getKind() == MK_Microsoft;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MicrosoftMangleContext *create(ASTContext &Context,
|
||||||
|
DiagnosticsEngine &Diags);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
59
include/clang/AST/MangleNumberingContext.h
Normal file
59
include/clang/AST/MangleNumberingContext.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//=== MangleNumberingContext.h - Context for mangling numbers ---*- 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 LambdaBlockMangleContext interface, which keeps track
|
||||||
|
// of the Itanium C++ ABI mangling numbers for lambda expressions and block
|
||||||
|
// literals.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#ifndef LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
|
||||||
|
#define LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
|
||||||
|
|
||||||
|
#include "clang/Basic/LLVM.h"
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||||
|
|
||||||
|
namespace clang {
|
||||||
|
|
||||||
|
class BlockDecl;
|
||||||
|
class CXXMethodDecl;
|
||||||
|
class IdentifierInfo;
|
||||||
|
class TagDecl;
|
||||||
|
class Type;
|
||||||
|
class VarDecl;
|
||||||
|
|
||||||
|
/// \brief Keeps track of the mangled names of lambda expressions and block
|
||||||
|
/// literals within a particular context.
|
||||||
|
class MangleNumberingContext
|
||||||
|
: public RefCountedBase<MangleNumberingContext> {
|
||||||
|
llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
|
||||||
|
llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~MangleNumberingContext() {}
|
||||||
|
|
||||||
|
/// \brief Retrieve the mangling number of a new lambda expression with the
|
||||||
|
/// given call operator within this context.
|
||||||
|
unsigned getManglingNumber(const CXXMethodDecl *CallOperator);
|
||||||
|
|
||||||
|
/// \brief Retrieve the mangling number of a new block literal within this
|
||||||
|
/// context.
|
||||||
|
unsigned getManglingNumber(const BlockDecl *BD);
|
||||||
|
|
||||||
|
/// \brief Retrieve the mangling number of a static local variable within
|
||||||
|
/// this context.
|
||||||
|
virtual unsigned getManglingNumber(const VarDecl *VD) = 0;
|
||||||
|
|
||||||
|
/// \brief Retrieve the mangling number of a static local variable within
|
||||||
|
/// this context.
|
||||||
|
unsigned getManglingNumber(const TagDecl *TD);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace clang
|
||||||
|
#endif
|
@ -231,7 +231,11 @@ class NestedNameSpecifierLoc {
|
|||||||
|
|
||||||
/// \brief Evalutes true when this nested-name-specifier location is
|
/// \brief Evalutes true when this nested-name-specifier location is
|
||||||
/// non-empty.
|
/// non-empty.
|
||||||
operator bool() const { return Qualifier; }
|
LLVM_EXPLICIT operator bool() const { return Qualifier; }
|
||||||
|
|
||||||
|
/// \brief Evalutes true when this nested-name-specifier location is
|
||||||
|
/// empty.
|
||||||
|
bool hasQualifier() const { return Qualifier; }
|
||||||
|
|
||||||
/// \brief Retrieve the nested-name-specifier to which this instance
|
/// \brief Retrieve the nested-name-specifier to which this instance
|
||||||
/// refers.
|
/// refers.
|
||||||
|
@ -29,6 +29,11 @@ class ParentMap {
|
|||||||
/// visited and updated or inserted but not the parents of S.
|
/// visited and updated or inserted but not the parents of S.
|
||||||
void addStmt(Stmt* S);
|
void addStmt(Stmt* S);
|
||||||
|
|
||||||
|
/// Manually sets the parent of \p S to \p Parent.
|
||||||
|
///
|
||||||
|
/// If \p S is already in the map, this method will update the mapping.
|
||||||
|
void setParent(const Stmt *S, const Stmt *Parent);
|
||||||
|
|
||||||
Stmt *getParent(Stmt*) const;
|
Stmt *getParent(Stmt*) const;
|
||||||
Stmt *getParentIgnoreParens(Stmt *) const;
|
Stmt *getParentIgnoreParens(Stmt *) const;
|
||||||
Stmt *getParentIgnoreParenCasts(Stmt *) const;
|
Stmt *getParentIgnoreParenCasts(Stmt *) const;
|
||||||
|
@ -39,8 +39,9 @@ struct PrintingPolicy {
|
|||||||
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
|
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
|
||||||
SuppressUnwrittenScope(false), SuppressInitializers(false),
|
SuppressUnwrittenScope(false), SuppressInitializers(false),
|
||||||
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
|
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
|
||||||
SuppressStrongLifetime(false), Bool(LO.Bool),
|
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
|
||||||
TerseOutput(false), PolishForDeclaration(false) { }
|
Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false),
|
||||||
|
MSWChar(LO.MicrosoftExt && !LO.WChar) { }
|
||||||
|
|
||||||
/// \brief What language we're printing.
|
/// \brief What language we're printing.
|
||||||
LangOptions LangOpts;
|
LangOptions LangOpts;
|
||||||
@ -131,6 +132,10 @@ struct PrintingPolicy {
|
|||||||
/// ARC.
|
/// ARC.
|
||||||
unsigned SuppressStrongLifetime : 1;
|
unsigned SuppressStrongLifetime : 1;
|
||||||
|
|
||||||
|
/// \brief When true, suppress printing of lifetime qualifier in
|
||||||
|
/// ARC.
|
||||||
|
unsigned SuppressLifetimeQualifiers : 1;
|
||||||
|
|
||||||
/// \brief Whether we can use 'bool' rather than '_Bool', even if the language
|
/// \brief Whether we can use 'bool' rather than '_Bool', even if the language
|
||||||
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
|
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
|
||||||
unsigned Bool : 1;
|
unsigned Bool : 1;
|
||||||
@ -146,6 +151,10 @@ struct PrintingPolicy {
|
|||||||
/// declaration tag; such as, do not print attributes attached to the declaration.
|
/// declaration tag; such as, do not print attributes attached to the declaration.
|
||||||
///
|
///
|
||||||
unsigned PolishForDeclaration : 1;
|
unsigned PolishForDeclaration : 1;
|
||||||
|
|
||||||
|
/// \brief When true, print the built-in wchar_t type as __wchar_t. For use in
|
||||||
|
/// Microsoft mode when wchar_t is not available.
|
||||||
|
unsigned MSWChar : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
@ -107,12 +107,9 @@ class RawComment {
|
|||||||
return RawText;
|
return RawText;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceRange getSourceRange() const LLVM_READONLY {
|
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
|
||||||
return Range;
|
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
|
||||||
}
|
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
|
||||||
|
|
||||||
unsigned getBeginLine(const SourceManager &SM) const;
|
|
||||||
unsigned getEndLine(const SourceManager &SM) const;
|
|
||||||
|
|
||||||
const char *getBriefText(const ASTContext &Context) const {
|
const char *getBriefText(const ASTContext &Context) const {
|
||||||
if (BriefTextValid)
|
if (BriefTextValid)
|
||||||
@ -146,11 +143,6 @@ class RawComment {
|
|||||||
/// considered as documentation comments.
|
/// considered as documentation comments.
|
||||||
bool ParseAllComments : 1;
|
bool ParseAllComments : 1;
|
||||||
|
|
||||||
mutable bool BeginLineValid : 1; ///< True if BeginLine is valid
|
|
||||||
mutable bool EndLineValid : 1; ///< True if EndLine is valid
|
|
||||||
mutable unsigned BeginLine; ///< Cached line number
|
|
||||||
mutable unsigned EndLine; ///< Cached line number
|
|
||||||
|
|
||||||
/// \brief Constructor for AST deserialization.
|
/// \brief Constructor for AST deserialization.
|
||||||
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
|
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
|
||||||
bool IsAlmostTrailingComment,
|
bool IsAlmostTrailingComment,
|
||||||
@ -158,8 +150,7 @@ class RawComment {
|
|||||||
Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
|
Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
|
||||||
IsAttached(false), IsTrailingComment(IsTrailingComment),
|
IsAttached(false), IsTrailingComment(IsTrailingComment),
|
||||||
IsAlmostTrailingComment(IsAlmostTrailingComment),
|
IsAlmostTrailingComment(IsAlmostTrailingComment),
|
||||||
ParseAllComments(ParseAllComments),
|
ParseAllComments(ParseAllComments)
|
||||||
BeginLineValid(false), EndLineValid(false)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
|
StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
|
||||||
@ -178,8 +169,7 @@ class BeforeThanCompare<RawComment> {
|
|||||||
explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
|
explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
|
||||||
|
|
||||||
bool operator()(const RawComment &LHS, const RawComment &RHS) {
|
bool operator()(const RawComment &LHS, const RawComment &RHS) {
|
||||||
return SM.isBeforeInTranslationUnit(LHS.getSourceRange().getBegin(),
|
return SM.isBeforeInTranslationUnit(LHS.getLocStart(), RHS.getLocStart());
|
||||||
RHS.getSourceRange().getBegin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(const RawComment *LHS, const RawComment *RHS) {
|
bool operator()(const RawComment *LHS, const RawComment *RHS) {
|
||||||
@ -191,8 +181,7 @@ class BeforeThanCompare<RawComment> {
|
|||||||
/// sorted in order of appearance in the translation unit.
|
/// sorted in order of appearance in the translation unit.
|
||||||
class RawCommentList {
|
class RawCommentList {
|
||||||
public:
|
public:
|
||||||
RawCommentList(SourceManager &SourceMgr) :
|
RawCommentList(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
|
||||||
SourceMgr(SourceMgr), OnlyWhitespaceSeen(true) { }
|
|
||||||
|
|
||||||
void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator);
|
void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator);
|
||||||
|
|
||||||
@ -203,15 +192,9 @@ class RawCommentList {
|
|||||||
private:
|
private:
|
||||||
SourceManager &SourceMgr;
|
SourceManager &SourceMgr;
|
||||||
std::vector<RawComment *> Comments;
|
std::vector<RawComment *> Comments;
|
||||||
SourceLocation PrevCommentEndLoc;
|
|
||||||
bool OnlyWhitespaceSeen;
|
|
||||||
|
|
||||||
void addCommentsToFront(const std::vector<RawComment *> &C) {
|
void addCommentsToFront(const std::vector<RawComment *> &C) {
|
||||||
size_t OldSize = Comments.size();
|
Comments.insert(Comments.begin(), C.begin(), C.end());
|
||||||
Comments.resize(C.size() + OldSize);
|
|
||||||
std::copy_backward(Comments.begin(), Comments.begin() + OldSize,
|
|
||||||
Comments.end());
|
|
||||||
std::copy(C.begin(), C.end(), Comments.begin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class ASTReader;
|
friend class ASTReader;
|
||||||
|
@ -93,10 +93,22 @@ class ASTRecordLayout {
|
|||||||
/// HasOwnVFPtr - Does this class provide a virtual function table
|
/// HasOwnVFPtr - Does this class provide a virtual function table
|
||||||
/// (vtable in Itanium, vftbl in Microsoft) that is independent from
|
/// (vtable in Itanium, vftbl in Microsoft) that is independent from
|
||||||
/// its base classes?
|
/// its base classes?
|
||||||
bool HasOwnVFPtr; // TODO: stash this somewhere more efficient
|
bool HasOwnVFPtr : 1;
|
||||||
|
|
||||||
|
/// HasVFPtr - Does this class have a vftable that could be extended by
|
||||||
|
/// a derived class. The class may have inherited this pointer from
|
||||||
|
/// a primary base class.
|
||||||
|
bool HasExtendableVFPtr : 1;
|
||||||
|
|
||||||
|
/// AlignAfterVBases - Force appropriate alignment after virtual bases are
|
||||||
|
/// laid out in MS-C++-ABI.
|
||||||
|
bool AlignAfterVBases : 1;
|
||||||
|
|
||||||
/// PrimaryBase - The primary base info for this record.
|
/// PrimaryBase - The primary base info for this record.
|
||||||
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
|
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
|
||||||
|
|
||||||
|
/// BaseSharingVBPtr - The base we share vbptr with.
|
||||||
|
const CXXRecordDecl *BaseSharingVBPtr;
|
||||||
|
|
||||||
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
|
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
|
||||||
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
|
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
|
||||||
@ -122,13 +134,16 @@ class ASTRecordLayout {
|
|||||||
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
|
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
|
||||||
ASTRecordLayout(const ASTContext &Ctx,
|
ASTRecordLayout(const ASTContext &Ctx,
|
||||||
CharUnits size, CharUnits alignment,
|
CharUnits size, CharUnits alignment,
|
||||||
bool hasOwnVFPtr, CharUnits vbptroffset,
|
bool hasOwnVFPtr, bool hasExtendableVFPtr,
|
||||||
|
CharUnits vbptroffset,
|
||||||
CharUnits datasize,
|
CharUnits datasize,
|
||||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||||
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
|
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
|
||||||
CharUnits SizeOfLargestEmptySubobject,
|
CharUnits SizeOfLargestEmptySubobject,
|
||||||
const CXXRecordDecl *PrimaryBase,
|
const CXXRecordDecl *PrimaryBase,
|
||||||
bool IsPrimaryBaseVirtual,
|
bool IsPrimaryBaseVirtual,
|
||||||
|
const CXXRecordDecl *BaseSharingVBPtr,
|
||||||
|
bool ForceAlign,
|
||||||
const BaseOffsetsMapTy& BaseOffsets,
|
const BaseOffsetsMapTy& BaseOffsets,
|
||||||
const VBaseOffsetsMapTy& VBaseOffsets);
|
const VBaseOffsetsMapTy& VBaseOffsets);
|
||||||
|
|
||||||
@ -226,6 +241,37 @@ class ASTRecordLayout {
|
|||||||
return CXXInfo->HasOwnVFPtr;
|
return CXXInfo->HasOwnVFPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// hasVFPtr - Does this class have a virtual function table pointer
|
||||||
|
/// that can be extended by a derived class? This is synonymous with
|
||||||
|
/// this class having a VFPtr at offset zero.
|
||||||
|
bool hasExtendableVFPtr() const {
|
||||||
|
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||||
|
return CXXInfo->HasExtendableVFPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// hasOwnVBPtr - Does this class provide its own virtual-base
|
||||||
|
/// table pointer, rather than inheriting one from a primary base
|
||||||
|
/// class?
|
||||||
|
///
|
||||||
|
/// This implies that the ABI has no primary base class, meaning
|
||||||
|
/// that it has no base classes that are suitable under the conditions
|
||||||
|
/// of the ABI.
|
||||||
|
bool hasOwnVBPtr() const {
|
||||||
|
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||||
|
return hasVBPtr() && !CXXInfo->BaseSharingVBPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// hasVBPtr - Does this class have a virtual function table pointer.
|
||||||
|
bool hasVBPtr() const {
|
||||||
|
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||||
|
return !CXXInfo->VBPtrOffset.isNegative();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getAlignAfterVBases() const {
|
||||||
|
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||||
|
return CXXInfo->AlignAfterVBases;
|
||||||
|
}
|
||||||
|
|
||||||
/// getVBPtrOffset - Get the offset for virtual base table pointer.
|
/// getVBPtrOffset - Get the offset for virtual base table pointer.
|
||||||
/// This is only meaningful with the Microsoft ABI.
|
/// This is only meaningful with the Microsoft ABI.
|
||||||
CharUnits getVBPtrOffset() const {
|
CharUnits getVBPtrOffset() const {
|
||||||
@ -233,6 +279,11 @@ class ASTRecordLayout {
|
|||||||
return CXXInfo->VBPtrOffset;
|
return CXXInfo->VBPtrOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CXXRecordDecl *getBaseSharingVBPtr() const {
|
||||||
|
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||||
|
return CXXInfo->BaseSharingVBPtr;
|
||||||
|
}
|
||||||
|
|
||||||
const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
|
const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
|
||||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||||
return CXXInfo->VBaseOffsets;
|
return CXXInfo->VBaseOffsets;
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "clang/AST/Stmt.h"
|
#include "clang/AST/Stmt.h"
|
||||||
#include "clang/AST/StmtCXX.h"
|
#include "clang/AST/StmtCXX.h"
|
||||||
#include "clang/AST/StmtObjC.h"
|
#include "clang/AST/StmtObjC.h"
|
||||||
|
#include "clang/AST/StmtOpenMP.h"
|
||||||
#include "clang/AST/TemplateBase.h"
|
#include "clang/AST/TemplateBase.h"
|
||||||
#include "clang/AST/TemplateName.h"
|
#include "clang/AST/TemplateName.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
@ -108,7 +109,7 @@ namespace clang {
|
|||||||
/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar
|
/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar
|
||||||
/// is Foo's super class) before calling VisitFoo(), the result is
|
/// is Foo's super class) before calling VisitFoo(), the result is
|
||||||
/// that the Visit*() methods for a given node are called in the
|
/// that the Visit*() methods for a given node are called in the
|
||||||
/// top-down order (e.g. for a node of type NamedDecl, the order will
|
/// top-down order (e.g. for a node of type NamespaceDecl, the order will
|
||||||
/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()).
|
/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()).
|
||||||
///
|
///
|
||||||
/// This scheme guarantees that all Visit*() calls for the same AST
|
/// This scheme guarantees that all Visit*() calls for the same AST
|
||||||
@ -243,8 +244,16 @@ class RecursiveASTVisitor {
|
|||||||
/// \brief Recursively visit a lambda capture.
|
/// \brief Recursively visit a lambda capture.
|
||||||
///
|
///
|
||||||
/// \returns false if the visitation was terminated early, true otherwise.
|
/// \returns false if the visitation was terminated early, true otherwise.
|
||||||
bool TraverseLambdaCapture(LambdaExpr::Capture C);
|
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaExpr::Capture *C);
|
||||||
|
|
||||||
|
/// \brief Recursively visit the body of a lambda expression.
|
||||||
|
///
|
||||||
|
/// This provides a hook for visitors that need more context when visiting
|
||||||
|
/// \c LE->getBody().
|
||||||
|
///
|
||||||
|
/// \returns false if the visitation was terminated early, true otherwise.
|
||||||
|
bool TraverseLambdaBody(LambdaExpr *LE);
|
||||||
|
|
||||||
// ---- Methods on Stmts ----
|
// ---- Methods on Stmts ----
|
||||||
|
|
||||||
// Declare Traverse*() for all concrete Stmt classes.
|
// Declare Traverse*() for all concrete Stmt classes.
|
||||||
@ -342,7 +351,7 @@ class RecursiveASTVisitor {
|
|||||||
// ---- Methods on TypeLocs ----
|
// ---- Methods on TypeLocs ----
|
||||||
// FIXME: this currently just calls the matching Type methods
|
// FIXME: this currently just calls the matching Type methods
|
||||||
|
|
||||||
// Declare Traverse*() for all concrete Type classes.
|
// Declare Traverse*() for all concrete TypeLoc classes.
|
||||||
#define ABSTRACT_TYPELOC(CLASS, BASE)
|
#define ABSTRACT_TYPELOC(CLASS, BASE)
|
||||||
#define TYPELOC(CLASS, BASE) \
|
#define TYPELOC(CLASS, BASE) \
|
||||||
bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
|
bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
|
||||||
@ -398,8 +407,12 @@ class RecursiveASTVisitor {
|
|||||||
private:
|
private:
|
||||||
// These are helper methods used by more than one Traverse* method.
|
// These are helper methods used by more than one Traverse* method.
|
||||||
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
|
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
|
||||||
bool TraverseClassInstantiations(ClassTemplateDecl *D);
|
#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
|
||||||
bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
|
bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D);
|
||||||
|
DEF_TRAVERSE_TMPL_INST(Class)
|
||||||
|
DEF_TRAVERSE_TMPL_INST(Var)
|
||||||
|
DEF_TRAVERSE_TMPL_INST(Function)
|
||||||
|
#undef DEF_TRAVERSE_TMPL_INST
|
||||||
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
||||||
unsigned Count);
|
unsigned Count);
|
||||||
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
||||||
@ -409,6 +422,13 @@ class RecursiveASTVisitor {
|
|||||||
bool TraverseDeclContextHelper(DeclContext *DC);
|
bool TraverseDeclContextHelper(DeclContext *DC);
|
||||||
bool TraverseFunctionHelper(FunctionDecl *D);
|
bool TraverseFunctionHelper(FunctionDecl *D);
|
||||||
bool TraverseVarHelper(VarDecl *D);
|
bool TraverseVarHelper(VarDecl *D);
|
||||||
|
bool TraverseOMPClause(OMPClause *C);
|
||||||
|
#define OPENMP_CLAUSE(Name, Class) \
|
||||||
|
bool Visit##Class(Class *C);
|
||||||
|
#include "clang/Basic/OpenMPKinds.def"
|
||||||
|
/// \brief Process clauses with list of variables.
|
||||||
|
template <typename T>
|
||||||
|
void VisitOMPClauseList(T *Node);
|
||||||
|
|
||||||
struct EnqueueJob {
|
struct EnqueueJob {
|
||||||
Stmt *S;
|
Stmt *S;
|
||||||
@ -802,10 +822,20 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
|
bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(
|
||||||
|
LambdaExpr *LE, const LambdaExpr::Capture *C) {
|
||||||
|
if (C->isInitCapture())
|
||||||
|
TRY_TO(TraverseDecl(C->getCapturedVar()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
|
||||||
|
TRY_TO(TraverseStmt(LE->getBody()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------- Type traversal -----------------
|
// ----------------- Type traversal -----------------
|
||||||
|
|
||||||
// This macro makes available a variable T, the passed-in type.
|
// This macro makes available a variable T, the passed-in type.
|
||||||
@ -844,6 +874,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, {
|
|||||||
TRY_TO(TraverseType(T->getPointeeType()));
|
TRY_TO(TraverseType(T->getPointeeType()));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_TYPE(DecayedType, {
|
||||||
|
TRY_TO(TraverseType(T->getOriginalType()));
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPE(ConstantArrayType, {
|
DEF_TRAVERSE_TYPE(ConstantArrayType, {
|
||||||
TRY_TO(TraverseType(T->getElementType()));
|
TRY_TO(TraverseType(T->getElementType()));
|
||||||
})
|
})
|
||||||
@ -1050,6 +1084,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, {
|
|||||||
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
|
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_TYPELOC(DecayedType, {
|
||||||
|
TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
|
||||||
|
})
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
|
bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
|
||||||
// This isn't available for ArrayType, but is for the ArrayTypeLoc.
|
// This isn't available for ArrayType, but is for the ArrayTypeLoc.
|
||||||
@ -1420,59 +1458,44 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A helper method for traversing the implicit instantiations of a
|
#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
|
||||||
// class template.
|
/* A helper method for traversing the implicit instantiations of a
|
||||||
template<typename Derived>
|
class or variable template. */ \
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
|
template<typename Derived> \
|
||||||
ClassTemplateDecl *D) {
|
bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( \
|
||||||
ClassTemplateDecl::spec_iterator end = D->spec_end();
|
TMPLDECLKIND##TemplateDecl *D) { \
|
||||||
for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
|
TMPLDECLKIND##TemplateDecl::spec_iterator end = D->spec_end(); \
|
||||||
ClassTemplateSpecializationDecl* SD = *it;
|
for (TMPLDECLKIND##TemplateDecl::spec_iterator it = D->spec_begin(); \
|
||||||
|
it != end; ++it) { \
|
||||||
switch (SD->getSpecializationKind()) {
|
TMPLDECLKIND##TemplateSpecializationDecl* SD = *it; \
|
||||||
// Visit the implicit instantiations with the requested pattern.
|
\
|
||||||
case TSK_Undeclared:
|
switch (SD->getSpecializationKind()) { \
|
||||||
case TSK_ImplicitInstantiation:
|
/* Visit the implicit instantiations with the requested pattern. */ \
|
||||||
TRY_TO(TraverseDecl(SD));
|
case TSK_Undeclared: \
|
||||||
break;
|
case TSK_ImplicitInstantiation: \
|
||||||
|
TRY_TO(TraverseDecl(SD)); \
|
||||||
// We don't need to do anything on an explicit instantiation
|
break; \
|
||||||
// or explicit specialization because there will be an explicit
|
\
|
||||||
// node for it elsewhere.
|
/* We don't need to do anything on an explicit instantiation
|
||||||
case TSK_ExplicitInstantiationDeclaration:
|
or explicit specialization because there will be an explicit
|
||||||
case TSK_ExplicitInstantiationDefinition:
|
node for it elsewhere. */ \
|
||||||
case TSK_ExplicitSpecialization:
|
case TSK_ExplicitInstantiationDeclaration: \
|
||||||
break;
|
case TSK_ExplicitInstantiationDefinition: \
|
||||||
}
|
case TSK_ExplicitSpecialization: \
|
||||||
}
|
break; \
|
||||||
|
} \
|
||||||
return true;
|
} \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ClassTemplateDecl, {
|
DEF_TRAVERSE_TMPL_INST(Class)
|
||||||
CXXRecordDecl* TempDecl = D->getTemplatedDecl();
|
DEF_TRAVERSE_TMPL_INST(Var)
|
||||||
TRY_TO(TraverseDecl(TempDecl));
|
|
||||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
|
||||||
|
|
||||||
// By default, we do not traverse the instantiations of
|
|
||||||
// class templates since they do not appear in the user code. The
|
|
||||||
// following code optionally traverses them.
|
|
||||||
//
|
|
||||||
// We only traverse the class instantiations when we see the canonical
|
|
||||||
// declaration of the template, to ensure we only visit them once.
|
|
||||||
if (getDerived().shouldVisitTemplateInstantiations() &&
|
|
||||||
D == D->getCanonicalDecl())
|
|
||||||
TRY_TO(TraverseClassInstantiations(D));
|
|
||||||
|
|
||||||
// Note that getInstantiatedFromMemberTemplate() is just a link
|
|
||||||
// from a template instantiation back to the template from which
|
|
||||||
// it was instantiated, and thus should not be traversed.
|
|
||||||
})
|
|
||||||
|
|
||||||
// A helper method for traversing the instantiations of a
|
// A helper method for traversing the instantiations of a
|
||||||
// function while skipping its specializations.
|
// function while skipping its specializations.
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
|
||||||
FunctionTemplateDecl *D) {
|
FunctionTemplateDecl *D) {
|
||||||
FunctionTemplateDecl::spec_iterator end = D->spec_end();
|
FunctionTemplateDecl::spec_iterator end = D->spec_end();
|
||||||
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
|
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
|
||||||
@ -1500,21 +1523,32 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
|
// This macro unifies the traversal of class, variable and function
|
||||||
TRY_TO(TraverseDecl(D->getTemplatedDecl()));
|
// template declarations.
|
||||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \
|
||||||
|
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \
|
||||||
// By default, we do not traverse the instantiations of
|
TRY_TO(TraverseDecl(D->getTemplatedDecl())); \
|
||||||
// function templates since they do not appear in the user code. The
|
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
|
||||||
// following code optionally traverses them.
|
\
|
||||||
//
|
/* By default, we do not traverse the instantiations of
|
||||||
// We only traverse the function instantiations when we see the canonical
|
class templates since they do not appear in the user code. The
|
||||||
// declaration of the template, to ensure we only visit them once.
|
following code optionally traverses them.
|
||||||
if (getDerived().shouldVisitTemplateInstantiations() &&
|
|
||||||
D == D->getCanonicalDecl())
|
We only traverse the class instantiations when we see the canonical
|
||||||
TRY_TO(TraverseFunctionInstantiations(D));
|
declaration of the template, to ensure we only visit them once. */ \
|
||||||
|
if (getDerived().shouldVisitTemplateInstantiations() && \
|
||||||
|
D == D->getCanonicalDecl()) \
|
||||||
|
TRY_TO(TraverseTemplateInstantiations(D)); \
|
||||||
|
\
|
||||||
|
/* Note that getInstantiatedFromMemberTemplate() is just a link
|
||||||
|
from a template instantiation back to the template from which
|
||||||
|
it was instantiated, and thus should not be traversed. */ \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_TMPL_DECL(Class)
|
||||||
|
DEF_TRAVERSE_TMPL_DECL(Var)
|
||||||
|
DEF_TRAVERSE_TMPL_DECL(Function)
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
|
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
|
||||||
// D is the "T" in something like
|
// D is the "T" in something like
|
||||||
// template <template <typename> class T> class container { };
|
// template <template <typename> class T> class container { };
|
||||||
@ -1607,27 +1641,31 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, {
|
|||||||
TRY_TO(TraverseCXXRecordHelper(D));
|
TRY_TO(TraverseCXXRecordHelper(D));
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
|
#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND) \
|
||||||
// For implicit instantiations ("set<int> x;"), we don't want to
|
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
|
||||||
// recurse at all, since the instatiated class isn't written in
|
/* For implicit instantiations ("set<int> x;"), we don't want to
|
||||||
// the source code anywhere. (Note the instatiated *type* --
|
recurse at all, since the instatiated template isn't written in
|
||||||
// set<int> -- is written, and will still get a callback of
|
the source code anywhere. (Note the instatiated *type* --
|
||||||
// TemplateSpecializationType). For explicit instantiations
|
set<int> -- is written, and will still get a callback of
|
||||||
// ("template set<int>;"), we do need a callback, since this
|
TemplateSpecializationType). For explicit instantiations
|
||||||
// is the only callback that's made for this instantiation.
|
("template set<int>;"), we do need a callback, since this
|
||||||
// We use getTypeAsWritten() to distinguish.
|
is the only callback that's made for this instantiation.
|
||||||
if (TypeSourceInfo *TSI = D->getTypeAsWritten())
|
We use getTypeAsWritten() to distinguish. */ \
|
||||||
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
|
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
|
||||||
|
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
|
||||||
if (!getDerived().shouldVisitTemplateInstantiations() &&
|
\
|
||||||
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
|
if (!getDerived().shouldVisitTemplateInstantiations() && \
|
||||||
// Returning from here skips traversing the
|
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \
|
||||||
// declaration context of the ClassTemplateSpecializationDecl
|
/* Returning from here skips traversing the
|
||||||
// (embedded in the DEF_TRAVERSE_DECL() macro)
|
declaration context of the *TemplateSpecializationDecl
|
||||||
// which contains the instantiated members of the class.
|
(embedded in the DEF_TRAVERSE_DECL() macro)
|
||||||
return true;
|
which contains the instantiated members of the template. */ \
|
||||||
|
return true; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_TMPL_SPEC_DECL(Class)
|
||||||
|
DEF_TRAVERSE_TMPL_SPEC_DECL(Var)
|
||||||
|
|
||||||
template <typename Derived>
|
template <typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
|
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
|
||||||
const TemplateArgumentLoc *TAL, unsigned Count) {
|
const TemplateArgumentLoc *TAL, unsigned Count) {
|
||||||
@ -1637,26 +1675,31 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
|
#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
|
||||||
// The partial specialization.
|
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
|
||||||
if (TemplateParameterList *TPL = D->getTemplateParameters()) {
|
/* The partial specialization. */ \
|
||||||
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
|
if (TemplateParameterList *TPL = D->getTemplateParameters()) { \
|
||||||
I != E; ++I) {
|
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \
|
||||||
TRY_TO(TraverseDecl(*I));
|
I != E; ++I) { \
|
||||||
}
|
TRY_TO(TraverseDecl(*I)); \
|
||||||
}
|
} \
|
||||||
// The args that remains unspecialized.
|
} \
|
||||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
/* The args that remains unspecialized. */ \
|
||||||
D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten()));
|
TRY_TO(TraverseTemplateArgumentLocsHelper( \
|
||||||
|
D->getTemplateArgsAsWritten()->getTemplateArgs(), \
|
||||||
// Don't need the ClassTemplatePartialSpecializationHelper, even
|
D->getTemplateArgsAsWritten()->NumTemplateArgs)); \
|
||||||
// though that's our parent class -- we already visit all the
|
\
|
||||||
// template args here.
|
/* Don't need the *TemplatePartialSpecializationHelper, even
|
||||||
TRY_TO(TraverseCXXRecordHelper(D));
|
though that's our parent class -- we already visit all the
|
||||||
|
template args here. */ \
|
||||||
// Instantiations will have been visited with the primary template.
|
TRY_TO(Traverse##DECLKIND##Helper(D)); \
|
||||||
|
\
|
||||||
|
/* Instantiations will have been visited with the primary template. */ \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Class, CXXRecord)
|
||||||
|
DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Var, Var)
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(EnumConstantDecl, {
|
DEF_TRAVERSE_DECL(EnumConstantDecl, {
|
||||||
TRY_TO(TraverseStmt(D->getInitExpr()));
|
TRY_TO(TraverseStmt(D->getInitExpr()));
|
||||||
})
|
})
|
||||||
@ -1736,6 +1779,14 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
|
|||||||
// including exception specifications.
|
// including exception specifications.
|
||||||
if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
|
if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
|
||||||
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
|
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
|
||||||
|
} else if (getDerived().shouldVisitImplicitCode()) {
|
||||||
|
// Visit parameter variable declarations of the implicit function
|
||||||
|
// if the traverser is visiting implicit code. Parameter variable
|
||||||
|
// declarations do not have valid TypeSourceInfo, so to visit them
|
||||||
|
// we need to traverse the declarations explicitly.
|
||||||
|
for (FunctionDecl::param_const_iterator I = D->param_begin(),
|
||||||
|
E = D->param_end(); I != E; ++I)
|
||||||
|
TRY_TO(TraverseDecl(*I));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
|
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||||
@ -2117,10 +2168,12 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
|
|||||||
// Walk only the visible parts of lambda expressions.
|
// Walk only the visible parts of lambda expressions.
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
||||||
|
TRY_TO(WalkUpFromLambdaExpr(S));
|
||||||
|
|
||||||
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
|
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
|
||||||
CEnd = S->explicit_capture_end();
|
CEnd = S->explicit_capture_end();
|
||||||
C != CEnd; ++C) {
|
C != CEnd; ++C) {
|
||||||
TRY_TO(TraverseLambdaCapture(*C));
|
TRY_TO(TraverseLambdaCapture(S, C));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
|
if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
|
||||||
@ -2140,7 +2193,7 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY_TO(TraverseStmt(S->getBody()));
|
TRY_TO(TraverseLambdaBody(S));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2174,6 +2227,7 @@ DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
|
|||||||
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
|
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
|
||||||
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
|
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
|
||||||
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
|
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
|
||||||
|
DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, { })
|
||||||
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
|
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
|
||||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||||
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
|
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
|
||||||
@ -2211,6 +2265,7 @@ DEF_TRAVERSE_STMT(ParenExpr, { })
|
|||||||
DEF_TRAVERSE_STMT(ParenListExpr, { })
|
DEF_TRAVERSE_STMT(ParenListExpr, { })
|
||||||
DEF_TRAVERSE_STMT(PredefinedExpr, { })
|
DEF_TRAVERSE_STMT(PredefinedExpr, { })
|
||||||
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
|
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
|
||||||
|
DEF_TRAVERSE_STMT(ConvertVectorExpr, { })
|
||||||
DEF_TRAVERSE_STMT(StmtExpr, { })
|
DEF_TRAVERSE_STMT(StmtExpr, { })
|
||||||
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
|
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
|
||||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||||
@ -2269,6 +2324,61 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
|
|||||||
// Traverse OpenCL: AsType, Convert.
|
// Traverse OpenCL: AsType, Convert.
|
||||||
DEF_TRAVERSE_STMT(AsTypeExpr, { })
|
DEF_TRAVERSE_STMT(AsTypeExpr, { })
|
||||||
|
|
||||||
|
// OpenMP directives.
|
||||||
|
DEF_TRAVERSE_STMT(OMPParallelDirective, {
|
||||||
|
ArrayRef<OMPClause *> Clauses = S->clauses();
|
||||||
|
for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
|
||||||
|
I != E; ++I)
|
||||||
|
if (!TraverseOMPClause(*I)) return false;
|
||||||
|
})
|
||||||
|
|
||||||
|
// OpenMP clauses.
|
||||||
|
template<typename Derived>
|
||||||
|
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
|
||||||
|
if (!C) return true;
|
||||||
|
switch (C->getClauseKind()) {
|
||||||
|
#define OPENMP_CLAUSE(Name, Class) \
|
||||||
|
case OMPC_##Name: \
|
||||||
|
return getDerived().Visit##Class(static_cast<Class*>(C));
|
||||||
|
#include "clang/Basic/OpenMPKinds.def"
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *C) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename T>
|
||||||
|
void RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
|
||||||
|
for (typename T::varlist_iterator I = Node->varlist_begin(),
|
||||||
|
E = Node->varlist_end();
|
||||||
|
I != E; ++I)
|
||||||
|
TraverseStmt(*I);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
|
||||||
|
VisitOMPClauseList(C);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
|
||||||
|
OMPFirstprivateClause *C) {
|
||||||
|
VisitOMPClauseList(C);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
|
||||||
|
VisitOMPClauseList(C);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: look at the following tricky-seeming exprs to see if we
|
// FIXME: look at the following tricky-seeming exprs to see if we
|
||||||
// need to recurse on anything. These are ones that have methods
|
// need to recurse on anything. These are ones that have methods
|
||||||
// returning decls or qualtypes or nestednamespecifier -- though I'm
|
// returning decls or qualtypes or nestednamespecifier -- though I'm
|
||||||
|
@ -75,7 +75,7 @@ class Redeclarable {
|
|||||||
|
|
||||||
/// \brief Return the first declaration of this declaration or itself if this
|
/// \brief Return the first declaration of this declaration or itself if this
|
||||||
/// is the only declaration.
|
/// is the only declaration.
|
||||||
decl_type *getFirstDeclaration() {
|
decl_type *getFirstDecl() {
|
||||||
decl_type *D = static_cast<decl_type*>(this);
|
decl_type *D = static_cast<decl_type*>(this);
|
||||||
while (D->getPreviousDecl())
|
while (D->getPreviousDecl())
|
||||||
D = D->getPreviousDecl();
|
D = D->getPreviousDecl();
|
||||||
@ -84,31 +84,29 @@ class Redeclarable {
|
|||||||
|
|
||||||
/// \brief Return the first declaration of this declaration or itself if this
|
/// \brief Return the first declaration of this declaration or itself if this
|
||||||
/// is the only declaration.
|
/// is the only declaration.
|
||||||
const decl_type *getFirstDeclaration() const {
|
const decl_type *getFirstDecl() const {
|
||||||
const decl_type *D = static_cast<const decl_type*>(this);
|
const decl_type *D = static_cast<const decl_type*>(this);
|
||||||
while (D->getPreviousDecl())
|
while (D->getPreviousDecl())
|
||||||
D = D->getPreviousDecl();
|
D = D->getPreviousDecl();
|
||||||
return D;
|
return D;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns true if this is the first declaration.
|
/// \brief True if this is the first declaration in its redeclaration chain.
|
||||||
bool isFirstDeclaration() const {
|
bool isFirstDecl() const { return RedeclLink.NextIsLatest(); }
|
||||||
return RedeclLink.NextIsLatest();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||||
decl_type *getMostRecentDecl() {
|
decl_type *getMostRecentDecl() {
|
||||||
return getFirstDeclaration()->RedeclLink.getNext();
|
return getFirstDecl()->RedeclLink.getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||||
const decl_type *getMostRecentDecl() const {
|
const decl_type *getMostRecentDecl() const {
|
||||||
return getFirstDeclaration()->RedeclLink.getNext();
|
return getFirstDecl()->RedeclLink.getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
|
/// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
|
||||||
/// first and only declaration.
|
/// first and only declaration.
|
||||||
void setPreviousDeclaration(decl_type *PrevDecl);
|
void setPreviousDecl(decl_type *PrevDecl);
|
||||||
|
|
||||||
/// \brief Iterates through all the redeclarations of the same decl.
|
/// \brief Iterates through all the redeclarations of the same decl.
|
||||||
class redecl_iterator {
|
class redecl_iterator {
|
||||||
@ -134,7 +132,7 @@ class Redeclarable {
|
|||||||
redecl_iterator& operator++() {
|
redecl_iterator& operator++() {
|
||||||
assert(Current && "Advancing while iterator has reached end");
|
assert(Current && "Advancing while iterator has reached end");
|
||||||
// Sanity check to avoid infinite loop on invalid redecl chain.
|
// Sanity check to avoid infinite loop on invalid redecl chain.
|
||||||
if (Current->isFirstDeclaration()) {
|
if (Current->isFirstDecl()) {
|
||||||
if (PassedFirst) {
|
if (PassedFirst) {
|
||||||
assert(0 && "Passed first decl twice, invalid redecl chain!");
|
assert(0 && "Passed first decl twice, invalid redecl chain!");
|
||||||
Current = 0;
|
Current = 0;
|
||||||
@ -175,6 +173,40 @@ class Redeclarable {
|
|||||||
friend class ASTDeclWriter;
|
friend class ASTDeclWriter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Get the primary declaration for a declaration from an AST file. That
|
||||||
|
/// will be the first-loaded declaration.
|
||||||
|
Decl *getPrimaryMergedDecl(Decl *D);
|
||||||
|
|
||||||
|
/// \brief Provides common interface for the Decls that cannot be redeclared,
|
||||||
|
/// but can be merged if the same declaration is brought in from multiple
|
||||||
|
/// modules.
|
||||||
|
template<typename decl_type>
|
||||||
|
class Mergeable {
|
||||||
|
public:
|
||||||
|
Mergeable() {}
|
||||||
|
|
||||||
|
/// \brief Return the first declaration of this declaration or itself if this
|
||||||
|
/// is the only declaration.
|
||||||
|
decl_type *getFirstDecl() {
|
||||||
|
decl_type *D = static_cast<decl_type*>(this);
|
||||||
|
if (!D->isFromASTFile())
|
||||||
|
return D;
|
||||||
|
return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Return the first declaration of this declaration or itself if this
|
||||||
|
/// is the only declaration.
|
||||||
|
const decl_type *getFirstDecl() const {
|
||||||
|
const decl_type *D = static_cast<const decl_type*>(this);
|
||||||
|
if (!D->isFromASTFile())
|
||||||
|
return D;
|
||||||
|
return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns true if this is the first declaration.
|
||||||
|
bool isFirstDecl() const { return getFirstDecl() == this; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -266,10 +266,6 @@ class Stmt {
|
|||||||
/// Whether this initializer list originally had a GNU array-range
|
/// Whether this initializer list originally had a GNU array-range
|
||||||
/// designator in it. This is a temporary marker used by CodeGen.
|
/// designator in it. This is a temporary marker used by CodeGen.
|
||||||
unsigned HadArrayRangeDesignator : 1;
|
unsigned HadArrayRangeDesignator : 1;
|
||||||
|
|
||||||
/// Whether this initializer list initializes a std::initializer_list
|
|
||||||
/// object.
|
|
||||||
unsigned InitializesStdInitializerList : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TypeTraitExprBitfields {
|
class TypeTraitExprBitfields {
|
||||||
@ -289,7 +285,7 @@ class Stmt {
|
|||||||
/// \brief The number of arguments to this type trait.
|
/// \brief The number of arguments to this type trait.
|
||||||
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
|
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
// FIXME: this is wasteful on 64-bit platforms.
|
// FIXME: this is wasteful on 64-bit platforms.
|
||||||
void *Aligner;
|
void *Aligner;
|
||||||
@ -316,19 +312,21 @@ class Stmt {
|
|||||||
public:
|
public:
|
||||||
// Only allow allocation of Stmts using the allocator in ASTContext
|
// Only allow allocation of Stmts using the allocator in ASTContext
|
||||||
// or by doing a placement new.
|
// or by doing a placement new.
|
||||||
void* operator new(size_t bytes, ASTContext& C,
|
void* operator new(size_t bytes, const ASTContext& C,
|
||||||
unsigned alignment = 8) throw();
|
unsigned alignment = 8);
|
||||||
|
|
||||||
void* operator new(size_t bytes, ASTContext* C,
|
void* operator new(size_t bytes, const ASTContext* C,
|
||||||
unsigned alignment = 8) throw();
|
unsigned alignment = 8) {
|
||||||
|
return operator new(bytes, *C, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
void* operator new(size_t bytes, void* mem) throw() {
|
void* operator new(size_t bytes, void* mem) throw() {
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete(void*, ASTContext&, unsigned) throw() { }
|
void operator delete(void*, const ASTContext&, unsigned) throw() { }
|
||||||
void operator delete(void*, ASTContext*, unsigned) throw() { }
|
void operator delete(void*, const ASTContext*, unsigned) throw() { }
|
||||||
void operator delete(void*, std::size_t) throw() { }
|
void operator delete(void*, size_t) throw() { }
|
||||||
void operator delete(void*, void*) throw() { }
|
void operator delete(void*, void*) throw() { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -382,7 +380,7 @@ class Stmt {
|
|||||||
|
|
||||||
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
|
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
|
||||||
/// back to its original source language syntax.
|
/// back to its original source language syntax.
|
||||||
void dumpPretty(ASTContext &Context) const;
|
void dumpPretty(const ASTContext &Context) const;
|
||||||
void printPretty(raw_ostream &OS, PrinterHelper *Helper,
|
void printPretty(raw_ostream &OS, PrinterHelper *Helper,
|
||||||
const PrintingPolicy &Policy,
|
const PrintingPolicy &Policy,
|
||||||
unsigned Indentation = 0) const;
|
unsigned Indentation = 0) const;
|
||||||
@ -401,13 +399,6 @@ class Stmt {
|
|||||||
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
|
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// hasImplicitControlFlow - Some statements (e.g. short circuited operations)
|
|
||||||
/// contain implicit control-flow in the order their subexpressions
|
|
||||||
/// are evaluated. This predicate returns true if this statement has
|
|
||||||
/// such implicit control-flow. Such statements are also specially handled
|
|
||||||
/// within CFGs.
|
|
||||||
bool hasImplicitControlFlow() const;
|
|
||||||
|
|
||||||
/// Child Iterators: All subclasses must implement 'children'
|
/// Child Iterators: All subclasses must implement 'children'
|
||||||
/// to permit easy iteration over the substatements/subexpessions of an
|
/// to permit easy iteration over the substatements/subexpessions of an
|
||||||
/// AST node. This permits easy iteration over all nodes in the AST.
|
/// AST node. This permits easy iteration over all nodes in the AST.
|
||||||
@ -553,10 +544,10 @@ class CompoundStmt : public Stmt {
|
|||||||
Stmt** Body;
|
Stmt** Body;
|
||||||
SourceLocation LBracLoc, RBracLoc;
|
SourceLocation LBracLoc, RBracLoc;
|
||||||
public:
|
public:
|
||||||
CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
|
CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
|
||||||
SourceLocation LB, SourceLocation RB);
|
SourceLocation LB, SourceLocation RB);
|
||||||
|
|
||||||
// \brief Build an empty compound statment with a location.
|
// \brief Build an empty compound statement with a location.
|
||||||
explicit CompoundStmt(SourceLocation Loc)
|
explicit CompoundStmt(SourceLocation Loc)
|
||||||
: Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) {
|
: Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) {
|
||||||
CompoundStmtBits.NumStmts = 0;
|
CompoundStmtBits.NumStmts = 0;
|
||||||
@ -568,7 +559,7 @@ class CompoundStmt : public Stmt {
|
|||||||
CompoundStmtBits.NumStmts = 0;
|
CompoundStmtBits.NumStmts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts);
|
void setStmts(const ASTContext &C, Stmt **Stmts, unsigned NumStmts);
|
||||||
|
|
||||||
bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
|
bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
|
||||||
unsigned size() const { return CompoundStmtBits.NumStmts; }
|
unsigned size() const { return CompoundStmtBits.NumStmts; }
|
||||||
@ -827,10 +818,10 @@ class AttributedStmt : public Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static AttributedStmt *Create(ASTContext &C, SourceLocation Loc,
|
static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
|
||||||
ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
|
ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
|
||||||
// \brief Build an empty attributed statement.
|
// \brief Build an empty attributed statement.
|
||||||
static AttributedStmt *CreateEmpty(ASTContext &C, unsigned NumAttrs);
|
static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs);
|
||||||
|
|
||||||
SourceLocation getAttrLoc() const { return AttrLoc; }
|
SourceLocation getAttrLoc() const { return AttrLoc; }
|
||||||
ArrayRef<const Attr*> getAttrs() const {
|
ArrayRef<const Attr*> getAttrs() const {
|
||||||
@ -860,7 +851,7 @@ class IfStmt : public Stmt {
|
|||||||
SourceLocation ElseLoc;
|
SourceLocation ElseLoc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
|
IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
|
||||||
Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
|
Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
|
||||||
|
|
||||||
/// \brief Build an empty if/then/else statement
|
/// \brief Build an empty if/then/else statement
|
||||||
@ -875,7 +866,7 @@ class IfStmt : public Stmt {
|
|||||||
/// }
|
/// }
|
||||||
/// \endcode
|
/// \endcode
|
||||||
VarDecl *getConditionVariable() const;
|
VarDecl *getConditionVariable() const;
|
||||||
void setConditionVariable(ASTContext &C, VarDecl *V);
|
void setConditionVariable(const ASTContext &C, VarDecl *V);
|
||||||
|
|
||||||
/// If this IfStmt has a condition variable, return the faux DeclStmt
|
/// If this IfStmt has a condition variable, return the faux DeclStmt
|
||||||
/// associated with the creation of that condition variable.
|
/// associated with the creation of that condition variable.
|
||||||
@ -933,7 +924,7 @@ class SwitchStmt : public Stmt {
|
|||||||
unsigned AllEnumCasesCovered : 1;
|
unsigned AllEnumCasesCovered : 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond);
|
SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
|
||||||
|
|
||||||
/// \brief Build a empty switch statement.
|
/// \brief Build a empty switch statement.
|
||||||
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
|
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
|
||||||
@ -948,7 +939,7 @@ class SwitchStmt : public Stmt {
|
|||||||
/// }
|
/// }
|
||||||
/// \endcode
|
/// \endcode
|
||||||
VarDecl *getConditionVariable() const;
|
VarDecl *getConditionVariable() const;
|
||||||
void setConditionVariable(ASTContext &C, VarDecl *V);
|
void setConditionVariable(const ASTContext &C, VarDecl *V);
|
||||||
|
|
||||||
/// If this SwitchStmt has a condition variable, return the faux DeclStmt
|
/// If this SwitchStmt has a condition variable, return the faux DeclStmt
|
||||||
/// associated with the creation of that condition variable.
|
/// associated with the creation of that condition variable.
|
||||||
@ -967,9 +958,6 @@ class SwitchStmt : public Stmt {
|
|||||||
SwitchCase *getSwitchCaseList() { return FirstCase; }
|
SwitchCase *getSwitchCaseList() { return FirstCase; }
|
||||||
|
|
||||||
/// \brief Set the case list for this switch statement.
|
/// \brief Set the case list for this switch statement.
|
||||||
///
|
|
||||||
/// The caller is responsible for incrementing the retain counts on
|
|
||||||
/// all of the SwitchCase statements in this list.
|
|
||||||
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
|
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
|
||||||
|
|
||||||
SourceLocation getSwitchLoc() const { return SwitchLoc; }
|
SourceLocation getSwitchLoc() const { return SwitchLoc; }
|
||||||
@ -1021,7 +1009,7 @@ class WhileStmt : public Stmt {
|
|||||||
Stmt* SubExprs[END_EXPR];
|
Stmt* SubExprs[END_EXPR];
|
||||||
SourceLocation WhileLoc;
|
SourceLocation WhileLoc;
|
||||||
public:
|
public:
|
||||||
WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
|
WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
|
||||||
SourceLocation WL);
|
SourceLocation WL);
|
||||||
|
|
||||||
/// \brief Build an empty while statement.
|
/// \brief Build an empty while statement.
|
||||||
@ -1036,7 +1024,7 @@ class WhileStmt : public Stmt {
|
|||||||
/// }
|
/// }
|
||||||
/// \endcode
|
/// \endcode
|
||||||
VarDecl *getConditionVariable() const;
|
VarDecl *getConditionVariable() const;
|
||||||
void setConditionVariable(ASTContext &C, VarDecl *V);
|
void setConditionVariable(const ASTContext &C, VarDecl *V);
|
||||||
|
|
||||||
/// If this WhileStmt has a condition variable, return the faux DeclStmt
|
/// If this WhileStmt has a condition variable, return the faux DeclStmt
|
||||||
/// associated with the creation of that condition variable.
|
/// associated with the creation of that condition variable.
|
||||||
@ -1129,8 +1117,9 @@ class ForStmt : public Stmt {
|
|||||||
SourceLocation LParenLoc, RParenLoc;
|
SourceLocation LParenLoc, RParenLoc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc,
|
ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
|
||||||
Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP);
|
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
|
||||||
|
SourceLocation RP);
|
||||||
|
|
||||||
/// \brief Build an empty for statement.
|
/// \brief Build an empty for statement.
|
||||||
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
|
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
|
||||||
@ -1146,7 +1135,7 @@ class ForStmt : public Stmt {
|
|||||||
/// }
|
/// }
|
||||||
/// \endcode
|
/// \endcode
|
||||||
VarDecl *getConditionVariable() const;
|
VarDecl *getConditionVariable() const;
|
||||||
void setConditionVariable(ASTContext &C, VarDecl *V);
|
void setConditionVariable(const ASTContext &C, VarDecl *V);
|
||||||
|
|
||||||
/// If this ForStmt has a condition variable, return the faux DeclStmt
|
/// If this ForStmt has a condition variable, return the faux DeclStmt
|
||||||
/// associated with the creation of that condition variable.
|
/// associated with the creation of that condition variable.
|
||||||
@ -1417,7 +1406,7 @@ class AsmStmt : public Stmt {
|
|||||||
//===--- Asm String Analysis ---===//
|
//===--- Asm String Analysis ---===//
|
||||||
|
|
||||||
/// Assemble final IR asm string.
|
/// Assemble final IR asm string.
|
||||||
std::string generateAsmString(ASTContext &C) const;
|
std::string generateAsmString(const ASTContext &C) const;
|
||||||
|
|
||||||
//===--- Output operands ---===//
|
//===--- Output operands ---===//
|
||||||
|
|
||||||
@ -1520,7 +1509,7 @@ class GCCAsmStmt : public AsmStmt {
|
|||||||
friend class ASTStmtReader;
|
friend class ASTStmtReader;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
|
GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
|
||||||
bool isvolatile, unsigned numoutputs, unsigned numinputs,
|
bool isvolatile, unsigned numoutputs, unsigned numinputs,
|
||||||
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
|
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
|
||||||
StringLiteral *asmstr, unsigned numclobbers,
|
StringLiteral *asmstr, unsigned numclobbers,
|
||||||
@ -1586,10 +1575,10 @@ class GCCAsmStmt : public AsmStmt {
|
|||||||
/// translation of strings from GCC syntax to LLVM IR syntax, and handles
|
/// translation of strings from GCC syntax to LLVM IR syntax, and handles
|
||||||
//// flattening of named references like %[foo] to Operand AsmStringPiece's.
|
//// flattening of named references like %[foo] to Operand AsmStringPiece's.
|
||||||
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
|
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
|
||||||
ASTContext &C, unsigned &DiagOffs) const;
|
const ASTContext &C, unsigned &DiagOffs) const;
|
||||||
|
|
||||||
/// Assemble final IR asm string.
|
/// Assemble final IR asm string.
|
||||||
std::string generateAsmString(ASTContext &C) const;
|
std::string generateAsmString(const ASTContext &C) const;
|
||||||
|
|
||||||
//===--- Output operands ---===//
|
//===--- Output operands ---===//
|
||||||
|
|
||||||
@ -1649,7 +1638,7 @@ class GCCAsmStmt : public AsmStmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setOutputsAndInputsAndClobbers(ASTContext &C,
|
void setOutputsAndInputsAndClobbers(const ASTContext &C,
|
||||||
IdentifierInfo **Names,
|
IdentifierInfo **Names,
|
||||||
StringLiteral **Constraints,
|
StringLiteral **Constraints,
|
||||||
Stmt **Exprs,
|
Stmt **Exprs,
|
||||||
@ -1695,9 +1684,9 @@ class MSAsmStmt : public AsmStmt {
|
|||||||
friend class ASTStmtReader;
|
friend class ASTStmtReader;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc,
|
MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
|
||||||
bool issimple, bool isvolatile, ArrayRef<Token> asmtoks,
|
SourceLocation lbraceloc, bool issimple, bool isvolatile,
|
||||||
unsigned numoutputs, unsigned numinputs,
|
ArrayRef<Token> asmtoks, unsigned numoutputs, unsigned numinputs,
|
||||||
ArrayRef<StringRef> constraints,
|
ArrayRef<StringRef> constraints,
|
||||||
ArrayRef<Expr*> exprs, StringRef asmstr,
|
ArrayRef<Expr*> exprs, StringRef asmstr,
|
||||||
ArrayRef<StringRef> clobbers, SourceLocation endloc);
|
ArrayRef<StringRef> clobbers, SourceLocation endloc);
|
||||||
@ -1720,7 +1709,7 @@ class MSAsmStmt : public AsmStmt {
|
|||||||
StringRef getAsmString() const { return AsmStr; }
|
StringRef getAsmString() const { return AsmStr; }
|
||||||
|
|
||||||
/// Assemble final IR asm string.
|
/// Assemble final IR asm string.
|
||||||
std::string generateAsmString(ASTContext &C) const;
|
std::string generateAsmString(const ASTContext &C) const;
|
||||||
|
|
||||||
//===--- Output operands ---===//
|
//===--- Output operands ---===//
|
||||||
|
|
||||||
@ -1765,12 +1754,9 @@ class MSAsmStmt : public AsmStmt {
|
|||||||
StringRef getClobber(unsigned i) const { return getClobbers()[i]; }
|
StringRef getClobber(unsigned i) const { return getClobbers()[i]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initialize(ASTContext &C,
|
void initialize(const ASTContext &C, StringRef AsmString,
|
||||||
StringRef AsmString,
|
ArrayRef<Token> AsmToks, ArrayRef<StringRef> Constraints,
|
||||||
ArrayRef<Token> AsmToks,
|
ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers);
|
||||||
ArrayRef<StringRef> Constraints,
|
|
||||||
ArrayRef<Expr*> Exprs,
|
|
||||||
ArrayRef<StringRef> Clobbers);
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
|
SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
|
||||||
@ -1800,7 +1786,7 @@ class SEHExceptStmt : public Stmt {
|
|||||||
explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { }
|
explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SEHExceptStmt* Create(ASTContext &C,
|
static SEHExceptStmt* Create(const ASTContext &C,
|
||||||
SourceLocation ExceptLoc,
|
SourceLocation ExceptLoc,
|
||||||
Expr *FilterExpr,
|
Expr *FilterExpr,
|
||||||
Stmt *Block);
|
Stmt *Block);
|
||||||
@ -1841,7 +1827,7 @@ class SEHFinallyStmt : public Stmt {
|
|||||||
explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { }
|
explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SEHFinallyStmt* Create(ASTContext &C,
|
static SEHFinallyStmt* Create(const ASTContext &C,
|
||||||
SourceLocation FinallyLoc,
|
SourceLocation FinallyLoc,
|
||||||
Stmt *Block);
|
Stmt *Block);
|
||||||
|
|
||||||
@ -1880,10 +1866,8 @@ class SEHTryStmt : public Stmt {
|
|||||||
explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { }
|
explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SEHTryStmt* Create(ASTContext &C,
|
static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry,
|
||||||
bool isCXXTry,
|
SourceLocation TryLoc, Stmt *TryBlock,
|
||||||
SourceLocation TryLoc,
|
|
||||||
Stmt *TryBlock,
|
|
||||||
Stmt *Handler);
|
Stmt *Handler);
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
|
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
|
||||||
@ -2006,13 +1990,13 @@ class CapturedStmt : public Stmt {
|
|||||||
void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; }
|
void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CapturedStmt *Create(ASTContext &Context, Stmt *S,
|
static CapturedStmt *Create(const ASTContext &Context, Stmt *S,
|
||||||
CapturedRegionKind Kind,
|
CapturedRegionKind Kind,
|
||||||
ArrayRef<Capture> Captures,
|
ArrayRef<Capture> Captures,
|
||||||
ArrayRef<Expr *> CaptureInits,
|
ArrayRef<Expr *> CaptureInits,
|
||||||
CapturedDecl *CD, RecordDecl *RD);
|
CapturedDecl *CD, RecordDecl *RD);
|
||||||
|
|
||||||
static CapturedStmt *CreateDeserialized(ASTContext &Context,
|
static CapturedStmt *CreateDeserialized(const ASTContext &Context,
|
||||||
unsigned NumCaptures);
|
unsigned NumCaptures);
|
||||||
|
|
||||||
/// \brief Retrieve the statement being captured.
|
/// \brief Retrieve the statement being captured.
|
||||||
|
@ -79,10 +79,10 @@ class CXXTryStmt : public Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc,
|
static CXXTryStmt *Create(const ASTContext &C, SourceLocation tryLoc,
|
||||||
Stmt *tryBlock, ArrayRef<Stmt*> handlers);
|
Stmt *tryBlock, ArrayRef<Stmt*> handlers);
|
||||||
|
|
||||||
static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty,
|
static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty,
|
||||||
unsigned numHandlers);
|
unsigned numHandlers);
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
|
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define LLVM_CLANG_AST_STMT_ITR_H
|
#define LLVM_CLANG_AST_STMT_ITR_H
|
||||||
|
|
||||||
#include "llvm/Support/DataTypes.h"
|
#include "llvm/Support/DataTypes.h"
|
||||||
|
#include "llvm/Support/Compiler.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@ -28,18 +29,14 @@ class VariableArrayType;
|
|||||||
|
|
||||||
class StmtIteratorBase {
|
class StmtIteratorBase {
|
||||||
protected:
|
protected:
|
||||||
enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3,
|
enum { StmtMode = 0x0, SizeOfTypeVAMode = 0x1, DeclGroupMode = 0x2,
|
||||||
Flags = 0x3 };
|
Flags = 0x3 };
|
||||||
|
|
||||||
Stmt **stmt;
|
Stmt **stmt;
|
||||||
union { Decl *decl; Decl **DGI; };
|
Decl **DGI;
|
||||||
uintptr_t RawVAPtr;
|
uintptr_t RawVAPtr;
|
||||||
Decl **DGE;
|
Decl **DGE;
|
||||||
|
|
||||||
bool inDecl() const {
|
|
||||||
return (RawVAPtr & Flags) == DeclMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool inDeclGroup() const {
|
bool inDeclGroup() const {
|
||||||
return (RawVAPtr & Flags) == DeclGroupMode;
|
return (RawVAPtr & Flags) == DeclGroupMode;
|
||||||
}
|
}
|
||||||
@ -49,7 +46,7 @@ class StmtIteratorBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool inStmt() const {
|
bool inStmt() const {
|
||||||
return (RawVAPtr & Flags) == 0;
|
return (RawVAPtr & Flags) == StmtMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VariableArrayType *getVAPtr() const {
|
const VariableArrayType *getVAPtr() const {
|
||||||
@ -57,7 +54,7 @@ class StmtIteratorBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setVAPtr(const VariableArrayType *P) {
|
void setVAPtr(const VariableArrayType *P) {
|
||||||
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
|
assert (inDeclGroup() || inSizeOfTypeVA());
|
||||||
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,11 +64,10 @@ class StmtIteratorBase {
|
|||||||
|
|
||||||
Stmt*& GetDeclExpr() const;
|
Stmt*& GetDeclExpr() const;
|
||||||
|
|
||||||
StmtIteratorBase(Stmt **s) : stmt(s), decl(0), RawVAPtr(0) {}
|
StmtIteratorBase(Stmt **s) : stmt(s), DGI(0), RawVAPtr(0) {}
|
||||||
StmtIteratorBase(Decl *d, Stmt **s);
|
|
||||||
StmtIteratorBase(const VariableArrayType *t);
|
StmtIteratorBase(const VariableArrayType *t);
|
||||||
StmtIteratorBase(Decl **dgi, Decl **dge);
|
StmtIteratorBase(Decl **dgi, Decl **dge);
|
||||||
StmtIteratorBase() : stmt(0), decl(0), RawVAPtr(0) {}
|
StmtIteratorBase() : stmt(0), DGI(0), RawVAPtr(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -86,7 +82,6 @@ class StmtIteratorImpl : public StmtIteratorBase,
|
|||||||
StmtIteratorImpl() {}
|
StmtIteratorImpl() {}
|
||||||
StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {}
|
StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {}
|
||||||
StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {}
|
StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {}
|
||||||
StmtIteratorImpl(Decl *d, Stmt **s) : StmtIteratorBase(d, s) {}
|
|
||||||
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
|
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
|
||||||
|
|
||||||
DERIVED& operator++() {
|
DERIVED& operator++() {
|
||||||
@ -107,15 +102,15 @@ class StmtIteratorImpl : public StmtIteratorBase,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const DERIVED& RHS) const {
|
bool operator==(const DERIVED& RHS) const {
|
||||||
return stmt == RHS.stmt && decl == RHS.decl && RawVAPtr == RHS.RawVAPtr;
|
return stmt == RHS.stmt && DGI == RHS.DGI && RawVAPtr == RHS.RawVAPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const DERIVED& RHS) const {
|
bool operator!=(const DERIVED& RHS) const {
|
||||||
return stmt != RHS.stmt || decl != RHS.decl || RawVAPtr != RHS.RawVAPtr;
|
return stmt != RHS.stmt || DGI != RHS.DGI || RawVAPtr != RHS.RawVAPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
REFERENCE operator*() const {
|
REFERENCE operator*() const {
|
||||||
return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
|
return inStmt() ? *stmt : GetDeclExpr();
|
||||||
}
|
}
|
||||||
|
|
||||||
REFERENCE operator->() const { return operator*(); }
|
REFERENCE operator->() const { return operator*(); }
|
||||||
@ -131,9 +126,6 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
|||||||
|
|
||||||
StmtIterator(const VariableArrayType *t)
|
StmtIterator(const VariableArrayType *t)
|
||||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||||
|
|
||||||
StmtIterator(Decl* D, Stmt **s = 0)
|
|
||||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(D, s) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||||
@ -156,7 +148,7 @@ struct StmtRange : std::pair<StmtIterator,StmtIterator> {
|
|||||||
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
|
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
|
||||||
|
|
||||||
bool empty() const { return first == second; }
|
bool empty() const { return first == second; }
|
||||||
operator bool() const { return !empty(); }
|
LLVM_EXPLICIT operator bool() const { return !empty(); }
|
||||||
|
|
||||||
Stmt *operator->() const { return first.operator->(); }
|
Stmt *operator->() const { return first.operator->(); }
|
||||||
Stmt *&operator*() const { return first.operator*(); }
|
Stmt *&operator*() const { return first.operator*(); }
|
||||||
@ -199,7 +191,7 @@ struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
|
|||||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||||
|
|
||||||
bool empty() const { return first == second; }
|
bool empty() const { return first == second; }
|
||||||
operator bool() const { return !empty(); }
|
LLVM_EXPLICIT operator bool() const { return !empty(); }
|
||||||
|
|
||||||
const Stmt *operator->() const { return first.operator->(); }
|
const Stmt *operator->() const { return first.operator->(); }
|
||||||
const Stmt *operator*() const { return first.operator*(); }
|
const Stmt *operator*() const { return first.operator*(); }
|
||||||
|
@ -181,13 +181,12 @@ class ObjCAtTryStmt : public Stmt {
|
|||||||
HasFinally(HasFinally) { }
|
HasFinally(HasFinally) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc,
|
static ObjCAtTryStmt *Create(const ASTContext &Context,
|
||||||
Stmt *atTryStmt,
|
SourceLocation atTryLoc, Stmt *atTryStmt,
|
||||||
Stmt **CatchStmts, unsigned NumCatchStmts,
|
Stmt **CatchStmts, unsigned NumCatchStmts,
|
||||||
Stmt *atFinallyStmt);
|
Stmt *atFinallyStmt);
|
||||||
static ObjCAtTryStmt *CreateEmpty(ASTContext &Context,
|
static ObjCAtTryStmt *CreateEmpty(const ASTContext &Context,
|
||||||
unsigned NumCatchStmts,
|
unsigned NumCatchStmts, bool HasFinally);
|
||||||
bool HasFinally);
|
|
||||||
|
|
||||||
/// \brief Retrieve the location of the @ in the \@try.
|
/// \brief Retrieve the location of the @ in the \@try.
|
||||||
SourceLocation getAtTryLoc() const { return AtTryLoc; }
|
SourceLocation getAtTryLoc() const { return AtTryLoc; }
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user