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()
|
||||
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
# Looking for bin/Debug/llvm-tblgen is a complete hack. How can we get
|
||||
if (EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
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?
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
||||
endif()
|
||||
set (PATH_TO_LLVM_CONFIG "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
else()
|
||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
||||
endif()
|
||||
|
||||
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}
|
||||
ABSOLUTE)
|
||||
|
||||
option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install' target." OFF)
|
||||
|
||||
include(AddLLVM)
|
||||
include(TableGen)
|
||||
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}")
|
||||
link_directories("${PATH_TO_LLVM_BUILD}/lib")
|
||||
|
||||
if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
else()
|
||||
# FIXME: This is an utter hack.
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
endif()
|
||||
exec_program("${PATH_TO_LLVM_CONFIG} --bindir" OUTPUT_VARIABLE LLVM_BINARY_DIR)
|
||||
set(LLVM_TABLEGEN_EXE "${LLVM_BINARY_DIR}/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
|
||||
# Define the default arguments to use with 'lit', and an option for the user
|
||||
# to override.
|
||||
@ -90,6 +90,16 @@ if( CLANG_VENDOR )
|
||||
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
|
||||
endif()
|
||||
|
||||
set(CLANG_REPOSITORY_STRING "" CACHE STRING
|
||||
"Vendor-specific text for showing the repository the source is taken from.")
|
||||
|
||||
if(CLANG_REPOSITORY_STRING)
|
||||
add_definitions(-DCLANG_REPOSITORY_STRING="${CLANG_REPOSITORY_STRING}")
|
||||
endif()
|
||||
|
||||
set(CLANG_VENDOR_UTI "org.llvm.clang" CACHE STRING
|
||||
"Vendor-specific uti.")
|
||||
|
||||
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
@ -151,7 +161,7 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
|
||||
endif ()
|
||||
|
||||
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 ()
|
||||
|
||||
configure_file(
|
||||
@ -189,6 +199,41 @@ function(clang_tablegen)
|
||||
endif()
|
||||
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)
|
||||
llvm_process_sources(srcs ${ARGN})
|
||||
if(MSVC_IDE OR XCODE)
|
||||
@ -228,11 +273,18 @@ macro(add_clang_library name)
|
||||
llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
|
||||
target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
|
||||
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")
|
||||
endmacro(add_clang_library)
|
||||
|
||||
@ -246,26 +298,58 @@ include_directories(BEFORE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "*.def"
|
||||
PATTERN "*.h"
|
||||
PATTERN "config.h" EXCLUDE
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "*.def"
|
||||
PATTERN "*.h"
|
||||
PATTERN "config.h" EXCLUDE
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "*.inc"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(DIRECTORY include/clang-c
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*.h"
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
# FIXME: They should be options.
|
||||
add_definitions(-DCLANG_ENABLE_ARCMT -DCLANG_ENABLE_REWRITER -DCLANG_ENABLE_STATIC_ANALYZER)
|
||||
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
|
||||
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
|
||||
set(CLANG_EXECUTABLE_VERSION
|
||||
@ -290,13 +374,17 @@ option(CLANG_INCLUDE_TESTS
|
||||
"Generate build targets for the Clang unit tests."
|
||||
${LLVM_INCLUDE_TESTS})
|
||||
|
||||
# TODO: docs.
|
||||
add_subdirectory(test)
|
||||
|
||||
if( CLANG_INCLUDE_TESTS )
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(unittests)
|
||||
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
|
||||
# FIXME: This could be removed with future version of CMake.
|
||||
if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
|
||||
@ -309,3 +397,5 @@ endif()
|
||||
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
|
||||
"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
|
||||
|
||||
N: Chad Rosier
|
||||
E: mcrosier@apple.com
|
||||
E: mcrosier@codeaurora.org
|
||||
D: MS-inline asm, and the compiler driver
|
||||
|
||||
N: Richard Smith
|
||||
|
@ -266,6 +266,29 @@ def __eq__(self, other):
|
||||
def __ne__(self, 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):
|
||||
return "<SourceRange start %r, end %r>" % (self.start, self.end)
|
||||
|
||||
@ -508,7 +531,7 @@ def name(self):
|
||||
@staticmethod
|
||||
def from_id(id):
|
||||
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]
|
||||
|
||||
@staticmethod
|
||||
@ -721,10 +744,14 @@ def __repr__(self):
|
||||
# A reference to a labeled statement.
|
||||
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.
|
||||
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
|
||||
|
||||
@ -908,6 +935,26 @@ def __repr__(self):
|
||||
# pack.
|
||||
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.
|
||||
#
|
||||
# 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.
|
||||
CursorKind.SEH_FINALLY_STMT = CursorKind(228)
|
||||
|
||||
# A MS inline assembly statement extension.
|
||||
CursorKind.MS_ASM_STMT = CursorKind(229)
|
||||
|
||||
# The null statement.
|
||||
CursorKind.NULL_STMT = CursorKind(230)
|
||||
|
||||
@ -1028,6 +1078,7 @@ def __repr__(self):
|
||||
CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
|
||||
CursorKind.ANNOTATE_ATTR = CursorKind(406)
|
||||
CursorKind.ASM_LABEL_ATTR = CursorKind(407)
|
||||
CursorKind.PACKED_ATTR = CursorKind(408)
|
||||
|
||||
###
|
||||
# Preprocessing
|
||||
@ -1036,6 +1087,12 @@ def __repr__(self):
|
||||
CursorKind.MACRO_INSTANTIATION = CursorKind(502)
|
||||
CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
|
||||
|
||||
###
|
||||
# Extra declaration
|
||||
|
||||
# A module import declaration.
|
||||
CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
|
||||
|
||||
### Cursors ###
|
||||
|
||||
class Cursor(Structure):
|
||||
@ -1282,6 +1339,16 @@ def referenced(self):
|
||||
|
||||
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):
|
||||
"""Return an iterator for accessing the arguments of this cursor."""
|
||||
num_args = conf.lib.clang_Cursor_getNumArguments(self)
|
||||
@ -1450,6 +1517,54 @@ def __repr__(self):
|
||||
TypeKind.FUNCTIONPROTO = TypeKind(111)
|
||||
TypeKind.CONSTANTARRAY = TypeKind(112)
|
||||
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):
|
||||
"""
|
||||
@ -1625,6 +1740,12 @@ def get_array_size(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):
|
||||
"""
|
||||
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))
|
||||
|
||||
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):
|
||||
if type(other) != type(self):
|
||||
return False
|
||||
@ -1918,7 +2051,7 @@ def __del__(self):
|
||||
|
||||
def read(self, path):
|
||||
"""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):
|
||||
"""Load the translation unit from the given source code file by running
|
||||
@ -2590,6 +2723,10 @@ def cursor(self):
|
||||
[Index, c_char_p],
|
||||
c_object_p),
|
||||
|
||||
("clang_CXXMethod_isPureVirtual",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_CXXMethod_isStatic",
|
||||
[Cursor],
|
||||
bool),
|
||||
@ -2973,6 +3110,11 @@ def cursor(self):
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getTypeSpelling",
|
||||
[Type],
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_hashCursor",
|
||||
[Cursor],
|
||||
c_uint),
|
||||
@ -3077,17 +3219,36 @@ def cursor(self):
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_Cursor_getBriefCommentText",
|
||||
[Cursor],
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_Cursor_getRawCommentText",
|
||||
[Cursor],
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_Type_getAlignOf",
|
||||
[Type],
|
||||
c_longlong),
|
||||
|
||||
("clang_Type_getClassType",
|
||||
[Type],
|
||||
Type,
|
||||
Type.from_result),
|
||||
|
||||
("clang_Type_getOffsetOf",
|
||||
[Type, c_char_p],
|
||||
c_longlong),
|
||||
|
||||
("clang_Type_getSizeOf",
|
||||
[Type],
|
||||
c_ulonglong),
|
||||
c_longlong),
|
||||
|
||||
("clang_Type_getCXXRefQualifier",
|
||||
[Type],
|
||||
c_uint),
|
||||
]
|
||||
|
||||
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'
|
||||
|
||||
def test_get_all_kinds():
|
||||
assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds()
|
||||
assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds()
|
||||
kinds = 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():
|
||||
"""Check that every kind classifies to exactly one group."""
|
||||
|
@ -132,6 +132,22 @@ def test_equal():
|
||||
assert a.type != None
|
||||
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():
|
||||
"""Ensure TypeKind.spelling works."""
|
||||
tu = get_tu('int a;')
|
||||
@ -237,12 +253,20 @@ def test_function_variadic():
|
||||
|
||||
def test_element_type():
|
||||
"""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')
|
||||
v = get_cursor(tu, 'v')
|
||||
assert c 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 v.type.kind == TypeKind.VARIABLEARRAY
|
||||
assert v.type.element_type.kind == TypeKind.INT
|
||||
|
||||
@raises(Exception)
|
||||
def test_invalid_element_type():
|
||||
@ -361,3 +385,13 @@ def test_offset():
|
||||
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>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<!-- TODO: Add exception specification. -->
|
||||
<optional>
|
||||
<ref name="Headerfile" />
|
||||
</optional>
|
||||
@ -91,6 +90,9 @@
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Exceptions" />
|
||||
</optional>
|
||||
<zeroOrMore>
|
||||
<ref name="Availability" />
|
||||
</zeroOrMore>
|
||||
@ -410,9 +412,14 @@
|
||||
</data>
|
||||
</element>
|
||||
<optional>
|
||||
<element name="Index">
|
||||
<data type="nonNegativeInteger" />
|
||||
</element>
|
||||
<choice>
|
||||
<element name="Index">
|
||||
<data type="nonNegativeInteger" />
|
||||
</element>
|
||||
<element name="IsVarArg">
|
||||
<empty />
|
||||
</element>
|
||||
</choice>
|
||||
</optional>
|
||||
<element name="Direction">
|
||||
<attribute name="isExplicit">
|
||||
@ -435,6 +442,14 @@
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Exceptions">
|
||||
<element name="Exceptions">
|
||||
<oneOrMore>
|
||||
<ref name="TextBlockContent" />
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Availability">
|
||||
<element name="Availability">
|
||||
<attribute name="distribution">
|
||||
|
@ -16,6 +16,7 @@ following types of bugs:
|
||||
* Use-after-free
|
||||
* Use-after-return (to some extent)
|
||||
* Double-free, invalid free
|
||||
* Memory leaks (experimental)
|
||||
|
||||
Typical slowdown introduced by AddressSanitizer is **2x**.
|
||||
|
||||
@ -114,8 +115,7 @@ function attribute
|
||||
(or a deprecated synonym `no_address_safety_analysis`)
|
||||
to disable instrumentation of a particular function. This attribute may not be
|
||||
supported by other compilers, so we suggest to use it together with
|
||||
``__has_feature(address_sanitizer)``. Note: currently, this attribute will be
|
||||
lost if the function is inlined.
|
||||
``__has_feature(address_sanitizer)``.
|
||||
|
||||
Initialization order checking
|
||||
-----------------------------
|
||||
@ -126,6 +126,42 @@ globals defined in another translation unit. To enable this check at runtime,
|
||||
you should set environment variable
|
||||
``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
|
||||
===================
|
||||
|
||||
|
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
|
||||
|
||||
$ clang-format --help
|
||||
$ clang-format -help
|
||||
OVERVIEW: A tool to format C/C++/Obj-C code.
|
||||
|
||||
If no arguments are specified, it formats the code from standard input
|
||||
and writes the result to the standard output.
|
||||
If <file> is given, it reformats the file. If -i is specified together
|
||||
with <file>, the file is edited in-place. Otherwise, the result is
|
||||
written to the standard output.
|
||||
If <file>s are given, it reformats the files. If -i is specified
|
||||
together with <file>s, the files are edited in-place. Otherwise, the
|
||||
result is written to the standard output.
|
||||
|
||||
USAGE: clang-format [options] [<file>]
|
||||
USAGE: clang-format [options] [<file> ...]
|
||||
|
||||
OPTIONS:
|
||||
-fatal-assembler-warnings - Consider warnings as error
|
||||
-help - Display available options (-help-hidden for more)
|
||||
-i - Inplace edit <file>, if specified.
|
||||
-length=<int> - Format a range of this length, -1 for end of file.
|
||||
-offset=<int> - Format a range starting at this file offset.
|
||||
-stats - Enable statistics output from program
|
||||
-style=<string> - Coding style, currently supports: LLVM, Google, Chromium.
|
||||
-version - Display the version of this program
|
||||
|
||||
Clang-format options:
|
||||
|
||||
-cursor=<uint> - The position of the cursor when invoking
|
||||
clang-format from an editor integration
|
||||
-dump-config - Dump configuration options to stdout and exit.
|
||||
Can be used with -style option.
|
||||
-i - Inplace edit <file>s, if specified.
|
||||
-length=<uint> - Format a range of this length (in bytes).
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -offset and -length pairs.
|
||||
When only a single -offset is specified without
|
||||
-length, clang-format will format up to the end
|
||||
of the file.
|
||||
Can only be used with one input file.
|
||||
-lines=<string> - <start line>:<end line> - format a range of
|
||||
lines (both 1-based).
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -lines arguments.
|
||||
Can't be used with -offset and -length.
|
||||
Can only be used with one input file.
|
||||
-offset=<uint> - Format a range starting at this byte offset.
|
||||
Multiple ranges can be formatted by specifying
|
||||
several -offset and -length pairs.
|
||||
Can only be used with one input file.
|
||||
-output-replacements-xml - Output replacements as XML.
|
||||
-style=<string> - Coding style, currently supports:
|
||||
LLVM, Google, Chromium, Mozilla, WebKit.
|
||||
Use -style=file to load style configuration from
|
||||
.clang-format file located in one of the parent
|
||||
directories of the source file (or current
|
||||
directory for stdin).
|
||||
Use -style="{key: value, ...}" to set specific
|
||||
parameters, e.g.:
|
||||
-style="{BasedOnStyle: llvm, IndentWidth: 8}"
|
||||
|
||||
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
|
||||
@ -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.
|
||||
|
||||
|
||||
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
|
||||
=============================
|
||||
|
||||
@ -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]
|
||||
|
||||
Reformat changed lines in diff
|
||||
Reformat changed lines in diff.
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-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:
|
||||
|
||||
.. 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
|
||||
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
|
||||
according to configurable style guides. To do so, clang-format uses Clang's
|
||||
``Lexer`` to transform an input file into a token stream and then changes all
|
||||
the whitespace around those tokens. The goal is for clang-format to both serve
|
||||
both as a user tool (ideally with powerful IDE integrations) and part of other
|
||||
the whitespace around those tokens. The goal is for clang-format to serve both
|
||||
as a user tool (ideally with powerful IDE integrations) and as part of other
|
||||
refactoring tools, e.g. to do a reformatting of all the lines changed during a
|
||||
renaming.
|
||||
|
||||
@ -125,7 +125,7 @@ Ideas for new Tools
|
||||
``foo`` is a standard container. We could also detect similar patterns for
|
||||
arrays.
|
||||
* ``make_shared`` / ``make_unique`` conversion. Part of this transformation
|
||||
can be incorporated into the ``auto`` transformation. Will convert
|
||||
can be incorporated into the ``auto`` transformation. Will convert
|
||||
|
||||
.. 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.
|
||||
|
||||
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
|
||||
names are inside the ``DeclarationName`` class).
|
||||
that describes what kind of name ``N`` stores. There are 10 options (all of
|
||||
the names are inside the ``DeclarationName`` class).
|
||||
|
||||
``Identifier``
|
||||
|
||||
The name is a simple identifier. Use ``N.getAsIdentifierInfo()`` to retrieve
|
||||
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``
|
||||
|
||||
@ -999,6 +995,21 @@ names are inside the ``DeclarationName`` class).
|
||||
Use ``N.getCXXOverloadedOperator()`` to retrieve the overloaded operator (a
|
||||
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
|
||||
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
|
||||
|
@ -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
|
||||
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
|
||||
============
|
||||
|
||||
@ -27,9 +33,8 @@ Examining the AST
|
||||
=================
|
||||
|
||||
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,
|
||||
which can be enabled with the flags ``-ast-dump`` and ``-ast-dump-xml``. Note
|
||||
that ``-ast-dump-xml`` currently only works with debug builds of clang.
|
||||
at it on some simple example code. Clang has a builtin AST-dump mode,
|
||||
which can be enabled with the flag ``-ast-dump``.
|
||||
|
||||
Let's look at a simple example AST:
|
||||
|
||||
@ -41,40 +46,26 @@ Let's look at a simple example AST:
|
||||
return result;
|
||||
}
|
||||
|
||||
# Clang by default is a frontend for many tools; -cc1 tells it to directly
|
||||
# use the C++ compiler mode. -undef leaves out some internal declarations.
|
||||
$ clang -cc1 -undef -ast-dump-xml test.cc
|
||||
# Clang by default is a frontend for many tools; -Xclang is used to pass
|
||||
# options directly to the C++ frontend.
|
||||
$ clang -Xclang -ast-dump -fsyntax-only test.cc
|
||||
TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
|
||||
... cutting out internal declarations of clang ...
|
||||
<TranslationUnit ptr="0x4871160">
|
||||
<Function ptr="0x48a5800" name="f" prototype="true">
|
||||
<FunctionProtoType ptr="0x4871de0" canonical="0x4871de0">
|
||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
||||
<parameters>
|
||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
||||
</parameters>
|
||||
</FunctionProtoType>
|
||||
<ParmVar ptr="0x4871d80" name="x" initstyle="c">
|
||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
||||
</ParmVar>
|
||||
<Stmt>
|
||||
(CompoundStmt 0x48a5a38 <t2.cc:1:14, line:4:1>
|
||||
(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'))))
|
||||
`-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
|
||||
|-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
|
||||
`-CompoundStmt 0x5aead88 <col:14, line:4:1>
|
||||
|-DeclStmt 0x5aead10 <line:2:3, col:24>
|
||||
| `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
|
||||
| `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
|
||||
| `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
|
||||
| |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
|
||||
| | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
|
||||
| `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
|
||||
`-ReturnStmt 0x5aead68 <line:3:3, col:10>
|
||||
`-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
|
||||
`-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'
|
||||
|
||||
</Stmt>
|
||||
</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
|
||||
The toplevel declaration in
|
||||
a translation unit is always the `translation unit
|
||||
declaration <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_.
|
||||
In this example, our first user written declaration is the `function
|
||||
|
@ -159,12 +159,16 @@ include paths, or 0 otherwise:
|
||||
# include "myinclude.h"
|
||||
#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.
|
||||
#if defined(__has_include) && __has_include("myinclude.h")
|
||||
#if defined(__has_include)
|
||||
#if __has_include("myinclude.h")
|
||||
# include "myinclude.h"
|
||||
#endif
|
||||
|
||||
To test for this feature, use ``#if defined(__has_include)``.
|
||||
#endif
|
||||
|
||||
.. _langext-__has_include_next:
|
||||
|
||||
@ -185,9 +189,11 @@ or 0 otherwise:
|
||||
#endif
|
||||
|
||||
// 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"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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
|
||||
@ -801,8 +807,7 @@ Use ``__has_feature(cxx_contextual_conversions)`` or
|
||||
``__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
|
||||
*new-expression*, the operand of a *delete-expression*, an integral constant
|
||||
expression, or a condition in a ``switch`` statement. Clang does not yet
|
||||
support this feature.
|
||||
expression, or a condition in a ``switch`` statement.
|
||||
|
||||
C++1y decltype(auto)
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
@ -821,9 +826,9 @@ for default initializers in aggregate members is enabled.
|
||||
C++1y generalized lambda capture
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_generalized_capture)`` or
|
||||
``__has_extension(cxx_generalized_capture`` to determine if support for
|
||||
generalized lambda captures is enabled
|
||||
Use ``__has_feature(cxx_init_capture)`` or
|
||||
``__has_extension(cxx_init_capture)`` to determine if support for
|
||||
lambda captures with explicit initializers is enabled
|
||||
(for instance, ``[n(0)] { return ++n; }``).
|
||||
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
|
||||
declarations, local variable modification, and control flow constructs
|
||||
are permitted in ``constexpr`` functions.
|
||||
Clang's implementation of this feature is incomplete.
|
||||
|
||||
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
|
||||
for return type deduction for functions (using ``auto`` as a return type)
|
||||
is enabled.
|
||||
Clang's implementation of this feature is incomplete.
|
||||
|
||||
C++1y runtime-sized arrays
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -918,8 +921,8 @@ enabled.
|
||||
C11 ``_Thread_local``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(c_thread_local)`` to determine if support for
|
||||
``_Thread_local`` variables is enabled.
|
||||
Use ``__has_feature(c_thread_local)`` or ``__has_extension(c_thread_local)``
|
||||
to determine if support for ``_Thread_local`` variables is enabled.
|
||||
|
||||
Checks for Type Traits
|
||||
======================
|
||||
@ -1173,8 +1176,52 @@ of this feature in version of clang being used.
|
||||
|
||||
.. _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
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
=========================
|
||||
|
||||
@ -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
|
||||
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:
|
||||
|
||||
@ -1433,8 +1497,8 @@ for the implementation of various target-specific header files like
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// Identity operation - return 4-element vector V1.
|
||||
__builtin_shufflevector(V1, V1, 0, 1, 2, 3)
|
||||
// identity operation - return 4-element vector v1.
|
||||
__builtin_shufflevector(v1, v1, 0, 1, 2, 3)
|
||||
|
||||
// "Splat" element 0 of V1 into a 4-element result.
|
||||
__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.
|
||||
__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**:
|
||||
|
||||
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
|
||||
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
|
||||
``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
|
||||
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)``.
|
||||
|
||||
``__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``
|
||||
-------------------------
|
||||
|
||||
@ -1526,6 +1638,22 @@ correct code by avoiding expensive loops around
|
||||
implementation details of ``__sync_lock_test_and_set()``. The
|
||||
``__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
|
||||
----------------------------------
|
||||
|
||||
@ -1554,15 +1682,60 @@ The complete list of builtins are:
|
||||
|
||||
.. 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 __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 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 __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 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:
|
||||
|
||||
__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_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
|
||||
=============================
|
||||
|
||||
@ -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
|
||||
attributes <http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html>`_, and
|
||||
`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
|
||||
declaration, which means they must go either at the start of the declaration or
|
||||
immediately after the name being declared.
|
||||
@ -1698,6 +1902,48 @@ Which compiles to (on X86-32):
|
||||
movl %gs:(%eax), %eax
|
||||
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
|
||||
==============================
|
||||
|
||||
@ -1735,8 +1981,8 @@ with :doc:`ThreadSanitizer`.
|
||||
Use ``__attribute__((no_sanitize_thread))`` on a function declaration
|
||||
to specify that checks for data races on plain (non-atomic) memory accesses
|
||||
should not be inserted by ThreadSanitizer.
|
||||
The function may still be instrumented by the tool
|
||||
to avoid false positives in other places.
|
||||
The function is still instrumented by the tool to avoid false positives and
|
||||
provide meaningful stack traces.
|
||||
|
||||
.. _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
|
||||
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
|
||||
====================
|
||||
|
||||
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
|
||||
buffer type matches the passed ``MPI_Datatype``;
|
||||
* for HDF5 library there is a similar usecase as MPI;
|
||||
the buffer type matches the passed ``MPI_Datatype``;
|
||||
* for HDF5 library there is a similar use case to MPI;
|
||||
* checking types of variadic functions' arguments for functions like
|
||||
``fcntl()`` and ``ioctl()``.
|
||||
|
||||
@ -1948,7 +2251,7 @@ accepts a type tag that determines the type of some other argument.
|
||||
applicable type tags.
|
||||
|
||||
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:
|
||||
|
||||
|
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
|
||||
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 directory after building clang-headers, or if the tool is running from
|
||||
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/@DOT@/dot/g' \
|
||||
-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
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
@ -73,10 +78,10 @@ doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
|
||||
|
||||
regendoc:
|
||||
$(Echo) Building doxygen documentation
|
||||
$(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \
|
||||
$(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
|
||||
fi
|
||||
$(Verb) $(RM) -rf $(PROJ_OBJ_DIR)/doxygen
|
||||
$(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
|
||||
$(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.
|
||||
This attribute may not be
|
||||
supported by other compilers, so we suggest to use it together with
|
||||
``__has_feature(memory_sanitizer)``. Note: currently, this attribute will be
|
||||
lost if the function is inlined.
|
||||
``__has_feature(memory_sanitizer)``.
|
||||
|
||||
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
|
||||
===============
|
||||
|
@ -2,13 +2,13 @@
|
||||
Modules
|
||||
=======
|
||||
|
||||
.. warning::
|
||||
The functionality described on this page is supported for C and
|
||||
Objective-C. C++ support is experimental.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
.. warning::
|
||||
The functionality described on this page is still experimental! Please
|
||||
try it out and send us bug reports!
|
||||
|
||||
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):
|
||||
@ -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.
|
||||
|
||||
Import declaration
|
||||
------------------
|
||||
The most direct way to import a module is with an *import declaration*, which imports the named module:
|
||||
Objective-C Import declaration
|
||||
------------------------------
|
||||
Objective-C provides syntax for importing a module via an *@import declaration*, which imports the named module:
|
||||
|
||||
.. 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::
|
||||
|
||||
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.
|
||||
|
||||
.. warning::
|
||||
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.
|
||||
At present, there is no C or C++ syntax for import declarations. Clang
|
||||
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
|
||||
-------------------
|
||||
@ -148,6 +149,8 @@ Module maps are specified as separate files (each named ``module.map``) alongsid
|
||||
.. 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.
|
||||
|
||||
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
|
||||
-----------------
|
||||
@ -165,6 +168,9 @@ Command-line parameters
|
||||
``-fcxx-modules``
|
||||
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>``
|
||||
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>``
|
||||
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
|
||||
===================
|
||||
|
||||
@ -231,8 +246,9 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
|
||||
|
||||
``config_macros`` ``export`` ``module``
|
||||
``conflict`` ``framework`` ``requires``
|
||||
``exclude`` ``header`` ``umbrella``
|
||||
``explicit`` ``link``
|
||||
``exclude`` ``header`` ``private``
|
||||
``explicit`` ``link`` ``umbrella``
|
||||
``extern`` ``use``
|
||||
|
||||
Module map file
|
||||
---------------
|
||||
@ -258,6 +274,7 @@ A module declaration describes a module, including the headers that contribute t
|
||||
|
||||
*module-declaration*:
|
||||
``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.
|
||||
|
||||
@ -286,10 +303,13 @@ Modules can have a number of different kinds of members, each of which is descri
|
||||
*umbrella-dir-declaration*
|
||||
*submodule-declaration*
|
||||
*export-declaration*
|
||||
*use-declaration*
|
||||
*link-declaration*
|
||||
*config-macros-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
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
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*
|
||||
|
||||
*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:
|
||||
|
||||
@ -360,6 +383,7 @@ A header declaration specifies that a particular header is associated with the e
|
||||
|
||||
*header-declaration*:
|
||||
``umbrella``:sub:`opt` ``header`` *string-literal*
|
||||
``private`` ``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.
|
||||
@ -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
|
||||
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.
|
||||
|
||||
**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.,
|
||||
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
|
||||
~~~~~~~~~~~~~~~~
|
||||
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
|
||||
``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
|
||||
==================
|
||||
|
||||
|
@ -1,40 +1,56 @@
|
||||
=======================
|
||||
Clang 3.3 Release Notes
|
||||
Clang 3.4 Release Notes
|
||||
=======================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
Written by the `LLVM Team <http://llvm.org/>`_
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
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
|
||||
describe the status of Clang in some detail, including major improvements from
|
||||
the previous release and new feature work. For the general LLVM release notes,
|
||||
see `the LLVM documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
|
||||
releases may be downloaded from the `LLVM releases web site
|
||||
<http://llvm.org/releases/>`_.
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.4. Here we
|
||||
describe the status of Clang in some detail, including major
|
||||
improvements from the previous release and new feature work. For the
|
||||
general LLVM release notes, see `the LLVM
|
||||
documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
|
||||
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
|
||||
release, please check out the main please see the `Clang Web Site
|
||||
<http://clang.llvm.org>`_ or the `LLVM Web Site <http://llvm.org>`_.
|
||||
For more information about Clang or LLVM, including information about
|
||||
the latest release, please check out the main `Clang Web
|
||||
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
|
||||
Clang web page, this document applies to the *next* release, not the current
|
||||
one. To see the release notes for a specific release, please see the `releases
|
||||
page <http://llvm.org/releases/>`_.
|
||||
Note that if you are reading this file from a Subversion checkout or the
|
||||
main Clang web page, this document applies to the *next* release, not
|
||||
the current one. To see the release notes for a specific release, please
|
||||
see the `releases page <http://llvm.org/releases/>`_.
|
||||
|
||||
What's New in Clang 3.3?
|
||||
What's New in Clang 3.4?
|
||||
========================
|
||||
|
||||
Some of the major new features and improvements to Clang are listed
|
||||
here. Generic improvements to Clang as a whole or to its underlying
|
||||
infrastructure are described first, followed by language-specific sections with
|
||||
improvements to Clang's support for those languages.
|
||||
infrastructure are described first, followed by language-specific
|
||||
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
|
||||
------------------
|
||||
@ -44,90 +60,210 @@ Improvements to Clang's diagnostics
|
||||
|
||||
Clang's diagnostics are constantly being improved to catch more issues,
|
||||
explain them more clearly, and provide more accurate source information
|
||||
about them. The improvements since the 3.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++.
|
||||
This feature allows identifiers to contain certain Unicode characters, as
|
||||
specified by the active language standard; these characters can be written
|
||||
directly in the source file using the UTF-8 encoding, or referred to using
|
||||
*universal character names* (``\u00E0``, ``\U000000E0``).
|
||||
.. code-block:: c
|
||||
|
||||
#ifndef multiple
|
||||
#define multi
|
||||
#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
|
||||
---------------------------
|
||||
|
||||
- Added new checked arithmetic builtins for security critical applications.
|
||||
|
||||
C++ Language Changes in Clang
|
||||
-----------------------------
|
||||
|
||||
- Clang now correctly implements language linkage for functions and variables.
|
||||
This means that, for example, it is now possible to overload static functions
|
||||
declared in an ``extern "C"`` context. For backwards compatibility, an alias
|
||||
with the unmangled name is still emitted if it is the only one and has the
|
||||
``used`` attribute.
|
||||
- Fixed an ABI regression, introduced in Clang 3.2, which affected
|
||||
member offsets for classes inheriting from certain classes with tail padding.
|
||||
See PR16537.
|
||||
|
||||
- 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
|
||||
--------------------
|
||||
|
||||
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,
|
||||
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
|
||||
misusing the llvm::cast machinery to perform undefined operations. Their APIs
|
||||
have been changed to use two member function templates that return values
|
||||
instead of pointers or references - "T castAs" and "Optional<T> getAs" (in the
|
||||
case of the TypeLoc hierarchy the latter is "T getAs" and you can use the
|
||||
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.
|
||||
The ASTContext class now keeps track of two different types for wide character
|
||||
types: WCharTy and WideCharTy. WCharTy represents the built-in wchar_t type
|
||||
available in C++. WideCharTy is the type used for wide character literals; in
|
||||
C++ it is the same as WCharTy, but in C99, where wchar_t is a typedef, it is an
|
||||
integer type.
|
||||
|
||||
Static Analyzer
|
||||
---------------
|
||||
|
||||
The static analyzer (which contains additional code checking beyond compiler
|
||||
warnings) has improved significantly in both in the core analysis engine and
|
||||
also in the kinds of issues it can find.
|
||||
The static analyzer has been greatly improved. This impacts the overall analyzer quality and reduces a number of false positives.
|
||||
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.
|
||||
|
||||
Core Analysis Improvements
|
||||
==========================
|
||||
Clang Format
|
||||
------------
|
||||
|
||||
- Support for interprocedural reasoning about constructors and destructors.
|
||||
- New false positive suppression mechanisms that reduced the number of false
|
||||
null pointer dereference warnings due to interprocedural analysis.
|
||||
- Major performance enhancements to speed up interprocedural analysis
|
||||
Clang now includes a new tool ``clang-format`` which can be used to
|
||||
automatically format C, C++ and Objective-C source code. ``clang-format``
|
||||
automatically chooses linebreaks and indentation and can be easily integrated
|
||||
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'.
|
||||
- Detection of mismatched allocators and deallocators (e.g., using 'new' with
|
||||
'free()', 'malloc()' with 'delete').
|
||||
- Additional checks for misuses of Apple Foundation framework collection APIs.
|
||||
- `clang-cl <UsersManual.html#clang-cl>`_ provides a new driver mode that is
|
||||
designed for compatibility with Visual Studio's compiler, cl.exe. This driver
|
||||
mode makes Clang accept the same kind of command-line options as cl.exe. The
|
||||
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
|
||||
==========================
|
||||
@ -135,11 +271,13 @@ Significant Known Problems
|
||||
Additional Information
|
||||
======================
|
||||
|
||||
A wide variety of additional information is available on the `Clang web page
|
||||
<http://clang.llvm.org/>`_. The web page contains versions of the API
|
||||
documentation which are up-to-date with the Subversion version of the source
|
||||
code. You can access versions of these documents specific to this release by
|
||||
going into the "``clang/docs/``" directory in the Clang tree.
|
||||
A wide variety of additional information is available on the `Clang web
|
||||
page <http://clang.llvm.org/>`_. The web page contains versions of the
|
||||
API documentation which are up-to-date with the Subversion revision of
|
||||
the source code. You can access versions of these documents specific to
|
||||
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
|
||||
us via the `mailing list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_.
|
||||
If you have any questions or comments about Clang, please feel free to
|
||||
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
|
||||
:ref:`no_sanitize_thread <langext-thread_sanitizer>`
|
||||
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
|
||||
supported by other compilers, so we suggest to use it together with
|
||||
``__has_feature(thread_sanitizer)``. Note: currently, this attribute will be
|
||||
lost if the function is inlined.
|
||||
``__has_feature(thread_sanitizer)``.
|
||||
|
||||
Blacklist
|
||||
---------
|
||||
|
||||
ThreadSanitizer supports ``src`` and ``fun`` entity types in
|
||||
:doc:`SanitizerSpecialCaseList`, that can be used to suppress data race reports in
|
||||
the specified source files or functions. Unlike functions marked with
|
||||
:ref:`no_sanitize_thread <langext-thread_sanitizer>` attribute,
|
||||
blacklisted functions are not instrumented at all. This can lead to false positives
|
||||
due to missed synchronization via atomic operations and missed stack frames in reports.
|
||||
|
||||
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
|
||||
compatible with the GNU GCC compiler as reasonably possible, easing
|
||||
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
|
||||
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
|
||||
|
||||
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<
|
||||
[float != float],
|
||||
[float != double],
|
||||
[...]>>>
|
||||
|
||||
.. _cl_diag_warning_groups:
|
||||
@ -853,7 +860,7 @@ Controlling Code Generation
|
||||
Clang provides a number of ways to control code generation. The options
|
||||
are listed below.
|
||||
|
||||
**-fsanitize=check1,check2,...**
|
||||
**-f[no-]sanitize=check1,check2,...**
|
||||
Turn on runtime checks for various forms of undefined or suspicious
|
||||
behavior.
|
||||
|
||||
@ -889,13 +896,14 @@ are listed below.
|
||||
includes all of the checks listed below other than
|
||||
``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
|
||||
runtime support. This group of sanitizers are generally used
|
||||
in conjunction with the ``-fsanitize-undefined-trap-on-error``
|
||||
flag, which causes traps to be emitted, rather than calls to
|
||||
runtime libraries. This includes all of the checks listed below
|
||||
other than ``unsigned-integer-overflow`` and ``vptr``.
|
||||
runtime support. This group of sanitizers is intended to be
|
||||
used in conjunction with the ``-fsanitize-undefined-trap-on-error``
|
||||
flag. This includes all of the checks listed below 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:
|
||||
|
||||
@ -913,6 +921,8 @@ are listed below.
|
||||
destination.
|
||||
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
||||
zero.
|
||||
- ``-fsanitize=function``: Indirect call of a function through a
|
||||
function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
|
||||
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
|
||||
- ``-fsanitize=null``: Use of a null pointer or creation of a null
|
||||
reference.
|
||||
@ -941,6 +951,15 @@ are listed below.
|
||||
it is of the wrong dynamic type, or that its lifetime has not
|
||||
begun or has ended. Incompatible with ``-fno-rtti``.
|
||||
|
||||
You can turn off or modify checks for certain source files, functions
|
||||
or even variables by providing a special file:
|
||||
|
||||
- ``-fsanitize-blacklist=/path/to/blacklist/file``: disable or modify
|
||||
sanitizer checks for objects listed in the file. See
|
||||
:doc:`SanitizerSpecialCaseList` for file format description.
|
||||
- ``-fno-sanitize-blacklist``: don't use blacklist file, if it was
|
||||
specified earlier in the command line.
|
||||
|
||||
Experimental features of AddressSanitizer (not ready for widespread
|
||||
use, require explicit ``-fsanitize=address``):
|
||||
|
||||
@ -958,10 +977,31 @@ are listed below.
|
||||
uninitialized bits came from. Slows down execution by additional
|
||||
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
|
||||
order to link to the appropriate runtime library. It is not possible
|
||||
to combine the ``-fsanitize=address`` and ``-fsanitize=thread``
|
||||
checkers in the same program.
|
||||
order to link to the appropriate runtime library. When using
|
||||
``-fsanitize=vptr`` (or a group that includes it, such as
|
||||
``-fsanitize=undefined``) with a C++ program, the link must be
|
||||
performed by ``clang++``, not ``clang``, in order to link against the
|
||||
C++-specific parts of the runtime library.
|
||||
|
||||
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**
|
||||
Deprecated synonym for :ref:`-f[no-]sanitize=address
|
||||
<opt_fsanitize_address>`.
|
||||
@ -1007,6 +1047,26 @@ are listed below.
|
||||
efficient model can be used. The TLS model can be overridden per
|
||||
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
|
||||
-------------------------------------
|
||||
|
||||
@ -1178,30 +1238,40 @@ Microsoft extensions
|
||||
--------------------
|
||||
|
||||
clang has some experimental support for extensions from Microsoft Visual
|
||||
C++; to enable it, use the -fms-extensions command-line option. This is
|
||||
the default for Windows targets. Note that the support is incomplete;
|
||||
enabling Microsoft extensions will silently drop certain constructs
|
||||
(including ``__declspec`` and Microsoft-style asm statements).
|
||||
C++; to enable it, use the ``-fms-extensions`` command-line option. This is
|
||||
the default for Windows targets. Note that the support is incomplete.
|
||||
Some constructs such as ``dllexport`` on classes are ignored with a warning,
|
||||
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
|
||||
invalid C++ to be able to parse most Microsoft headers. This flag is
|
||||
enabled by default for Windows targets.
|
||||
clang has a ``-fms-compatibility`` flag that makes clang accept enough
|
||||
invalid C++ to be able to parse most Microsoft headers. For example, it
|
||||
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
|
||||
until the end of a translation unit. This flag is enabled by default for
|
||||
Windows targets.
|
||||
``-fdelayed-template-parsing`` lets clang delay parsing of function template
|
||||
definitions until the end of a translation unit. This flag is enabled by
|
||||
default for Windows targets.
|
||||
|
||||
- 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
|
||||
can compile. This option will be removed when clang supports the full
|
||||
set of MS extensions required for these headers.
|
||||
can compile.
|
||||
- clang does not support the Microsoft extension where anonymous record
|
||||
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
|
||||
where MSVC and GCC are incompatible clang follows the MSVC
|
||||
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.
|
||||
|
||||
.. _cxx:
|
||||
@ -1210,8 +1280,8 @@ C++ Language Features
|
||||
=====================
|
||||
|
||||
clang fully implements all of standard C++98 except for exported
|
||||
templates (which were removed in C++11), and `many C++11
|
||||
features <http://clang.llvm.org/cxx_status.html>`_ are also implemented.
|
||||
templates (which were removed in C++11), and all of standard C++11
|
||||
and the current draft standard for C++1y.
|
||||
|
||||
Controlling implementation limits
|
||||
---------------------------------
|
||||
@ -1229,7 +1299,12 @@ Controlling implementation limits
|
||||
.. option:: -ftemplate-depth=N
|
||||
|
||||
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:
|
||||
|
||||
@ -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++
|
||||
codebases.
|
||||
|
||||
On ``x86_64-mingw32``, passing i128(by value) is incompatible to Microsoft
|
||||
x64 calling conversion. You might need to tweak
|
||||
On ``x86_64-mingw32``, passing i128(by value) is incompatible with the
|
||||
Microsoft x64 calling conversion. You might need to tweak
|
||||
``WinX86_64ABIInfo::classify()`` in lib/CodeGen/TargetInfo.cpp.
|
||||
|
||||
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
|
||||
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
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
clang currently contains some support for PPC and Sparc; however,
|
||||
significant pieces of code generation are still missing, and they
|
||||
clang currently contains some support for other architectures (e.g. Sparc);
|
||||
however, significant pieces of code generation are still missing, and they
|
||||
haven't undergone significant testing.
|
||||
|
||||
clang contains limited support for the MSP430 embedded processor, but
|
||||
@ -1302,9 +1385,10 @@ None
|
||||
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
|
||||
""""""
|
||||
@ -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
|
||||
``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
|
||||
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
|
||||
=============
|
||||
@ -121,6 +125,19 @@ ExprInspection checks
|
||||
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
|
||||
==========
|
||||
|
@ -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
|
||||
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
|
||||
default.
|
||||
|
@ -48,9 +48,9 @@
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '3.3'
|
||||
version = '3.4'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '3.3'
|
||||
release = '3.4'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -48,9 +48,9 @@
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '3.3'
|
||||
version = '3.4'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '3.3'
|
||||
release = '3.4'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -1224,7 +1224,30 @@ DOT_CLEANUP = YES
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||
# used. If set to NO the values of all tags below this one will be ignored.
|
||||
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
|
||||
# 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>
|
||||
<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>
|
||||
|
||||
<p class="footer">
|
||||
|
@ -18,9 +18,13 @@ Using Clang as a Compiler
|
||||
|
||||
UsersManual
|
||||
LanguageExtensions
|
||||
CrossCompilation
|
||||
AddressSanitizer
|
||||
ThreadSanitizer
|
||||
MemorySanitizer
|
||||
DataFlowSanitizer
|
||||
LeakSanitizer
|
||||
SanitizerSpecialCaseList
|
||||
Modules
|
||||
FAQ
|
||||
|
||||
@ -51,6 +55,7 @@ Using Clang Tools
|
||||
ClangTools
|
||||
ClangCheck
|
||||
ClangFormat
|
||||
ClangFormatStyleOptions
|
||||
|
||||
Design Documents
|
||||
================
|
||||
|
@ -7,7 +7,7 @@ clang - the Clang C, C++, and Objective-C compiler
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
|
||||
[B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-Oz>|B<-O3>|B<-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<-I>I<dir...> B<-L>I<dir...>
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
linker is run to combine the results into an executable or shared library.
|
||||
|
||||
=item B<--analyze>
|
||||
|
||||
Run the Clang Static Analyzer.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
@ -263,20 +260,52 @@ may not exist on earlier ones.
|
||||
|
||||
=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
|
||||
level compiles the fastest and generates the most debuggable code. B<-O2> is a
|
||||
moderate level of optimization which enables most optimizations. B<-Os> is like
|
||||
B<-O2> with extra optimizations to reduce code size. B<-Oz> is like B<-Os>
|
||||
(and thus B<-O2>), but reduces code size further. B<-O3> is like B<-O2>,
|
||||
except that it enables optimizations that take longer to perform or that may
|
||||
generate larger code (in an attempt to make the program run faster).
|
||||
B<-Ofast> enables all the optimizations from B<-O3> along with other aggressive
|
||||
optimizations that may violate strict compliance with language standards. On
|
||||
supported platforms, B<-O4> enables link-time optimization; object files are
|
||||
stored in the LLVM bitcode file format and whole program optimization is done at
|
||||
link time. B<-O1> is somewhere between B<-O0> and B<-O2>.
|
||||
Specify which optimization level to use:
|
||||
|
||||
=over
|
||||
|
||||
=item B<-O0>
|
||||
|
||||
Means "no optimization": this level compiles the fastest and
|
||||
generates the most debuggable code.
|
||||
|
||||
=item B<-O1>
|
||||
|
||||
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>
|
||||
|
||||
|
@ -154,20 +154,25 @@ def act_on_decl(declaration, comment, allowed_types):
|
||||
inner, name = m.groups()
|
||||
add_matcher('Type', name, 'Matcher<%s>...' % inner,
|
||||
comment, is_dyncast=True)
|
||||
add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
|
||||
comment, is_dyncast=True)
|
||||
# FIXME: re-enable once we have implemented casting on the TypeLoc
|
||||
# hierarchy.
|
||||
# add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
|
||||
# comment, is_dyncast=True)
|
||||
return
|
||||
|
||||
m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
|
||||
\s*([^\s,]+\s*),
|
||||
\s*(?:[^\s,]+\s*)
|
||||
\s*(?:[^\s,]+\s*),
|
||||
\s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
|
||||
\)\s*;\s*$""", declaration, flags=re.X)
|
||||
if m:
|
||||
loc = m.group(1)
|
||||
name = m.group(2)
|
||||
result_types = extract_result_types(comment)
|
||||
if not result_types:
|
||||
raise Exception('Did not find allowed result types for: %s' % name)
|
||||
loc, name, n_results, results = m.groups()[0:4]
|
||||
result_types = [r.strip() for r in results.split(',')]
|
||||
|
||||
comment_result_types = extract_result_types(comment)
|
||||
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:
|
||||
add_matcher(result_type, name, 'Matcher<Type>', comment)
|
||||
if loc:
|
||||
@ -175,7 +180,31 @@ def act_on_decl(declaration, comment, allowed_types):
|
||||
comment)
|
||||
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*
|
||||
@ -185,8 +214,8 @@ def act_on_decl(declaration, comment, allowed_types):
|
||||
(?:,\s*\d+\s*)?
|
||||
\)\s*{\s*$""", declaration, flags=re.X)
|
||||
if m:
|
||||
p, n, result, name = m.groups()[1:5]
|
||||
args = m.groups()[5:]
|
||||
p, n, result, name = m.groups()[0:4]
|
||||
args = m.groups()[4:]
|
||||
if not result:
|
||||
if not allowed_types:
|
||||
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)
|
||||
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:
|
||||
# Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
|
||||
m = re.match(r"""^\s*(.*)\s+
|
||||
@ -270,7 +319,7 @@ def sort_table(matcher_type, matcher_map):
|
||||
declaration += ' ' + line
|
||||
if ((not line.strip()) or
|
||||
line.rstrip()[-1] == ';' or
|
||||
line.rstrip()[-1] == '{'):
|
||||
(line.rstrip()[-1] == '{' and line.rstrip()[-3:] != '= {')):
|
||||
if line.strip() and line.rstrip()[-1] == '{':
|
||||
body = True
|
||||
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.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
linker selectiondag asmparser instrumentation
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter irreader \
|
||||
ipo linker selectiondag asmparser instrumentation option
|
||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
||||
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
|
||||
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
@ -34,11 +35,11 @@ using namespace clang::driver;
|
||||
// GetMainExecutable (since some platforms don't support taking the
|
||||
// address of main, and some platforms can't implement GetMainExecutable
|
||||
// without being given the address of a function in the main executable).
|
||||
llvm::sys::Path GetExecutablePath(const char *Argv0) {
|
||||
std::string GetExecutablePath(const char *Argv0) {
|
||||
// This just needs to be some symbol in the binary; C++ doesn't
|
||||
// allow taking the address of ::main however.
|
||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
|
||||
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
|
||||
}
|
||||
|
||||
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) {
|
||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||
llvm::sys::Path Path = GetExecutablePath(argv[0]);
|
||||
std::string Path = GetExecutablePath(argv[0]);
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
TextDiagnosticPrinter *DiagClient =
|
||||
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
||||
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
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");
|
||||
|
||||
// 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())) {
|
||||
SmallString<256> 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();
|
||||
return 1;
|
||||
}
|
||||
@ -117,7 +118,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
// Show the invocation, with -v.
|
||||
if (CI->getHeaderSearchOpts().Verbose) {
|
||||
llvm::errs() << "clang invocation:\n";
|
||||
C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
|
||||
Jobs.Print(llvm::errs(), "\n", true);
|
||||
llvm::errs() << "\n";
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ typedef void * CXCompileCommand;
|
||||
*/
|
||||
typedef enum {
|
||||
/*
|
||||
* \brief No error occured
|
||||
* \brief No error occurred
|
||||
*/
|
||||
CXCompilationDatabase_NoError = 0,
|
||||
|
||||
@ -141,6 +141,24 @@ clang_CompileCommand_getNumArgs(CXCompileCommand);
|
||||
CINDEX_LINKAGE CXString
|
||||
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);
|
||||
|
||||
/**
|
||||
* \brief Free the given string,
|
||||
* \brief Free the given string.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_disposeString(CXString string);
|
||||
|
||||
|
@ -16,9 +16,7 @@
|
||||
#ifndef CLANG_C_INDEX_H
|
||||
#define CLANG_C_INDEX_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "clang-c/Platform.h"
|
||||
#include "clang-c/CXString.h"
|
||||
@ -32,7 +30,7 @@
|
||||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||
*/
|
||||
#define CINDEX_VERSION_MAJOR 0
|
||||
#define CINDEX_VERSION_MINOR 19
|
||||
#define CINDEX_VERSION_MINOR 20
|
||||
|
||||
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
||||
((major) * 10000) \
|
||||
@ -413,6 +411,12 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -723,7 +727,7 @@ CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
|
||||
* \brief Retrieve the child diagnostics of a CXDiagnostic.
|
||||
*
|
||||
* This CXDiagnosticSet does not need to be released by
|
||||
* clang_diposeDiagnosticSet.
|
||||
* clang_disposeDiagnosticSet.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* 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 {
|
||||
/**
|
||||
@ -850,7 +854,7 @@ CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic,
|
||||
* default behavior of the clang compiler.
|
||||
*
|
||||
* \returns A set of display options suitable for use with \c
|
||||
* clang_displayDiagnostic().
|
||||
* clang_formatDiagnostic().
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
|
||||
|
||||
@ -1942,7 +1946,7 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_CompoundStmt = 202,
|
||||
|
||||
/** \brief A case statment.
|
||||
/** \brief A case statement.
|
||||
*/
|
||||
CXCursor_CaseStmt = 203,
|
||||
|
||||
@ -2062,7 +2066,11 @@ enum CXCursorKind {
|
||||
*/
|
||||
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.
|
||||
@ -2087,7 +2095,8 @@ enum CXCursorKind {
|
||||
CXCursor_CXXOverrideAttr = 405,
|
||||
CXCursor_AnnotateAttr = 406,
|
||||
CXCursor_AsmLabelAttr = 407,
|
||||
CXCursor_LastAttr = CXCursor_AsmLabelAttr,
|
||||
CXCursor_PackedAttr = 408,
|
||||
CXCursor_LastAttr = CXCursor_PackedAttr,
|
||||
|
||||
/* Preprocessing */
|
||||
CXCursor_PreprocessingDirective = 500,
|
||||
@ -2666,7 +2675,11 @@ enum CXTypeKind {
|
||||
CXType_FunctionNoProto = 110,
|
||||
CXType_FunctionProto = 111,
|
||||
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_PnaclCall = 8,
|
||||
CXCallingConv_IntelOclBicc = 9,
|
||||
CXCallingConv_X86_64Win64 = 10,
|
||||
CXCallingConv_X86_64SysV = 11,
|
||||
|
||||
CXCallingConv_Invalid = 100,
|
||||
CXCallingConv_Unexposed = 200
|
||||
@ -2954,6 +2969,13 @@ enum CXTypeLayoutError {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@ -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);
|
||||
|
||||
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
|
||||
* bitfield.
|
||||
@ -3413,6 +3452,13 @@ typedef enum {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -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
|
||||
* declared 'static'.
|
||||
|
@ -97,6 +97,8 @@ class MigrationProcess {
|
||||
FileRemapper Remapper;
|
||||
|
||||
public:
|
||||
bool HadARCErrors;
|
||||
|
||||
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
|
@ -57,14 +57,12 @@ class MigrateAction : public WrapperFrontendAction {
|
||||
/// \brief Migrates to modern ObjC syntax.
|
||||
class ObjCMigrateAction : public WrapperFrontendAction {
|
||||
std::string MigrateDir;
|
||||
bool MigrateLiterals;
|
||||
bool MigrateSubscripting;
|
||||
unsigned ObjCMigAction;
|
||||
FileRemapper Remapper;
|
||||
CompilerInstance *CompInst;
|
||||
public:
|
||||
ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
||||
bool migrateLiterals,
|
||||
bool migrateSubscripting);
|
||||
unsigned migrateAction);
|
||||
|
||||
protected:
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
|
||||
|
@ -53,7 +53,6 @@ class FileRemapper {
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
|
||||
void remap(StringRef filePath, StringRef newPath);
|
||||
|
||||
void applyMappings(PreprocessorOptions &PPOpts) const;
|
||||
|
||||
|
@ -168,6 +168,13 @@ class APValue {
|
||||
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.
|
||||
void swap(APValue &RHS);
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
#define LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
@ -70,6 +72,10 @@ class ASTConsumer {
|
||||
/// can be defined in declspecs).
|
||||
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.
|
||||
/// 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
|
||||
@ -86,6 +92,21 @@ class ASTConsumer {
|
||||
/// The default implementation passes it to HandleTopLevelDecl.
|
||||
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
|
||||
/// unit to notify the consumer that the given tentative definition should be
|
||||
/// completed.
|
||||
|
@ -19,11 +19,9 @@
|
||||
#include "clang/AST/CanonicalType.h"
|
||||
#include "clang/AST/CommentCommandTraits.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/LambdaMangleContext.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/RawCommentList.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/AddressSpaces.h"
|
||||
@ -47,6 +45,7 @@ namespace llvm {
|
||||
|
||||
namespace clang {
|
||||
class FileManager;
|
||||
class AtomicExpr;
|
||||
class ASTRecordLayout;
|
||||
class BlockExpr;
|
||||
class CharUnits;
|
||||
@ -55,9 +54,11 @@ namespace clang {
|
||||
class ExternalASTSource;
|
||||
class ASTMutationListener;
|
||||
class IdentifierTable;
|
||||
class MaterializeTemporaryExpr;
|
||||
class SelectorTable;
|
||||
class TargetInfo;
|
||||
class CXXABI;
|
||||
class MangleNumberingContext;
|
||||
// Decls
|
||||
class MangleContext;
|
||||
class ObjCIvarDecl;
|
||||
@ -81,6 +82,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
|
||||
mutable llvm::FoldingSet<ComplexType> ComplexTypes;
|
||||
mutable llvm::FoldingSet<PointerType> PointerTypes;
|
||||
mutable llvm::FoldingSet<DecayedType> DecayedTypes;
|
||||
mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
|
||||
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
|
||||
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
|
||||
@ -146,7 +148,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
mutable TypeInfoMap MemoizedTypeInfo;
|
||||
|
||||
/// \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.
|
||||
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
|
||||
@ -163,6 +165,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
|
||||
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
|
||||
/// is used in canonical template names.
|
||||
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
|
||||
@ -190,6 +197,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
/// \brief The typedef for the __uint128_t type.
|
||||
mutable TypedefDecl *UInt128Decl;
|
||||
|
||||
/// \brief The typedef for the __float128 stub type.
|
||||
mutable TypeDecl *Float128StubDecl;
|
||||
|
||||
/// \brief The typedef for the target specific predefined
|
||||
/// __builtin_va_list type.
|
||||
@ -261,13 +271,30 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// wasting space in the Decl class.
|
||||
llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs;
|
||||
|
||||
/// \brief Keeps track of the static data member templates from which
|
||||
/// static data members of class template specializations were instantiated.
|
||||
/// \brief A mapping from non-redeclarable declarations in modules that were
|
||||
/// 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
|
||||
/// data members to the static data member representations within the
|
||||
/// class template from which they were instantiated along with the kind
|
||||
/// of instantiation or specialization (a TemplateSpecializationKind - 1).
|
||||
/// For non-templates, this value will be NULL. For variable
|
||||
/// declarations that describe a variable template, this will be a
|
||||
/// pointer to a VarTemplateDecl. For static data members
|
||||
/// 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:
|
||||
///
|
||||
@ -286,8 +313,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// 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
|
||||
/// class template X) and will be marked TSK_ImplicitInstantiation.
|
||||
llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>
|
||||
InstantiatedFromStaticDataMember;
|
||||
llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>
|
||||
TemplateOrInstantiation;
|
||||
|
||||
/// \brief Keeps track of the declaration from which a UsingDecl was
|
||||
/// created during instantiation.
|
||||
@ -328,12 +355,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
|
||||
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
|
||||
|
||||
/// \brief Mapping from each declaration context to its corresponding lambda
|
||||
/// mangling context.
|
||||
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
|
||||
/// \brief Mapping from each declaration context to its corresponding
|
||||
/// mangling numbering context (used for constructs like lambdas which
|
||||
/// need to be consistently numbered for the mangler).
|
||||
llvm::DenseMap<const DeclContext *, MangleNumberingContext *>
|
||||
MangleNumberingContexts;
|
||||
|
||||
llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts;
|
||||
llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers;
|
||||
/// \brief Side-table of mangling numbers for declarations which rarely
|
||||
/// need them (like static local vars).
|
||||
llvm::DenseMap<const NamedDecl *, unsigned> MangleNumbers;
|
||||
|
||||
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
|
||||
/// 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.
|
||||
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 ASTReader;
|
||||
friend class ASTWriter;
|
||||
@ -419,22 +453,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
return getParents(ast_type_traits::DynTypedNode::create(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;
|
||||
}
|
||||
ParentVector getParents(const ast_type_traits::DynTypedNode &Node);
|
||||
|
||||
const clang::PrintingPolicy &getPrintingPolicy() const {
|
||||
return PrintingPolicy;
|
||||
@ -451,7 +470,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
return BumpAlloc;
|
||||
}
|
||||
|
||||
void *Allocate(unsigned Size, unsigned Align = 8) const {
|
||||
void *Allocate(size_t Size, unsigned Align = 8) const {
|
||||
return BumpAlloc.Allocate(Size, Align);
|
||||
}
|
||||
void Deallocate(void *Ptr) const { }
|
||||
@ -470,6 +489,19 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
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; }
|
||||
|
||||
DiagnosticsEngine &getDiagnostics() const;
|
||||
@ -580,7 +612,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// preprocessor is not available.
|
||||
comments::FullComment *getCommentForDecl(const Decl *D,
|
||||
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,
|
||||
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
|
||||
/// class template specialization, returns the templated static data member
|
||||
/// from which it was instantiated.
|
||||
// FIXME: Remove ?
|
||||
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
|
||||
const VarDecl *Var);
|
||||
|
||||
TemplateOrSpecializationInfo
|
||||
getTemplateOrSpecializationInfo(const VarDecl *Var);
|
||||
|
||||
FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
|
||||
|
||||
void setClassScopeSpecializationPattern(FunctionDecl *FD,
|
||||
@ -615,6 +656,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
TemplateSpecializationKind TSK,
|
||||
SourceLocation PointOfInstantiation = SourceLocation());
|
||||
|
||||
void setTemplateOrSpecializationInfo(VarDecl *Inst,
|
||||
TemplateOrSpecializationInfo TSI);
|
||||
|
||||
/// \brief If the given using decl \p Inst is an instantiation of a
|
||||
/// (possibly unresolved) using decl from a template instantiation,
|
||||
/// return it.
|
||||
@ -632,31 +676,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
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.
|
||||
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
|
||||
overridden_cxx_method_iterator
|
||||
@ -732,7 +751,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
return import_iterator(FirstLocalImport);
|
||||
}
|
||||
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; }
|
||||
|
||||
|
||||
@ -740,7 +767,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
CanQualType VoidTy;
|
||||
CanQualType BoolTy;
|
||||
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 Char16Ty; // [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.
|
||||
TypedefDecl *getUInt128Decl() const;
|
||||
|
||||
/// \brief Retrieve the declaration for a 128-bit float stub type.
|
||||
TypeDecl *getFloat128StubType() const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Constructors
|
||||
@ -884,6 +915,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
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
|
||||
/// type.
|
||||
QualType getAtomicType(QualType T) const;
|
||||
@ -1104,7 +1143,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
/// \brief C++11 deduced auto type.
|
||||
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
|
||||
bool IsDependent = false) const;
|
||||
bool IsDependent) const;
|
||||
|
||||
/// \brief C++11 deduction pattern for 'auto' type.
|
||||
QualType getAutoDeductType() const;
|
||||
@ -1130,11 +1169,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// <stdint.h>.
|
||||
CanQualType getUIntMaxType() const;
|
||||
|
||||
/// \brief 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.
|
||||
/// \brief Return the unique wchar_t type available in C++ (and available as
|
||||
/// __wchar_t as a Microsoft extension).
|
||||
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".
|
||||
///
|
||||
/// 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
|
||||
/// alignment.
|
||||
///
|
||||
/// If \p RefAsPointee, references are treated like their underlying type
|
||||
/// (for alignof), else they're treated like pointers (for CodeGen).
|
||||
CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false) const;
|
||||
/// If \p ForAlignof, references are treated like their underlying type
|
||||
/// and large arrays don't get any special treatment. If not \p ForAlignof
|
||||
/// 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
|
||||
/// record (struct/union/class) \p D, which indicates its size and field
|
||||
/// position information.
|
||||
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const;
|
||||
const ASTRecordLayout *BuildMicrosoftASTRecordLayout(const RecordDecl *D) const;
|
||||
|
||||
/// \brief Get or compute information about the layout of the specified
|
||||
/// Objective-C interface.
|
||||
@ -1721,6 +1767,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
getCanonicalType(T2).getTypePtr();
|
||||
}
|
||||
|
||||
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
|
||||
const ObjCMethodDecl *MethodImp);
|
||||
|
||||
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
|
||||
|
||||
/// \brief Retrieves the "canonical" nested name specifier for a
|
||||
@ -1749,19 +1798,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
NestedNameSpecifier *
|
||||
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
|
||||
|
||||
/// \brief Retrieves the default calling convention to use for
|
||||
/// C++ instance methods.
|
||||
CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
|
||||
|
||||
/// \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 default calling convention for the current target.
|
||||
CallingConv getDefaultCallingConvention(bool isVariadic,
|
||||
bool IsCXXMethod) const;
|
||||
|
||||
/// \brief Retrieves the "canonical" template name that refers to a
|
||||
/// given template.
|
||||
@ -1899,6 +1938,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
return (*AddrSpaceMap)[AS - LangAS::Offset];
|
||||
}
|
||||
|
||||
bool addressSpaceMapManglingFor(unsigned AS) const {
|
||||
return AddrSpaceMapMangling ||
|
||||
AS < LangAS::Offset ||
|
||||
AS >= LangAS::Offset + LangAS::Count;
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper for integer ordering
|
||||
unsigned getIntegerRank(const Type *T) const;
|
||||
@ -1925,7 +1970,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
bool isObjCSelType(QualType T) const {
|
||||
return T == getObjCSelType();
|
||||
}
|
||||
bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
|
||||
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
|
||||
bool ForCompare);
|
||||
|
||||
@ -2092,12 +2136,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// it is not used.
|
||||
bool DeclMustBeEmitted(const Decl *D);
|
||||
|
||||
void addUnnamedTag(const TagDecl *Tag);
|
||||
int getUnnamedTagManglingNumber(const TagDecl *Tag) const;
|
||||
void setManglingNumber(const NamedDecl *ND, unsigned Number);
|
||||
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
|
||||
/// index of the parameter when it exceeds the size of the normal bitfield.
|
||||
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
|
||||
/// index of the parameter when it exceeds the size of the normal bitfield.
|
||||
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
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -2197,93 +2249,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
const ObjCImplementationDecl *Impl) const;
|
||||
|
||||
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.
|
||||
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
|
||||
// by DeclContext objects. This probably should not be in ASTContext,
|
||||
// but we include it here so that ASTContext can quickly deallocate them.
|
||||
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
|
||||
|
||||
/// \brief A counter used to uniquely identify "blocks".
|
||||
mutable unsigned int UniqueBlockByRefTypeID;
|
||||
|
||||
friend class DeclContext;
|
||||
friend class DeclarationNameTable;
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||
#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 ->
|
||||
/// \c To declaration mappings as they are imported.
|
||||
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
|
||||
/// 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 ObjCInterfaceDecl;
|
||||
class ObjCPropertyDecl;
|
||||
class QualType;
|
||||
class TagDecl;
|
||||
class VarDecl;
|
||||
class VarTemplateDecl;
|
||||
class VarTemplateSpecializationDecl;
|
||||
|
||||
/// \brief An abstract interface that should be implemented by listeners
|
||||
/// 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,
|
||||
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
|
||||
/// template declaration.
|
||||
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
|
||||
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.
|
||||
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
|
||||
|
||||
@ -78,6 +90,11 @@ class ASTMutationListener {
|
||||
const ObjCPropertyDecl *OrigProp,
|
||||
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
|
||||
// MultiplexASTMutationListener.
|
||||
};
|
||||
|
@ -7,22 +7,132 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provides a dynamically typed node container that can be used to store
|
||||
// an AST base node at runtime in the same storage in a type safe way.
|
||||
// Provides a dynamic type identifier and a dynamically typed node container
|
||||
// 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
|
||||
#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
|
||||
|
||||
#include "clang/AST/ASTFwd.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
struct PrintingPolicy;
|
||||
|
||||
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.
|
||||
///
|
||||
/// 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,
|
||||
/// 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
|
||||
/// the supported base types.
|
||||
class DynTypedNode {
|
||||
@ -49,15 +159,15 @@ class DynTypedNode {
|
||||
/// convertible to \c T.
|
||||
///
|
||||
/// For types that have identity via their pointer in the AST
|
||||
/// (like \c Stmt and \c Decl) the returned pointer points to the
|
||||
/// referenced AST node.
|
||||
/// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
|
||||
/// pointer points to the referenced AST node.
|
||||
/// For other types (like \c QualType) the value is stored directly
|
||||
/// in the \c DynTypedNode, and the returned pointer points at
|
||||
/// the storage inside DynTypedNode. For those nodes, do not
|
||||
/// use the pointer outside the scope of the DynTypedNode.
|
||||
template <typename T>
|
||||
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.
|
||||
@ -67,142 +177,171 @@ class DynTypedNode {
|
||||
/// method returns NULL.
|
||||
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:
|
||||
/// \brief Takes care of converting from and to \c T.
|
||||
template <typename T, typename EnablerT = void> struct BaseConverter;
|
||||
|
||||
/// \brief Supported base node types.
|
||||
enum NodeTypeTag {
|
||||
NT_Decl,
|
||||
NT_Stmt,
|
||||
NT_NestedNameSpecifier,
|
||||
NT_NestedNameSpecifierLoc,
|
||||
NT_QualType,
|
||||
NT_Type,
|
||||
NT_TypeLoc
|
||||
} Tag;
|
||||
/// \brief Converter that uses dyn_cast<T> from a stored BaseT*.
|
||||
template <typename T, typename BaseT> struct DynCastPtrConverter {
|
||||
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
|
||||
if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
|
||||
return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const BaseT &Node) {
|
||||
DynTypedNode Result;
|
||||
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.
|
||||
///
|
||||
/// Note that we can store \c Decls and \c Stmts by pointer as they are
|
||||
/// guaranteed to be unique pointers pointing to dedicated storage in the
|
||||
/// AST. \c QualTypes on the other hand do not have storage or unique
|
||||
/// Note that we can store \c Decls, \c Stmts, \c Types,
|
||||
/// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
|
||||
/// 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.
|
||||
llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
|
||||
NestedNameSpecifierLoc, QualType, Type,
|
||||
TypeLoc> Storage;
|
||||
typedef llvm::AlignedCharArrayUnion<
|
||||
Decl *, Stmt *, Type *, NestedNameSpecifier *, CXXCtorInitializer *>
|
||||
KindsByPointer;
|
||||
llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
|
||||
NestedNameSpecifierLoc, QualType, TypeLoc>
|
||||
Storage;
|
||||
};
|
||||
|
||||
// FIXME: Pull out abstraction for the following.
|
||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
||||
typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
|
||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_Decl)
|
||||
return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const Decl &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_Decl;
|
||||
new (Result.Storage.buffer) const Decl*(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
||||
typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
|
||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_Stmt)
|
||||
return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const Stmt &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_Stmt;
|
||||
new (Result.Storage.buffer) const Stmt*(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
||||
typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
|
||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_Type)
|
||||
return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const Type &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_Type;
|
||||
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;
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
T, typename llvm::enable_if<llvm::is_base_of<
|
||||
Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {};
|
||||
|
||||
template <typename T>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
T, typename llvm::enable_if<llvm::is_base_of<
|
||||
Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {};
|
||||
|
||||
template <typename T>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
T, typename llvm::enable_if<llvm::is_base_of<
|
||||
Type, T> >::type> : public DynCastPtrConverter<T, Type> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
NestedNameSpecifierLoc,
|
||||
void> : public ValueConverter<NestedNameSpecifierLoc> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<QualType,
|
||||
void> : public ValueConverter<QualType> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
TypeLoc, void> : public ValueConverter<TypeLoc> {};
|
||||
|
||||
// The only operation we allow on unsupported types is \c get.
|
||||
// This allows to conveniently use \c DynTypedNode when having an arbitrary
|
||||
// AST node that is not supported, but prevents misuse - a user cannot create
|
||||
// a DynTypedNode from arbitrary types.
|
||||
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 {
|
||||
switch (Tag) {
|
||||
case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
|
||||
case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
|
||||
default: return NULL;
|
||||
};
|
||||
if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
|
||||
return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
|
||||
} else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
|
||||
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
|
||||
|
@ -22,12 +22,21 @@ namespace clang {
|
||||
|
||||
/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
|
||||
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;
|
||||
|
||||
ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
friend class LazyASTUnresolvedSet;
|
||||
|
||||
public:
|
||||
ASTUnresolvedSet() {}
|
||||
ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
|
||||
@ -48,7 +57,7 @@ class ASTUnresolvedSet {
|
||||
/// Replaces the given declaration with the new one, once.
|
||||
///
|
||||
/// \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) {
|
||||
if (I->getDecl() == Old) {
|
||||
I->set(New, AS);
|
||||
@ -58,10 +67,7 @@ class ASTUnresolvedSet {
|
||||
return false;
|
||||
}
|
||||
|
||||
void erase(unsigned I) {
|
||||
Decls[I] = Decls.back();
|
||||
Decls.pop_back();
|
||||
}
|
||||
void erase(unsigned I) { Decls[I] = Decls.pop_back_val(); }
|
||||
|
||||
void clear() { Decls.clear(); }
|
||||
|
||||
@ -79,7 +85,29 @@ class ASTUnresolvedSet {
|
||||
DeclAccessPair &operator[](unsigned I) { 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
|
||||
|
||||
#endif
|
||||
|
@ -55,16 +55,24 @@ namespace clang {
|
||||
|
||||
template<typename T>
|
||||
class ASTVector {
|
||||
T *Begin, *End, *Capacity;
|
||||
private:
|
||||
T *Begin, *End;
|
||||
llvm::PointerIntPair<T*, 1, bool> Capacity;
|
||||
|
||||
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:
|
||||
// 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)
|
||||
: Begin(NULL), End(NULL), Capacity(NULL) {
|
||||
ASTVector(const ASTContext &C, unsigned N)
|
||||
: Begin(0), End(0), Capacity(0, false) {
|
||||
reserve(C, N);
|
||||
}
|
||||
|
||||
@ -155,8 +163,8 @@ class ASTVector {
|
||||
return const_pointer(Begin);
|
||||
}
|
||||
|
||||
void push_back(const_reference Elt, ASTContext &C) {
|
||||
if (End < Capacity) {
|
||||
void push_back(const_reference Elt, const ASTContext &C) {
|
||||
if (End < this->capacity_ptr()) {
|
||||
Retry:
|
||||
new (End) T(Elt);
|
||||
++End;
|
||||
@ -166,19 +174,19 @@ class ASTVector {
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
void reserve(ASTContext &C, unsigned N) {
|
||||
if (unsigned(Capacity-Begin) < N)
|
||||
void reserve(const ASTContext &C, unsigned N) {
|
||||
if (unsigned(this->capacity_ptr()-Begin) < N)
|
||||
grow(C, N);
|
||||
}
|
||||
|
||||
/// capacity - Return the total number of elements in the currently allocated
|
||||
/// 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.
|
||||
///
|
||||
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);
|
||||
|
||||
if (NumInputs == 0)
|
||||
@ -197,7 +205,7 @@ class ASTVector {
|
||||
|
||||
/// 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.
|
||||
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
|
||||
this->grow(C, this->size()+NumInputs);
|
||||
@ -214,13 +222,13 @@ class ASTVector {
|
||||
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.
|
||||
push_back(Elt);
|
||||
push_back(Elt, C);
|
||||
return this->end()-1;
|
||||
}
|
||||
|
||||
if (this->EndX < this->CapacityX) {
|
||||
if (this->End < this->capacity_ptr()) {
|
||||
Retry:
|
||||
new (this->end()) T(this->back());
|
||||
this->setEnd(this->end()+1);
|
||||
@ -235,7 +243,7 @@ class ASTVector {
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
iterator insert(ASTContext &C, iterator I, size_type NumToInsert,
|
||||
iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
|
||||
const T &Elt) {
|
||||
if (I == this->end()) { // Important special case for empty vector.
|
||||
append(C, NumToInsert, Elt);
|
||||
@ -284,7 +292,7 @@ class ASTVector {
|
||||
}
|
||||
|
||||
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.
|
||||
append(C, From, To);
|
||||
return this->end()-1;
|
||||
@ -335,7 +343,7 @@ class ASTVector {
|
||||
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()) {
|
||||
this->destroy_range(this->begin()+N, this->end());
|
||||
this->setEnd(this->begin()+N);
|
||||
@ -350,7 +358,7 @@ class ASTVector {
|
||||
private:
|
||||
/// grow - double the size of the allocated memory, guaranteeing space for at
|
||||
/// least one more element or MinSize if specified.
|
||||
void grow(ASTContext &C, size_type MinSize = 1);
|
||||
void grow(const ASTContext &C, size_type MinSize = 1);
|
||||
|
||||
void construct_range(T *S, T *E, const T &Elt) {
|
||||
for (; S != E; ++S)
|
||||
@ -365,13 +373,16 @@ class ASTVector {
|
||||
}
|
||||
|
||||
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.
|
||||
template <typename T>
|
||||
void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
|
||||
size_t CurCapacity = Capacity-Begin;
|
||||
void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
|
||||
size_t CurCapacity = this->capacity();
|
||||
size_t CurSize = size();
|
||||
size_t NewCapacity = 2*CurCapacity;
|
||||
if (NewCapacity < MinSize)
|
||||
@ -394,7 +405,7 @@ void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
|
||||
// ASTContext never frees any memory.
|
||||
Begin = NewElts;
|
||||
End = NewElts+CurSize;
|
||||
Capacity = Begin+NewCapacity;
|
||||
Capacity.setPointer(Begin+NewCapacity);
|
||||
}
|
||||
|
||||
} // end: clang namespace
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_CLANG_AST_ATTR_H
|
||||
|
||||
#include "clang/AST/AttrIterator.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
@ -145,7 +146,7 @@ class MSInheritanceAttr : public InheritableAttr {
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
|
@ -287,9 +287,9 @@ class OverridingMethods {
|
||||
|
||||
// Iterate over the set of overriding virtual methods in a given
|
||||
// subobject.
|
||||
typedef SmallVector<UniqueVirtualMethod, 4>::iterator
|
||||
typedef SmallVectorImpl<UniqueVirtualMethod>::iterator
|
||||
overriding_iterator;
|
||||
typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator
|
||||
typedef SmallVectorImpl<UniqueVirtualMethod>::const_iterator
|
||||
overriding_const_iterator;
|
||||
|
||||
// Add a new overriding method for a particular subobject.
|
||||
|
@ -81,7 +81,7 @@ class CanQual {
|
||||
operator QualType() const { return Stored; }
|
||||
|
||||
/// \brief Implicit conversion to bool.
|
||||
operator bool() const { return !isNull(); }
|
||||
LLVM_EXPLICIT operator bool() const { return !isNull(); }
|
||||
|
||||
bool isNull() const {
|
||||
return Stored.isNull();
|
||||
|
@ -19,21 +19,20 @@
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
/// 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
|
||||
/// 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
|
||||
/// refer to addressable units of data storage on the target machine, and
|
||||
/// characters are members of a set of elements used for the organization,
|
||||
/// control, or representation of data. According to C99, bytes are allowed
|
||||
/// to exceed characters in size, although currently, clang only supports
|
||||
/// architectures where the two are the same size.
|
||||
///
|
||||
/// For portability, never assume that a target character is 8 bits wide. Use
|
||||
/// In both C and C++, an object of type 'char', 'signed char', or 'unsigned
|
||||
/// char' occupies exactly one byte, so 'character unit' and 'byte' refer to
|
||||
/// the same quantity of storage. However, we use the term 'character unit'
|
||||
/// rather than 'byte' to avoid an implication that a character unit is
|
||||
/// exactly 8 bits.
|
||||
///
|
||||
/// For portability, never assume that a target character is 8 bits wide. Use
|
||||
/// CharUnit values wherever you calculate sizes, offsets, or alignments
|
||||
/// in character units.
|
||||
class CharUnits {
|
||||
|
@ -699,7 +699,10 @@ class ParamCommandComment : public BlockCommandComment {
|
||||
unsigned ParamIndex;
|
||||
|
||||
public:
|
||||
enum { InvalidParamIndex = ~0U };
|
||||
enum LLVM_ENUM_INT_TYPE(unsigned) {
|
||||
InvalidParamIndex = ~0U,
|
||||
VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U
|
||||
};
|
||||
|
||||
ParamCommandComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
@ -755,14 +758,25 @@ class ParamCommandComment : public BlockCommandComment {
|
||||
return ParamIndex != InvalidParamIndex;
|
||||
}
|
||||
|
||||
bool isVarArgParam() const LLVM_READONLY {
|
||||
return ParamIndex == VarArgParamIndex;
|
||||
}
|
||||
|
||||
void setIsVarArgParam() {
|
||||
ParamIndex = VarArgParamIndex;
|
||||
assert(isParamIndexValid());
|
||||
}
|
||||
|
||||
unsigned getParamIndex() const LLVM_READONLY {
|
||||
assert(isParamIndexValid());
|
||||
assert(!isVarArgParam());
|
||||
return ParamIndex;
|
||||
}
|
||||
|
||||
void setParamIndex(unsigned Index) {
|
||||
ParamIndex = Index;
|
||||
assert(isParamIndexValid());
|
||||
assert(!isVarArgParam());
|
||||
}
|
||||
};
|
||||
|
||||
@ -1097,10 +1111,6 @@ class FullComment : public Comment {
|
||||
return ThisDeclInfo;
|
||||
}
|
||||
|
||||
DeclInfo *getThisDeclInfo() const LLVM_READONLY {
|
||||
return ThisDeclInfo;
|
||||
}
|
||||
|
||||
ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
|
||||
|
||||
};
|
||||
|
@ -67,6 +67,9 @@ struct CommandInfo {
|
||||
/// a template parameter (\\tparam or an alias).
|
||||
unsigned IsTParamCommand : 1;
|
||||
|
||||
/// True if this command is \\throws or an alias.
|
||||
unsigned IsThrowsCommand : 1;
|
||||
|
||||
/// True if this command is \\deprecated or an alias.
|
||||
unsigned IsDeprecatedCommand : 1;
|
||||
|
||||
@ -142,6 +145,8 @@ class CommandTraits {
|
||||
llvm_unreachable("the command should be known");
|
||||
}
|
||||
|
||||
const CommandInfo *getTypoCorrectCommandInfo(StringRef Typo) const;
|
||||
|
||||
const CommandInfo *getCommandInfo(unsigned CommandID) const;
|
||||
|
||||
const CommandInfo *registerUnknownCommand(StringRef CommandName);
|
||||
|
@ -15,6 +15,7 @@ class Command<string name> {
|
||||
bit IsReturnsCommand = 0;
|
||||
bit IsParamCommand = 0;
|
||||
bit IsTParamCommand = 0;
|
||||
bit IsThrowsCommand = 0;
|
||||
bit IsDeprecatedCommand = 0;
|
||||
bit IsHeaderfileCommand = 0;
|
||||
|
||||
@ -109,6 +110,10 @@ def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
|
||||
// HeaderDoc command for template parameter documentation.
|
||||
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"> {
|
||||
let IsEmptyParagraphAllowed = 1;
|
||||
let IsDeprecatedCommand = 1;
|
||||
@ -200,11 +205,17 @@ def Mainpage : VerbatimLineCommand<"mainpage">;
|
||||
def Subpage : VerbatimLineCommand<"subpage">;
|
||||
def Ref : VerbatimLineCommand<"ref">;
|
||||
|
||||
def Relates : VerbatimLineCommand<"relates">;
|
||||
def Related : VerbatimLineCommand<"related">;
|
||||
def RelatesAlso : VerbatimLineCommand<"relatesalso">;
|
||||
def RelatedAlso : VerbatimLineCommand<"relatedalso">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DeclarationVerbatimLineCommand
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Doxygen commands.
|
||||
def Def : DeclarationVerbatimLineCommand<"def">;
|
||||
def Fn : DeclarationVerbatimLineCommand<"fn">;
|
||||
def Namespace : DeclarationVerbatimLineCommand<"namespace">;
|
||||
def Overload : DeclarationVerbatimLineCommand<"overload">;
|
||||
|
@ -16,7 +16,7 @@ namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
#define COMMENTSTART
|
||||
#include "clang/Basic/DiagnosticCommentKinds.inc"
|
||||
#undef DIAG
|
||||
|
@ -61,10 +61,8 @@ class Parser {
|
||||
void consumeToken() {
|
||||
if (MoreLATokens.empty())
|
||||
L.lex(Tok);
|
||||
else {
|
||||
Tok = MoreLATokens.back();
|
||||
MoreLATokens.pop_back();
|
||||
}
|
||||
else
|
||||
Tok = MoreLATokens.pop_back_val();
|
||||
}
|
||||
|
||||
void putBack(const Token &OldTok) {
|
||||
|
@ -58,9 +58,6 @@ class Sema {
|
||||
/// AST node for the \\brief command and its aliases.
|
||||
const BlockCommandComment *BriefCommand;
|
||||
|
||||
/// AST node for the \\returns command and its aliases.
|
||||
const BlockCommandComment *ReturnsCommand;
|
||||
|
||||
/// AST node for the \\headerfile command.
|
||||
const BlockCommandComment *HeaderfileCommand;
|
||||
|
||||
@ -211,7 +208,11 @@ class Sema {
|
||||
|
||||
bool isFunctionDecl();
|
||||
bool isAnyFunctionDecl();
|
||||
|
||||
/// \returns \c true if declaration that this comment is attached to declares
|
||||
/// a function pointer.
|
||||
bool isFunctionPointerVarDecl();
|
||||
bool isFunctionOrMethodVariadic();
|
||||
bool isObjCMethodDecl();
|
||||
bool isObjCPropertyDecl();
|
||||
bool isTemplateOrSpecialization();
|
||||
@ -220,6 +221,8 @@ class Sema {
|
||||
bool isUnionDecl();
|
||||
bool isObjCInterfaceDecl();
|
||||
bool isObjCProtocolDecl();
|
||||
bool isClassTemplateDecl();
|
||||
bool isFunctionTemplateDecl();
|
||||
|
||||
ArrayRef<const ParmVarDecl *> getParamVars();
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace clang {
|
||||
struct ASTTemplateArgumentListInfo;
|
||||
@ -43,6 +44,7 @@ class TemplateArgumentList;
|
||||
class TemplateParameterList;
|
||||
class TypeLoc;
|
||||
class UnresolvedSetImpl;
|
||||
class VarTemplateDecl;
|
||||
|
||||
/// \brief A container of type source information.
|
||||
///
|
||||
@ -109,7 +111,6 @@ class NamedDecl : public Decl {
|
||||
|
||||
private:
|
||||
NamedDecl *getUnderlyingDeclImpl();
|
||||
void verifyLinkage() const;
|
||||
|
||||
protected:
|
||||
NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
|
||||
@ -142,7 +143,7 @@ class NamedDecl : public Decl {
|
||||
// FIXME: Deprecated, move clients to getName().
|
||||
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,
|
||||
/// which may be a special name.
|
||||
@ -189,10 +190,13 @@ class NamedDecl : public Decl {
|
||||
|
||||
using Decl::isModulePrivate;
|
||||
using Decl::setModulePrivate;
|
||||
|
||||
|
||||
/// \brief Determine whether this declaration is hidden from name lookup.
|
||||
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.
|
||||
bool isCXXClassMember() const {
|
||||
const DeclContext *DC = getDeclContext();
|
||||
@ -212,11 +216,24 @@ class NamedDecl : public Decl {
|
||||
bool isCXXInstanceMember() const;
|
||||
|
||||
/// \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.
|
||||
bool hasExternalLinkage() const {
|
||||
return getLinkage() == ExternalLinkage;
|
||||
bool hasExternalFormalLinkage() const {
|
||||
return isExternalFormalLinkage(getLinkageInternal());
|
||||
}
|
||||
|
||||
bool isExternallyVisible() const {
|
||||
return clang::isExternallyVisible(getLinkageInternal());
|
||||
}
|
||||
|
||||
/// \brief Determines the visibility of this entity.
|
||||
@ -256,6 +273,13 @@ class NamedDecl : public Decl {
|
||||
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 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::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
/// \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.
|
||||
NamespaceDecl *getOriginalNamespace() {
|
||||
if (isFirstDeclaration())
|
||||
if (isFirstDecl())
|
||||
return this;
|
||||
|
||||
return AnonOrFirstNamespaceAndInline.getPointer();
|
||||
@ -385,7 +410,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
||||
|
||||
/// \brief Get the original (first) namespace declaration.
|
||||
const NamespaceDecl *getOriginalNamespace() const {
|
||||
if (isFirstDeclaration())
|
||||
if (isFirstDecl())
|
||||
return this;
|
||||
|
||||
return AnonOrFirstNamespaceAndInline.getPointer();
|
||||
@ -394,9 +419,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
||||
/// \brief Return true if this declaration is an original (first) declaration
|
||||
/// of the namespace. This is false for non-original (subsequent) namespace
|
||||
/// declarations and anonymous namespaces.
|
||||
bool isOriginalNamespace() const {
|
||||
return isFirstDeclaration();
|
||||
}
|
||||
bool isOriginalNamespace() const { return isFirstDecl(); }
|
||||
|
||||
/// \brief Retrieve the anonymous namespace nested inside this namespace,
|
||||
/// if any.
|
||||
@ -689,11 +712,21 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
|
||||
/// \brief Whether this variable is (C++0x) constexpr.
|
||||
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 StmtIteratorBase;
|
||||
friend class ASTNodeImporter;
|
||||
|
||||
protected:
|
||||
enum { NumParameterIndexBits = 8 };
|
||||
@ -732,15 +765,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
};
|
||||
|
||||
VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
QualType T, 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.
|
||||
}
|
||||
SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo, StorageClass SC);
|
||||
|
||||
typedef Redeclarable<VarDecl> redeclarable_base;
|
||||
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::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
static VarDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
@ -797,7 +824,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// is a non-static local variable.
|
||||
bool hasLocalStorage() const {
|
||||
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 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
|
||||
/// static local variable.
|
||||
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__
|
||||
@ -818,12 +849,19 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
getStorageClass() == SC_PrivateExtern;
|
||||
}
|
||||
|
||||
/// hasGlobalStorage - Returns true for all variables that do not
|
||||
/// have local storage. This includs all global variables as well
|
||||
/// as static variables declared within a function.
|
||||
/// \brief Returns true for all variables that do not have local storage.
|
||||
///
|
||||
/// This includes all global variables as well as static variables declared
|
||||
/// within a function.
|
||||
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;
|
||||
|
||||
/// \brief Determines whether this variable is a variable with
|
||||
@ -847,7 +885,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
bool isLocalVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
return false;
|
||||
if (const DeclContext *DC = getDeclContext())
|
||||
if (const DeclContext *DC = getLexicalDeclContext())
|
||||
return DC->getRedeclContext()->isFunctionOrMethod();
|
||||
return false;
|
||||
}
|
||||
@ -857,7 +895,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
bool isFunctionOrMethodVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
return false;
|
||||
const DeclContext *DC = getDeclContext()->getRedeclContext();
|
||||
const DeclContext *DC = getLexicalDeclContext()->getRedeclContext();
|
||||
return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;
|
||||
}
|
||||
|
||||
@ -908,10 +946,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
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.
|
||||
VarDecl *getDefinition(ASTContext &);
|
||||
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.
|
||||
bool isFileVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
Kind K = getKind();
|
||||
if (K == ParmVar || K == ImplicitParam)
|
||||
return false;
|
||||
|
||||
if (getDeclContext()->getRedeclContext()->isFileContext())
|
||||
if (getLexicalDeclContext()->getRedeclContext()->isFileContext())
|
||||
return true;
|
||||
|
||||
if (isStaticDataMember())
|
||||
@ -1000,20 +1035,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
|
||||
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
|
||||
/// constant expression, according to the relevant language standard.
|
||||
/// 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; }
|
||||
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
|
||||
/// class template specialization, returns the templated static data member
|
||||
/// from which it was instantiated.
|
||||
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.
|
||||
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
|
||||
/// class template specialization, retrieves the member specialization
|
||||
/// information.
|
||||
@ -1142,6 +1182,26 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
||||
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.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
|
||||
@ -1314,11 +1374,7 @@ class ParmVarDecl : public VarDecl {
|
||||
ParmVarDeclBits.HasInheritedDefaultArg = I;
|
||||
}
|
||||
|
||||
QualType getOriginalType() const {
|
||||
if (getTypeSourceInfo())
|
||||
return getTypeSourceInfo()->getType();
|
||||
return getType();
|
||||
}
|
||||
QualType getOriginalType() const;
|
||||
|
||||
/// \brief Determine whether this parameter is actually a function
|
||||
/// parameter pack.
|
||||
@ -1517,6 +1573,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
using redeclarable_base::redecls_end;
|
||||
using redeclarable_base::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation NLoc,
|
||||
@ -1701,6 +1758,10 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// entry point into an executable program.
|
||||
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
|
||||
/// of the reserved global placement operators:
|
||||
/// 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.
|
||||
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.
|
||||
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
|
||||
/// 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.
|
||||
bool Mutable : 1;
|
||||
mutable unsigned CachedFieldIndex : 31;
|
||||
@ -2153,6 +2236,10 @@ class FieldDecl : public DeclaratorDecl {
|
||||
|
||||
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.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
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
|
||||
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
|
||||
/// TagType for the X EnumDecl.
|
||||
class EnumConstantDecl : public ValueDecl {
|
||||
class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> {
|
||||
Stmt *Init; // an integer constant expression
|
||||
llvm::APSInt Val; // The value.
|
||||
protected:
|
||||
@ -2191,6 +2278,10 @@ class EnumConstantDecl : public ValueDecl {
|
||||
|
||||
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.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
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.
|
||||
class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
||||
virtual void anchor();
|
||||
/// UnderlyingType - This is the type the typedef is set to.
|
||||
TypeSourceInfo *TInfo;
|
||||
typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
|
||||
llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
|
||||
|
||||
protected:
|
||||
TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
TypeSourceInfo *TInfo)
|
||||
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), TInfo(TInfo) {}
|
||||
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), MaybeModedTInfo(TInfo) {}
|
||||
|
||||
typedef Redeclarable<TypedefNameDecl> redeclarable_base;
|
||||
virtual TypedefNameDecl *getNextRedeclaration() {
|
||||
@ -2315,25 +2406,30 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
||||
using redeclarable_base::redecls_end;
|
||||
using redeclarable_base::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
bool isModed() const { return MaybeModedTInfo.is<ModedTInfo*>(); }
|
||||
|
||||
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.
|
||||
TypedefNameDecl *getCanonicalDecl() {
|
||||
return getFirstDeclaration();
|
||||
}
|
||||
const TypedefNameDecl *getCanonicalDecl() const {
|
||||
return getFirstDeclaration();
|
||||
}
|
||||
|
||||
QualType getUnderlyingType() const {
|
||||
return TInfo->getType();
|
||||
}
|
||||
void setTypeSourceInfo(TypeSourceInfo *newType) {
|
||||
TInfo = newType;
|
||||
}
|
||||
TypedefNameDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||
const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
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.
|
||||
bool MayHaveOutOfDateDef : 1;
|
||||
|
||||
/// Has the full definition of this type been required by a use somewhere in
|
||||
/// the TU.
|
||||
bool IsCompleteDefinitionRequired : 1;
|
||||
private:
|
||||
SourceLocation RBraceLoc;
|
||||
|
||||
@ -2443,33 +2542,33 @@ class TagDecl
|
||||
// to be used for the (uncommon) case of out-of-line declarations.
|
||||
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);
|
||||
/// otherwise, if the tag declaration is anonymous and it is part of
|
||||
/// 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.
|
||||
llvm::PointerUnion<TypedefNameDecl*, ExtInfo*> TypedefNameDeclOrQualifier;
|
||||
llvm::PointerUnion<NamedDecl *, ExtInfo *> NamedDeclOrQualifier;
|
||||
|
||||
bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo*>(); }
|
||||
ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo*>(); }
|
||||
bool hasExtInfo() const { return NamedDeclOrQualifier.is<ExtInfo *>(); }
|
||||
ExtInfo *getExtInfo() { return NamedDeclOrQualifier.get<ExtInfo *>(); }
|
||||
const ExtInfo *getExtInfo() const {
|
||||
return TypedefNameDeclOrQualifier.get<ExtInfo*>();
|
||||
return NamedDeclOrQualifier.get<ExtInfo *>();
|
||||
}
|
||||
|
||||
protected:
|
||||
TagDecl(Kind DK, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
TagDecl *PrevDecl, SourceLocation StartL)
|
||||
: TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK),
|
||||
TypedefNameDeclOrQualifier((TypedefNameDecl*) 0) {
|
||||
TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, TagDecl *PrevDecl, SourceLocation StartL)
|
||||
: TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), TagDeclKind(TK),
|
||||
IsCompleteDefinition(false), IsBeingDefined(false),
|
||||
IsEmbeddedInDeclarator(false), IsFreeStanding(false),
|
||||
IsCompleteDefinitionRequired(false),
|
||||
NamedDeclOrQualifier((NamedDecl *)0) {
|
||||
assert((DK != Enum || TK == TTK_Enum) &&
|
||||
"EnumDecl not matched with TTK_Enum");
|
||||
TagDeclKind = TK;
|
||||
IsCompleteDefinition = false;
|
||||
IsBeingDefined = false;
|
||||
IsEmbeddedInDeclarator = false;
|
||||
IsFreeStanding = false;
|
||||
setPreviousDeclaration(PrevDecl);
|
||||
setPreviousDecl(PrevDecl);
|
||||
}
|
||||
|
||||
typedef Redeclarable<TagDecl> redeclarable_base;
|
||||
@ -2492,6 +2591,7 @@ class TagDecl
|
||||
using redeclarable_base::redecls_end;
|
||||
using redeclarable_base::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
SourceLocation getRBraceLoc() const { return RBraceLoc; }
|
||||
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
|
||||
@ -2522,6 +2622,12 @@ class TagDecl
|
||||
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.
|
||||
bool isBeingDefined() const {
|
||||
return IsBeingDefined;
|
||||
@ -2563,6 +2669,10 @@ class TagDecl
|
||||
|
||||
void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
|
||||
|
||||
void setCompleteDefinitionRequired(bool V = true) {
|
||||
IsCompleteDefinitionRequired = V;
|
||||
}
|
||||
|
||||
// FIXME: Return StringRef;
|
||||
const char *getKindName() const {
|
||||
return TypeWithKeyword::getTagTypeKindName(getTagKind());
|
||||
@ -2599,10 +2709,21 @@ class TagDecl
|
||||
return (getDeclName() || getTypedefNameForAnonDecl());
|
||||
}
|
||||
|
||||
TypedefNameDecl *getTypedefNameForAnonDecl() const {
|
||||
return hasExtInfo() ? 0 :
|
||||
TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
|
||||
bool hasDeclaratorForAnonDecl() const {
|
||||
return dyn_cast_or_null<DeclaratorDecl>(
|
||||
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);
|
||||
|
||||
@ -2702,21 +2823,22 @@ class EnumDecl : public TagDecl {
|
||||
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
|
||||
}
|
||||
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() {
|
||||
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() {
|
||||
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 {
|
||||
@ -2912,18 +3034,19 @@ class RecordDecl : public TagDecl {
|
||||
IdentifierInfo *Id, RecordDecl* PrevDecl = 0);
|
||||
static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
||||
|
||||
const RecordDecl *getPreviousDecl() const {
|
||||
return cast_or_null<RecordDecl>(TagDecl::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() {
|
||||
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; }
|
||||
@ -3106,13 +3229,17 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
Capture *Captures;
|
||||
unsigned NumCaptures;
|
||||
|
||||
unsigned ManglingNumber;
|
||||
Decl *ManglingContextDecl;
|
||||
|
||||
protected:
|
||||
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
|
||||
: Decl(Block, DC, CaretLoc), DeclContext(Block),
|
||||
IsVariadic(false), CapturesCXXThis(false),
|
||||
BlockMissingReturnType(true), IsConversionFromLambda(false),
|
||||
ParamInfo(0), NumParams(0), Body(0),
|
||||
SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
|
||||
SignatureAsWritten(0), Captures(0), NumCaptures(0),
|
||||
ManglingNumber(0), ManglingContextDecl(0) {}
|
||||
|
||||
public:
|
||||
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
|
||||
@ -3182,6 +3309,18 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
const Capture *end,
|
||||
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;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
@ -3354,7 +3493,7 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
// redeclaration, or we can build invalid chains. If the most recent
|
||||
// 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");
|
||||
decl_type *MostRecent = First->RedeclLink.getNext();
|
||||
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 {
|
||||
// Make this first.
|
||||
First = static_cast<decl_type*>(this);
|
||||
|
@ -28,7 +28,7 @@ class NamedDecl;
|
||||
/// A POD class for pairing a NamedDecl* with an access specifier.
|
||||
/// Can be put into unions.
|
||||
class DeclAccessPair {
|
||||
NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
|
||||
uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
|
||||
|
||||
enum { Mask = 0x3 };
|
||||
|
||||
@ -40,10 +40,10 @@ class DeclAccessPair {
|
||||
}
|
||||
|
||||
NamedDecl *getDecl() const {
|
||||
return (NamedDecl*) (~Mask & (uintptr_t) Ptr);
|
||||
return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
|
||||
}
|
||||
AccessSpecifier getAccess() const {
|
||||
return AccessSpecifier(Mask & (uintptr_t) Ptr);
|
||||
return AccessSpecifier(Mask & Ptr);
|
||||
}
|
||||
|
||||
void setDecl(NamedDecl *D) {
|
||||
@ -53,8 +53,7 @@ class DeclAccessPair {
|
||||
set(getDecl(), AS);
|
||||
}
|
||||
void set(NamedDecl *D, AccessSpecifier AS) {
|
||||
Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) |
|
||||
reinterpret_cast<uintptr_t>(D));
|
||||
Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D);
|
||||
}
|
||||
|
||||
operator NamedDecl*() const { return getDecl(); }
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "clang/AST/AttrIterator.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/Basic/Linkage.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
@ -31,6 +32,7 @@ class DeclarationName;
|
||||
class DependentDiagnostic;
|
||||
class EnumDecl;
|
||||
class FunctionDecl;
|
||||
class LinkageComputer;
|
||||
class LinkageSpecDecl;
|
||||
class Module;
|
||||
class NamedDecl;
|
||||
@ -157,7 +159,12 @@ class Decl {
|
||||
/// This declaration is a C++ operator declared in a non-class
|
||||
/// context. All such operators are also in IDNS_Ordinary.
|
||||
/// C++ lexical operator lookup looks for these.
|
||||
IDNS_NonMemberOperator = 0x0400
|
||||
IDNS_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
|
||||
@ -284,19 +291,16 @@ class Decl {
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 12;
|
||||
|
||||
/// \brief Whether the \c CachedLinkage field is active.
|
||||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned HasCachedLinkage : 1;
|
||||
|
||||
/// \brief If \c HasCachedLinkage, the linkage of this declaration.
|
||||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned CachedLinkage : 2;
|
||||
/// \brief If 0, we have not computed the linkage of this declaration.
|
||||
/// Otherwise, it is the linkage + 1.
|
||||
mutable unsigned CacheValidAndLinkage : 3;
|
||||
|
||||
friend class ASTDeclWriter;
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTReader;
|
||||
friend class LinkageComputer;
|
||||
|
||||
template<typename decl_type> friend class Redeclarable;
|
||||
|
||||
private:
|
||||
void CheckAccessDeclContext() const;
|
||||
@ -309,7 +313,7 @@ class Decl {
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
CacheValidAndLinkage(0)
|
||||
{
|
||||
if (StatisticsEnabled) add(DK);
|
||||
}
|
||||
@ -319,7 +323,7 @@ class Decl {
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
CacheValidAndLinkage(0)
|
||||
{
|
||||
if (StatisticsEnabled) add(DK);
|
||||
}
|
||||
@ -341,6 +345,18 @@ class Decl {
|
||||
/// \brief Update a potentially out-of-date declaration.
|
||||
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:
|
||||
|
||||
/// \brief Source range that this declaration covers.
|
||||
@ -419,7 +435,6 @@ class Decl {
|
||||
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
|
||||
}
|
||||
const AttrVec &getAttrs() const;
|
||||
void swapAttrs(Decl *D);
|
||||
void dropAttrs();
|
||||
|
||||
void addAttr(Attr *A) {
|
||||
@ -490,7 +505,16 @@ class Decl {
|
||||
/// whether the function is used.
|
||||
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.
|
||||
bool isReferenced() const;
|
||||
@ -513,13 +537,13 @@ class Decl {
|
||||
NextInContextAndBits.setInt(Bits);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \brief Whether this declaration was marked as being private to the
|
||||
/// module in which it was defined.
|
||||
bool isModulePrivate() const {
|
||||
bool isModulePrivate() const {
|
||||
return NextInContextAndBits.getInt() & ModulePrivateFlag;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
/// \brief Specify whether this declaration was marked as being private
|
||||
/// to the module in which it was defined.
|
||||
void setModulePrivate(bool MP = true) {
|
||||
@ -761,7 +785,12 @@ class Decl {
|
||||
const Decl *getPreviousDecl() const {
|
||||
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
|
||||
/// as this declaration (which may be this declaration).
|
||||
Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); }
|
||||
@ -777,8 +806,10 @@ class Decl {
|
||||
/// top-level Stmt* of that body. Otherwise this method returns null.
|
||||
virtual Stmt* getBody() const { return 0; }
|
||||
|
||||
/// \brief Returns true if this Decl represents a declaration for a body of
|
||||
/// \brief Returns true if this \c Decl represents a declaration for a body of
|
||||
/// 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; }
|
||||
|
||||
/// 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.
|
||||
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
|
||||
/// the object of a friend declaration.
|
||||
///
|
||||
@ -814,31 +871,39 @@ class Decl {
|
||||
/// class, but in the semantic context of the actual entity. This property
|
||||
/// applies only to a specific decl object; other redeclarations of the
|
||||
/// same entity may not (and probably don't) share this property.
|
||||
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
|
||||
void setObjectOfFriendDecl(bool PerformFriendInjection = false) {
|
||||
unsigned OldNS = IdentifierNamespace;
|
||||
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
|
||||
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
|
||||
IDNS_TagFriend | IDNS_OrdinaryFriend |
|
||||
IDNS_LocalExtern)) &&
|
||||
"namespace includes neither ordinary nor tag");
|
||||
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");
|
||||
|
||||
IdentifierNamespace = 0;
|
||||
Decl *Prev = getPreviousDecl();
|
||||
IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type);
|
||||
|
||||
if (OldNS & (IDNS_Tag | 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;
|
||||
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
|
||||
if (PerformFriendInjection ||
|
||||
(Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
|
||||
IdentifierNamespace |= IDNS_Ordinary;
|
||||
}
|
||||
}
|
||||
|
||||
enum FriendObjectKind {
|
||||
FOK_None, // not a friend object
|
||||
FOK_Declared, // a friend of a previously-declared entity
|
||||
FOK_Undeclared // a friend of a previously-undeclared entity
|
||||
FOK_None, ///< Not a friend object.
|
||||
FOK_Declared, ///< A friend of a previously-declared entity.
|
||||
FOK_Undeclared ///< A friend of a previously-undeclared entity.
|
||||
};
|
||||
|
||||
/// \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.
|
||||
FriendObjectKind getFriendObjectKind() const {
|
||||
unsigned mask
|
||||
= (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
|
||||
unsigned mask =
|
||||
(IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
|
||||
if (!mask) return FOK_None;
|
||||
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
|
||||
FOK_Declared : FOK_Undeclared);
|
||||
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared
|
||||
: FOK_Undeclared);
|
||||
}
|
||||
|
||||
/// Specifies that this declaration is a C++ overloaded non-member.
|
||||
@ -877,9 +942,6 @@ class Decl {
|
||||
// Same as dump(), but forces color printing.
|
||||
LLVM_ATTRIBUTE_USED void dumpColor() 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:
|
||||
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
|
||||
@ -974,6 +1036,7 @@ class DeclContext {
|
||||
mutable Decl *LastDecl;
|
||||
|
||||
friend class ExternalASTSource;
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTWriter;
|
||||
|
||||
/// \brief Build up a chain of declarations.
|
||||
@ -1096,6 +1159,14 @@ class DeclContext {
|
||||
/// C++0x scoped enums), and C++ linkage specifications.
|
||||
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
|
||||
/// to the declaration context DC.
|
||||
bool Equals(const DeclContext *DC) const {
|
||||
@ -1429,12 +1500,20 @@ class DeclContext {
|
||||
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
|
||||
/// into this declaration context without consulting the external source.
|
||||
///
|
||||
/// This function should almost never be used, because it subverts the
|
||||
/// usual relationship between a DeclContext and the external source.
|
||||
/// See the ASTImporter for the (few, but important) use cases.
|
||||
///
|
||||
/// FIXME: This is very inefficient; replace uses of it with uses of
|
||||
/// noload_lookup.
|
||||
void localUncachedLookup(DeclarationName Name,
|
||||
SmallVectorImpl<NamedDecl *> &Results);
|
||||
|
||||
@ -1458,10 +1537,16 @@ class DeclContext {
|
||||
/// of looking up every possible name.
|
||||
class all_lookups_iterator;
|
||||
|
||||
/// \brief Iterators over all possible lookups within this context.
|
||||
all_lookups_iterator lookups_begin() 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
|
||||
/// within this context.
|
||||
typedef UsingDirectiveDecl * const * udir_iterator;
|
||||
@ -1532,6 +1617,8 @@ class DeclContext {
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
|
||||
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpLookups() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpLookups(llvm::raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
void reconcileExternalVisibleStorage();
|
||||
@ -1548,6 +1635,8 @@ class DeclContext {
|
||||
friend class DependentDiagnostic;
|
||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||
|
||||
template<decl_iterator (DeclContext::*Begin)() const,
|
||||
decl_iterator (DeclContext::*End)() const>
|
||||
void buildLookupImpl(DeclContext *DCtx);
|
||||
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||
bool Rediscoverable);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <algorithm>
|
||||
@ -26,23 +27,29 @@ namespace clang {
|
||||
|
||||
class DependentDiagnostic;
|
||||
|
||||
/// StoredDeclsList - This is an array of decls optimized a common case of only
|
||||
/// containing one entry.
|
||||
/// \brief An array of decls optimized for the common case of only containing
|
||||
/// one entry.
|
||||
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;
|
||||
|
||||
/// \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,
|
||||
/// or a pointer to a vector.
|
||||
llvm::PointerUnion<NamedDecl *, DeclsTy *> Data;
|
||||
/// or a pointer to a vector with a flag to indicate if there are further
|
||||
/// external declarations.
|
||||
llvm::PointerUnion<NamedDecl*, DeclsAndHasExternalTy> Data;
|
||||
|
||||
public:
|
||||
StoredDeclsList() {}
|
||||
|
||||
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
|
||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||
Data = new DeclsTy(*RHSVec);
|
||||
Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec),
|
||||
RHS.hasExternalDecls());
|
||||
}
|
||||
|
||||
~StoredDeclsList() {
|
||||
@ -56,7 +63,7 @@ struct StoredDeclsList {
|
||||
delete Vector;
|
||||
Data = RHS.Data;
|
||||
if (DeclsTy *RHSVec = RHS.getAsVector())
|
||||
Data = new DeclsTy(*RHSVec);
|
||||
Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec), hasExternalDecls());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -66,8 +73,27 @@ struct StoredDeclsList {
|
||||
return Data.dyn_cast<NamedDecl *>();
|
||||
}
|
||||
|
||||
DeclsAndHasExternalTy getAsVectorAndHasExternal() const {
|
||||
return Data.dyn_cast<DeclsAndHasExternalTy>();
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -110,6 +136,8 @@ struct StoredDeclsList {
|
||||
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
|
||||
std::mem_fun(&Decl::isFromASTFile)),
|
||||
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.
|
||||
///
|
||||
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
|
||||
// form.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
DeclsTy *VT = new DeclsTy();
|
||||
VT->push_back(OldD);
|
||||
Data = VT;
|
||||
Data = DeclsAndHasExternalTy(VT, false);
|
||||
}
|
||||
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
|
@ -220,7 +220,7 @@ class CXXRecordDecl::friend_iterator {
|
||||
};
|
||||
|
||||
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 {
|
||||
@ -228,7 +228,7 @@ inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
|
||||
}
|
||||
|
||||
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;
|
||||
data().FirstFriend = FD;
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ class DeclContext::all_lookups_iterator {
|
||||
StoredDeclsMap::iterator End)
|
||||
: It(It), End(End) {}
|
||||
|
||||
DeclarationName getLookupName() const { return It->first; }
|
||||
|
||||
reference 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();
|
||||
if (Primary->hasExternalVisibleStorage())
|
||||
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
||||
@ -75,7 +77,7 @@ DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
||||
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();
|
||||
if (Primary->hasExternalVisibleStorage())
|
||||
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
||||
@ -84,6 +86,22 @@ DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
|
||||
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
|
||||
|
||||
#endif
|
||||
|
@ -452,7 +452,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
}
|
||||
|
||||
/// \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.
|
||||
virtual Stmt *getBody() const;
|
||||
@ -463,7 +463,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
void setBody(Stmt *B) { Body = B; }
|
||||
|
||||
/// \brief Returns whether this specific method is a definition.
|
||||
bool isThisDeclarationADefinition() const { return Body; }
|
||||
bool isThisDeclarationADefinition() const { return hasBody(); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
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<const ObjCProtocolDecl *, ObjCPropertyDecl*>
|
||||
ProtocolPropertyMap;
|
||||
|
||||
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
|
||||
|
||||
/// This routine collects list of properties to be implemented in the class.
|
||||
@ -1133,6 +1136,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
return lookupInstanceVariable(IVarName, ClassDeclared);
|
||||
}
|
||||
|
||||
ObjCProtocolDecl *lookupNestedProtocol(IdentifierInfo *Name);
|
||||
|
||||
// Lookup a method. First, we search locally. If a method isn't
|
||||
// found, we search referenced protocols and class categories.
|
||||
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
|
||||
@ -1196,14 +1201,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
using redeclarable_base::redecls_end;
|
||||
using redeclarable_base::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
/// Retrieves the canonical declaration of this Objective-C class.
|
||||
ObjCInterfaceDecl *getCanonicalDecl() {
|
||||
return getFirstDeclaration();
|
||||
}
|
||||
const ObjCInterfaceDecl *getCanonicalDecl() const {
|
||||
return getFirstDeclaration();
|
||||
}
|
||||
ObjCInterfaceDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||
const ObjCInterfaceDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||
|
||||
// Low-level accessor
|
||||
const Type *getTypeForDecl() const { return TypeForDecl; }
|
||||
@ -1244,10 +1246,12 @@ class ObjCIvarDecl : public FieldDecl {
|
||||
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
|
||||
bool synthesized)
|
||||
bool synthesized,
|
||||
bool backingIvarReferencedInAccessor)
|
||||
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
|
||||
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
|
||||
NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
|
||||
NextIvar(0), DeclAccess(ac), Synthesized(synthesized),
|
||||
BackingIvarReferencedInAccessor(backingIvarReferencedInAccessor) {}
|
||||
|
||||
public:
|
||||
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
|
||||
@ -1255,7 +1259,8 @@ class ObjCIvarDecl : public FieldDecl {
|
||||
IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
AccessControl ac, Expr *BW = NULL,
|
||||
bool synthesized=false);
|
||||
bool synthesized=false,
|
||||
bool backingIvarReferencedInAccessor=false);
|
||||
|
||||
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
@ -1277,6 +1282,13 @@ class ObjCIvarDecl : public FieldDecl {
|
||||
return DeclAccess == None ? Protected : AccessControl(DeclAccess);
|
||||
}
|
||||
|
||||
void setBackingIvarReferencedInAccessor(bool val) {
|
||||
BackingIvarReferencedInAccessor = val;
|
||||
}
|
||||
bool getBackingIvarReferencedInAccessor() const {
|
||||
return BackingIvarReferencedInAccessor;
|
||||
}
|
||||
|
||||
void setSynthesize(bool synth) { Synthesized = synth; }
|
||||
bool getSynthesize() const { return Synthesized; }
|
||||
|
||||
@ -1291,6 +1303,7 @@ class ObjCIvarDecl : public FieldDecl {
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
|
||||
unsigned DeclAccess : 3;
|
||||
unsigned Synthesized : 1;
|
||||
unsigned BackingIvarReferencedInAccessor : 1;
|
||||
};
|
||||
|
||||
|
||||
@ -1502,17 +1515,17 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
|
||||
using redeclarable_base::redecls_end;
|
||||
using redeclarable_base::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
/// Retrieves the canonical declaration of this Objective-C protocol.
|
||||
ObjCProtocolDecl *getCanonicalDecl() {
|
||||
return getFirstDeclaration();
|
||||
}
|
||||
const ObjCProtocolDecl *getCanonicalDecl() const {
|
||||
return getFirstDeclaration();
|
||||
}
|
||||
ObjCProtocolDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||
const ObjCProtocolDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||
|
||||
virtual void collectPropertiesToImplement(PropertyMap &PM,
|
||||
PropertyDeclOrder &PO) const;
|
||||
|
||||
void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
|
||||
ProtocolPropertyMap &PM) const;
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
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
|
||||
//
|
||||
@ -8,7 +8,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief This file defines OpenMP nodes.
|
||||
/// \brief This file defines OpenMP nodes for declarative directives.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -20,8 +20,6 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
class DeclRefExpr;
|
||||
|
||||
/// \brief This represents '#pragma omp threadprivate ...' directive.
|
||||
/// 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) :
|
||||
Decl(DK, DC, L), NumVars(0) { }
|
||||
|
||||
ArrayRef<const DeclRefExpr *> getVars() const {
|
||||
return ArrayRef<const DeclRefExpr *>(
|
||||
reinterpret_cast<const DeclRefExpr * const *>(this + 1),
|
||||
ArrayRef<const Expr *> getVars() const {
|
||||
return ArrayRef<const Expr *>(
|
||||
reinterpret_cast<const Expr * const *>(this + 1),
|
||||
NumVars);
|
||||
}
|
||||
|
||||
llvm::MutableArrayRef<DeclRefExpr *> getVars() {
|
||||
return llvm::MutableArrayRef<DeclRefExpr *>(
|
||||
reinterpret_cast<DeclRefExpr **>(this + 1),
|
||||
llvm::MutableArrayRef<Expr *> getVars() {
|
||||
return llvm::MutableArrayRef<Expr *>(
|
||||
reinterpret_cast<Expr **>(this + 1),
|
||||
NumVars);
|
||||
}
|
||||
|
||||
void setVars(ArrayRef<DeclRefExpr *> VL);
|
||||
void setVars(ArrayRef<Expr *> VL);
|
||||
|
||||
public:
|
||||
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
ArrayRef<DeclRefExpr *> VL);
|
||||
ArrayRef<Expr *> VL);
|
||||
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID, unsigned N);
|
||||
|
||||
typedef llvm::MutableArrayRef<DeclRefExpr *>::iterator varlist_iterator;
|
||||
typedef ArrayRef<const DeclRefExpr *>::iterator varlist_const_iterator;
|
||||
typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
|
||||
|
||||
unsigned varlist_size() const { return NumVars; }
|
||||
bool varlist_empty() const { return NumVars == 0; }
|
||||
|
@ -34,6 +34,8 @@ class TemplateTypeParmDecl;
|
||||
class NonTypeTemplateParmDecl;
|
||||
class TemplateTemplateParmDecl;
|
||||
class TypeAliasTemplateDecl;
|
||||
class VarTemplateDecl;
|
||||
class VarTemplatePartialSpecializationDecl;
|
||||
|
||||
/// \brief Stores a template parameter of any kind.
|
||||
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
|
||||
@ -629,9 +631,9 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
template <class decl_type> friend class RedeclarableTemplate;
|
||||
|
||||
/// \brief Retrieves the canonical declaration of this template.
|
||||
RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDeclaration(); }
|
||||
const RedeclarableTemplateDecl *getCanonicalDecl() const {
|
||||
return getFirstDeclaration();
|
||||
RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDecl(); }
|
||||
const RedeclarableTemplateDecl *getCanonicalDecl() const {
|
||||
return getFirstDecl();
|
||||
}
|
||||
|
||||
/// \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::getPreviousDecl;
|
||||
using redeclarable_base::getMostRecentDecl;
|
||||
using redeclarable_base::isFirstDecl;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
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
|
||||
/// function template.
|
||||
struct Common : CommonBase {
|
||||
Common() : InjectedArgs(0) { }
|
||||
Common() : InjectedArgs(), LazySpecializations() { }
|
||||
|
||||
/// \brief The function template specializations for this function
|
||||
/// 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
|
||||
/// require the use of this information.
|
||||
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,
|
||||
@ -771,12 +781,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
|
||||
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
|
||||
/// function template.
|
||||
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
|
||||
getSpecializations() const {
|
||||
return getCommonPtr()->Specializations;
|
||||
}
|
||||
getSpecializations() const;
|
||||
|
||||
/// \brief Add a specialization of this function template.
|
||||
///
|
||||
@ -815,14 +826,14 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// NULL if no such declaration exists.
|
||||
FunctionTemplateDecl *getPreviousDecl() {
|
||||
return cast_or_null<FunctionTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getPreviousDecl());
|
||||
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the previous declaration of this function template, or
|
||||
/// NULL if no such declaration exists.
|
||||
const FunctionTemplateDecl *getPreviousDecl() const {
|
||||
return cast_or_null<FunctionTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getPreviousDecl());
|
||||
static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
@ -847,7 +858,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// arguments for a function template, the notion is convenient when
|
||||
/// we need to perform substitutions inside the definition of a function
|
||||
/// template.
|
||||
std::pair<const TemplateArgument *, unsigned> getInjectedTemplateArgs();
|
||||
ArrayRef<TemplateArgument> getInjectedTemplateArgs();
|
||||
|
||||
/// \brief Create a function template node.
|
||||
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
@ -1377,7 +1388,7 @@ class ClassTemplateSpecializationDecl
|
||||
|
||||
/// \brief The template argument list deduced for the class template
|
||||
/// partial specialization itself.
|
||||
TemplateArgumentList *TemplateArgs;
|
||||
const TemplateArgumentList *TemplateArgs;
|
||||
};
|
||||
|
||||
/// \brief The template that this specialization specializes
|
||||
@ -1402,7 +1413,7 @@ class ClassTemplateSpecializationDecl
|
||||
ExplicitSpecializationInfo *ExplicitInfo;
|
||||
|
||||
/// \brief The template arguments used to describe this specialization.
|
||||
TemplateArgumentList *TemplateArgs;
|
||||
const TemplateArgumentList *TemplateArgs;
|
||||
|
||||
/// \brief The point where this template was instantiated (if any)
|
||||
SourceLocation PointOfInstantiation;
|
||||
@ -1438,9 +1449,9 @@ class ClassTemplateSpecializationDecl
|
||||
bool Qualified) const;
|
||||
|
||||
ClassTemplateSpecializationDecl *getMostRecentDecl() {
|
||||
CXXRecordDecl *Recent
|
||||
= cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDecl());
|
||||
if (!isa<ClassTemplateSpecializationDecl>(Recent)) {
|
||||
CXXRecordDecl *Recent = static_cast<CXXRecordDecl *>(
|
||||
this)->getMostRecentDecl();
|
||||
while (!isa<ClassTemplateSpecializationDecl>(Recent)) {
|
||||
// FIXME: Does injected class name need to be in the redeclarations chain?
|
||||
assert(Recent->isInjectedClassName() && Recent->getPreviousDecl());
|
||||
Recent = Recent->getPreviousDecl();
|
||||
@ -1553,7 +1564,7 @@ class ClassTemplateSpecializationDecl
|
||||
/// instantiation of the given class template partial specialization whose
|
||||
/// template arguments have been deduced.
|
||||
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
|
||||
TemplateArgumentList *TemplateArgs) {
|
||||
const TemplateArgumentList *TemplateArgs) {
|
||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
|
||||
"Already set to a class template partial specialization!");
|
||||
SpecializedPartialSpecialization *PS
|
||||
@ -1639,13 +1650,7 @@ class ClassTemplatePartialSpecializationDecl
|
||||
|
||||
/// \brief The source info for the template arguments as written.
|
||||
/// FIXME: redundant with TypeAsWritten?
|
||||
TemplateArgumentLoc *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;
|
||||
const ASTTemplateArgumentListInfo *ArgsAsWritten;
|
||||
|
||||
/// \brief The class template partial specialization from which this
|
||||
/// class template partial specialization was instantiated.
|
||||
@ -1663,16 +1668,12 @@ class ClassTemplatePartialSpecializationDecl
|
||||
ClassTemplateDecl *SpecializedTemplate,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
TemplateArgumentLoc *ArgInfos,
|
||||
unsigned NumArgInfos,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl,
|
||||
unsigned SequenceNumber);
|
||||
const ASTTemplateArgumentListInfo *ArgsAsWritten,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||
|
||||
ClassTemplatePartialSpecializationDecl()
|
||||
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
|
||||
TemplateParams(0), ArgsAsWritten(0),
|
||||
NumArgsAsWritten(0), SequenceNumber(0),
|
||||
InstantiatedFromMember(0, false) { }
|
||||
TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) { }
|
||||
|
||||
public:
|
||||
static ClassTemplatePartialSpecializationDecl *
|
||||
@ -1684,15 +1685,15 @@ class ClassTemplatePartialSpecializationDecl
|
||||
unsigned NumArgs,
|
||||
const TemplateArgumentListInfo &ArgInfos,
|
||||
QualType CanonInjectedType,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl,
|
||||
unsigned SequenceNumber);
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||
|
||||
static ClassTemplatePartialSpecializationDecl *
|
||||
CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
|
||||
return cast<ClassTemplatePartialSpecializationDecl>(
|
||||
ClassTemplateSpecializationDecl::getMostRecentDecl());
|
||||
static_cast<ClassTemplateSpecializationDecl *>(
|
||||
this)->getMostRecentDecl());
|
||||
}
|
||||
|
||||
/// Get the list of template parameters
|
||||
@ -1701,19 +1702,10 @@ class ClassTemplatePartialSpecializationDecl
|
||||
}
|
||||
|
||||
/// Get the template arguments as written.
|
||||
TemplateArgumentLoc *getTemplateArgsAsWritten() const {
|
||||
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
|
||||
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
|
||||
/// which this particular class template partial specialization was
|
||||
/// instantiated.
|
||||
@ -1735,15 +1727,15 @@ class ClassTemplatePartialSpecializationDecl
|
||||
/// \c Outer<float>::Inner<U*>, this function would return
|
||||
/// \c Outer<T>::Inner<U*>.
|
||||
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
|
||||
ClassTemplatePartialSpecializationDecl *First
|
||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
||||
ClassTemplatePartialSpecializationDecl *First =
|
||||
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
return First->InstantiatedFromMember.getPointer();
|
||||
}
|
||||
|
||||
void setInstantiatedFromMember(
|
||||
ClassTemplatePartialSpecializationDecl *PartialSpec) {
|
||||
ClassTemplatePartialSpecializationDecl *First
|
||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
||||
ClassTemplatePartialSpecializationDecl *First =
|
||||
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
First->InstantiatedFromMember.setPointer(PartialSpec);
|
||||
}
|
||||
|
||||
@ -1764,15 +1756,15 @@ class ClassTemplatePartialSpecializationDecl
|
||||
/// struct X<int>::Inner<T*> { /* ... */ };
|
||||
/// \endcode
|
||||
bool isMemberSpecialization() {
|
||||
ClassTemplatePartialSpecializationDecl *First
|
||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
||||
ClassTemplatePartialSpecializationDecl *First =
|
||||
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
return First->InstantiatedFromMember.getInt();
|
||||
}
|
||||
|
||||
/// \brief Note that this member template is a specialization.
|
||||
void setMemberSpecialization() {
|
||||
ClassTemplatePartialSpecializationDecl *First
|
||||
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
|
||||
ClassTemplatePartialSpecializationDecl *First =
|
||||
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
assert(First->InstantiatedFromMember.getPointer() &&
|
||||
"Only member templates can be member template specializations");
|
||||
return First->InstantiatedFromMember.setInt(true);
|
||||
@ -1821,7 +1813,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
QualType InjectedClassNameType;
|
||||
|
||||
/// \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/
|
||||
/// partial specializations that follow.
|
||||
@ -1900,14 +1892,23 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// NULL if no such declaration exists.
|
||||
ClassTemplateDecl *getPreviousDecl() {
|
||||
return cast_or_null<ClassTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getPreviousDecl());
|
||||
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the previous declaration of this class template, or
|
||||
/// NULL if no such declaration exists.
|
||||
const ClassTemplateDecl *getPreviousDecl() const {
|
||||
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() {
|
||||
@ -1926,11 +1927,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D,
|
||||
void *InsertPos);
|
||||
|
||||
/// \brief Return the next partial specialization sequence number.
|
||||
unsigned getNextPartialSpecSequenceNumber() {
|
||||
return getPartialSpecializations().size();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the partial specializations as an ordered list.
|
||||
void getPartialSpecializations(
|
||||
SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
|
||||
@ -2139,14 +2135,15 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// NULL if no such declaration exists.
|
||||
TypeAliasTemplateDecl *getPreviousDecl() {
|
||||
return cast_or_null<TypeAliasTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getPreviousDecl());
|
||||
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the previous declaration of this function template, or
|
||||
/// NULL if no such declaration exists.
|
||||
const TypeAliasTemplateDecl *getPreviousDecl() const {
|
||||
return cast_or_null<TypeAliasTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getPreviousDecl());
|
||||
static_cast<const RedeclarableTemplateDecl *>(
|
||||
this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
@ -2239,6 +2236,578 @@ class ClassScopeFunctionSpecializationDecl : public Decl {
|
||||
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *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 */
|
||||
|
||||
#endif
|
||||
|
@ -182,11 +182,16 @@ class DeclarationName {
|
||||
|
||||
// operator bool() - Evaluates true when this declaration name is
|
||||
// non-empty.
|
||||
operator bool() const {
|
||||
LLVM_EXPLICIT operator bool() const {
|
||||
return ((Ptr & PtrMask) != 0) ||
|
||||
(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.
|
||||
bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
|
||||
bool isObjCZeroArgSelector() const {
|
||||
@ -210,9 +215,6 @@ class DeclarationName {
|
||||
/// getNameAsString - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
||||
/// printName - Print the human-readable name to a stream.
|
||||
void printName(raw_ostream &OS) const;
|
||||
|
||||
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
||||
/// this declaration name, or NULL if this declaration name isn't a
|
||||
/// simple identifier.
|
||||
@ -302,6 +304,8 @@ class DeclarationName {
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, DeclarationName N);
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
inline bool operator<(DeclarationName LHS, DeclarationName RHS) {
|
||||
|
@ -53,7 +53,7 @@ class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
if (E->getCond()->isValueDependent())
|
||||
return;
|
||||
// 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) {
|
||||
|
@ -277,7 +277,6 @@ class Expr : public Stmt {
|
||||
MLV_IncompleteType,
|
||||
MLV_ConstQualified,
|
||||
MLV_ArrayType,
|
||||
MLV_ReadonlyProperty,
|
||||
MLV_NoSetterProperty,
|
||||
MLV_MemberFunction,
|
||||
MLV_SubObjCPropertySetting,
|
||||
@ -483,21 +482,22 @@ class Expr : public Stmt {
|
||||
///
|
||||
/// Note: This does not perform the implicit conversions required by C++11
|
||||
/// [expr.const]p5.
|
||||
bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
|
||||
bool isIntegerConstantExpr(llvm::APSInt &Result, const ASTContext &Ctx,
|
||||
SourceLocation *Loc = 0,
|
||||
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
|
||||
/// 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
|
||||
/// expression in C++11. Can only be used in C++.
|
||||
///
|
||||
/// Note: This does not perform the implicit conversions required by C++11
|
||||
/// [expr.const]p5.
|
||||
bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0,
|
||||
bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = 0,
|
||||
SourceLocation *Loc = 0) const;
|
||||
|
||||
/// 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
|
||||
/// that is not trivial.
|
||||
bool hasNonTrivialCall(ASTContext &Ctx);
|
||||
|
||||
|
||||
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
|
||||
/// integer. This must be called on an expression that constant folds to an
|
||||
/// integer.
|
||||
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
|
||||
SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
|
||||
|
||||
void EvaluateForOverflow(const ASTContext &Ctx,
|
||||
SmallVectorImpl<PartialDiagnosticAt> *Diag) const;
|
||||
|
||||
void EvaluateForOverflow(const ASTContext &Ctx) const;
|
||||
|
||||
/// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
|
||||
/// 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
|
||||
/// find the expression whose lifetime needs to be extended. Record
|
||||
/// the adjustments needed along the path.
|
||||
const Expr *
|
||||
skipRValueSubobjectAdjustments(
|
||||
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
|
||||
/// the LHSs of comma expressions and adjustments needed along the path.
|
||||
const Expr *skipRValueSubobjectAdjustments(
|
||||
SmallVectorImpl<const Expr *> &CommaLHS,
|
||||
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
|
||||
|
||||
/// Skip irrelevant expressions to find what should be materialize for
|
||||
/// binding with a reference.
|
||||
@ -893,7 +892,7 @@ class DeclRefExpr : public Expr {
|
||||
bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
|
||||
|
||||
/// \brief Helper to retrieve the optional NamedDecl through which this
|
||||
/// reference occured.
|
||||
/// reference occurred.
|
||||
NamedDecl *&getInternalFoundDecl() {
|
||||
assert(hasFoundDecl());
|
||||
if (hasQualifier())
|
||||
@ -902,12 +901,12 @@ class DeclRefExpr : public Expr {
|
||||
}
|
||||
|
||||
/// \brief Helper to retrieve the optional NamedDecl through which this
|
||||
/// reference occured.
|
||||
/// reference occurred.
|
||||
NamedDecl *getInternalFoundDecl() const {
|
||||
return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
|
||||
}
|
||||
|
||||
DeclRefExpr(ASTContext &Ctx,
|
||||
DeclRefExpr(const ASTContext &Ctx,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *D, bool refersToEnclosingLocal,
|
||||
@ -922,7 +921,7 @@ class DeclRefExpr : public Expr {
|
||||
|
||||
/// \brief Computes the type- and value-dependence flags for this
|
||||
/// declaration reference expression.
|
||||
void computeDependence(ASTContext &C);
|
||||
void computeDependence(const ASTContext &C);
|
||||
|
||||
public:
|
||||
DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T,
|
||||
@ -938,7 +937,7 @@ class DeclRefExpr : public Expr {
|
||||
computeDependence(D->getASTContext());
|
||||
}
|
||||
|
||||
static DeclRefExpr *Create(ASTContext &Context,
|
||||
static DeclRefExpr *Create(const ASTContext &Context,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *D,
|
||||
@ -948,7 +947,7 @@ class DeclRefExpr : public Expr {
|
||||
NamedDecl *FoundD = 0,
|
||||
const TemplateArgumentListInfo *TemplateArgs = 0);
|
||||
|
||||
static DeclRefExpr *Create(ASTContext &Context,
|
||||
static DeclRefExpr *Create(const ASTContext &Context,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *D,
|
||||
@ -959,7 +958,7 @@ class DeclRefExpr : public Expr {
|
||||
const TemplateArgumentListInfo *TemplateArgs = 0);
|
||||
|
||||
/// \brief Construct an empty declaration reference expression.
|
||||
static DeclRefExpr *CreateEmpty(ASTContext &Context,
|
||||
static DeclRefExpr *CreateEmpty(const ASTContext &Context,
|
||||
bool HasQualifier,
|
||||
bool HasFoundDecl,
|
||||
bool HasTemplateKWAndArgsInfo,
|
||||
@ -1000,7 +999,7 @@ class DeclRefExpr : public Expr {
|
||||
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
|
||||
/// presence of using declarations, etc. It always returns non-NULL, and may
|
||||
@ -1151,6 +1150,7 @@ class PredefinedExpr : public Expr {
|
||||
Func,
|
||||
Function,
|
||||
LFunction, // Same as Function, but as wide string.
|
||||
FuncDName,
|
||||
PrettyFunction,
|
||||
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
|
||||
/// 'virtual' keyword is omitted for virtual member functions.
|
||||
@ -1221,13 +1221,15 @@ class APNumericStorage {
|
||||
else
|
||||
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 {
|
||||
public:
|
||||
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 {
|
||||
@ -1235,7 +1237,7 @@ class APFloatStorage : private APNumericStorage {
|
||||
llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const {
|
||||
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());
|
||||
}
|
||||
};
|
||||
@ -1250,17 +1252,17 @@ class IntegerLiteral : public Expr, public APIntStorage {
|
||||
public:
|
||||
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
||||
// or UnsignedLongLongTy
|
||||
IntegerLiteral(ASTContext &C, const llvm::APInt &V, QualType type,
|
||||
IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type,
|
||||
SourceLocation l);
|
||||
|
||||
/// \brief Returns a new integer literal with value 'V' and type 'type'.
|
||||
/// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy,
|
||||
/// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V
|
||||
/// \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);
|
||||
/// \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 getLocEnd() const LLVM_READONLY { return Loc; }
|
||||
@ -1328,21 +1330,21 @@ class CharacterLiteral : public Expr {
|
||||
class FloatingLiteral : public Expr, private APFloatStorage {
|
||||
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);
|
||||
|
||||
/// \brief Construct an empty floating-point literal.
|
||||
explicit FloatingLiteral(ASTContext &C, EmptyShell Empty);
|
||||
explicit FloatingLiteral(const ASTContext &C, EmptyShell Empty);
|
||||
|
||||
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);
|
||||
static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty);
|
||||
static FloatingLiteral *Create(const ASTContext &C, EmptyShell Empty);
|
||||
|
||||
llvm::APFloat getValue() const {
|
||||
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");
|
||||
APFloatStorage::setValue(C, Val);
|
||||
}
|
||||
@ -1420,7 +1422,7 @@ class ImaginaryLiteral : public Expr {
|
||||
};
|
||||
|
||||
/// 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
|
||||
/// calling getByteLength(). The C type for a string is always a
|
||||
/// ConstantArrayType. In C++, the char type is const qualified, in C it is
|
||||
@ -1469,19 +1471,19 @@ class StringLiteral : public Expr {
|
||||
public:
|
||||
/// This is the "fully general" constructor that allows representation of
|
||||
/// strings formed from multiple concatenated tokens.
|
||||
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
|
||||
bool Pascal, QualType Ty,
|
||||
static StringLiteral *Create(const ASTContext &C, StringRef Str,
|
||||
StringKind Kind, bool Pascal, QualType Ty,
|
||||
const SourceLocation *Loc, unsigned NumStrs);
|
||||
|
||||
/// Simple constructor for string literals made from one token.
|
||||
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
|
||||
bool Pascal, QualType Ty,
|
||||
static StringLiteral *Create(const ASTContext &C, StringRef Str,
|
||||
StringKind Kind, bool Pascal, QualType Ty,
|
||||
SourceLocation Loc) {
|
||||
return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
|
||||
}
|
||||
|
||||
/// \brief Construct an empty string literal.
|
||||
static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
|
||||
static StringLiteral *CreateEmpty(const ASTContext &C, unsigned NumStrs);
|
||||
|
||||
StringRef getString() const {
|
||||
assert(CharByteWidth==1
|
||||
@ -1520,7 +1522,7 @@ class StringLiteral : public Expr {
|
||||
unsigned getCharByteWidth() const { return CharByteWidth; }
|
||||
|
||||
/// \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 getKind() const { return static_cast<StringKind>(Kind); }
|
||||
@ -1853,7 +1855,7 @@ class OffsetOfExpr : public Expr {
|
||||
// Number of sub-expressions (i.e. array subscript expressions).
|
||||
unsigned NumExprs;
|
||||
|
||||
OffsetOfExpr(ASTContext &C, QualType type,
|
||||
OffsetOfExpr(const ASTContext &C, QualType type,
|
||||
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
||||
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
|
||||
SourceLocation RParenLoc);
|
||||
@ -1864,12 +1866,12 @@ class OffsetOfExpr : public Expr {
|
||||
|
||||
public:
|
||||
|
||||
static OffsetOfExpr *Create(ASTContext &C, QualType type,
|
||||
static OffsetOfExpr *Create(const ASTContext &C, QualType type,
|
||||
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
||||
ArrayRef<OffsetOfNode> comps,
|
||||
ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
|
||||
|
||||
static OffsetOfExpr *CreateEmpty(ASTContext &C,
|
||||
static OffsetOfExpr *CreateEmpty(const ASTContext &C,
|
||||
unsigned NumComps, unsigned NumExprs);
|
||||
|
||||
/// getOperatorLoc - Return the location of the operator.
|
||||
@ -2133,10 +2135,11 @@ class CallExpr : public Expr {
|
||||
|
||||
protected:
|
||||
// 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,
|
||||
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) {
|
||||
assert(i < getNumPreArgs() && "Prearg access out of range!");
|
||||
@ -2154,11 +2157,11 @@ class CallExpr : public Expr {
|
||||
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
|
||||
|
||||
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);
|
||||
|
||||
/// \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]); }
|
||||
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.
|
||||
/// Any orphaned expressions are deleted by this, and any new operands are set
|
||||
/// to null.
|
||||
void setNumArgs(ASTContext& C, unsigned NumArgs);
|
||||
void setNumArgs(const ASTContext& C, unsigned NumArgs);
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
@ -2360,7 +2363,7 @@ class MemberExpr : public Expr {
|
||||
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
|
||||
HadMultipleCandidates(false) {}
|
||||
|
||||
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
|
||||
static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *memberdecl, DeclAccessPair founddecl,
|
||||
@ -2747,12 +2750,13 @@ class ImplicitCastExpr : public CastExpr {
|
||||
: 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,
|
||||
const CXXCastPath *BasePath,
|
||||
ExprValueKind Cat);
|
||||
|
||||
static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
|
||||
static ImplicitCastExpr *CreateEmpty(const ASTContext &Context,
|
||||
unsigned PathSize);
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return getSubExpr()->getLocStart();
|
||||
@ -2838,13 +2842,14 @@ class CStyleCastExpr : public ExplicitCastExpr {
|
||||
: ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { }
|
||||
|
||||
public:
|
||||
static CStyleCastExpr *Create(ASTContext &Context, QualType T,
|
||||
static CStyleCastExpr *Create(const ASTContext &Context, QualType T,
|
||||
ExprValueKind VK, CastKind K,
|
||||
Expr *Op, const CXXCastPath *BasePath,
|
||||
TypeSourceInfo *WrittenTy, SourceLocation L,
|
||||
SourceLocation R);
|
||||
|
||||
static CStyleCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
|
||||
static CStyleCastExpr *CreateEmpty(const ASTContext &Context,
|
||||
unsigned PathSize);
|
||||
|
||||
SourceLocation getLParenLoc() const { return LPLoc; }
|
||||
void setLParenLoc(SourceLocation L) { LPLoc = L; }
|
||||
@ -3412,7 +3417,7 @@ class ShuffleVectorExpr : public Expr {
|
||||
unsigned NumExprs;
|
||||
|
||||
public:
|
||||
ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type,
|
||||
ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type,
|
||||
SourceLocation BLoc, SourceLocation RP);
|
||||
|
||||
/// \brief Build an empty vector-shuffle expression.
|
||||
@ -3450,11 +3455,11 @@ class ShuffleVectorExpr : public Expr {
|
||||
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!");
|
||||
return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
|
||||
return getExpr(N+2)->EvaluateKnownConstInt(Ctx);
|
||||
}
|
||||
|
||||
// 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.
|
||||
/// This AST node is similar to the conditional operator (?:) in C, with
|
||||
/// the following exceptions:
|
||||
@ -3476,10 +3535,12 @@ class ChooseExpr : public Expr {
|
||||
enum { COND, LHS, RHS, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
|
||||
SourceLocation BuiltinLoc, RParenLoc;
|
||||
bool CondIsTrue;
|
||||
public:
|
||||
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs,
|
||||
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,
|
||||
(cond->isInstantiationDependent() ||
|
||||
lhs->isInstantiationDependent() ||
|
||||
@ -3487,7 +3548,7 @@ class ChooseExpr : public Expr {
|
||||
(cond->containsUnexpandedParameterPack() ||
|
||||
lhs->containsUnexpandedParameterPack() ||
|
||||
rhs->containsUnexpandedParameterPack())),
|
||||
BuiltinLoc(BLoc), RParenLoc(RP) {
|
||||
BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) {
|
||||
SubExprs[COND] = cond;
|
||||
SubExprs[LHS] = lhs;
|
||||
SubExprs[RHS] = rhs;
|
||||
@ -3498,12 +3559,21 @@ class ChooseExpr : public Expr {
|
||||
|
||||
/// isConditionTrue - Return whether the condition is true (i.e. not
|
||||
/// 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
|
||||
/// condition.
|
||||
Expr *getChosenSubExpr(const ASTContext &C) const {
|
||||
return isConditionTrue(C) ? getLHS() : getRHS();
|
||||
Expr *getChosenSubExpr() const {
|
||||
return isConditionTrue() ? getLHS() : getRHS();
|
||||
}
|
||||
|
||||
Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
|
||||
@ -3663,7 +3733,7 @@ class InitListExpr : public Expr {
|
||||
SourceLocation LBraceLoc, RBraceLoc;
|
||||
|
||||
/// 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:
|
||||
/// - the syntactic form, if this is in semantic form;
|
||||
/// - the semantic form, if this is in syntactic form.
|
||||
@ -3679,7 +3749,7 @@ class InitListExpr : public Expr {
|
||||
llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
|
||||
|
||||
public:
|
||||
InitListExpr(ASTContext &C, SourceLocation lbraceloc,
|
||||
InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
|
||||
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
|
||||
|
||||
/// \brief Build an empty initializer list.
|
||||
@ -3707,7 +3777,7 @@ class InitListExpr : public Expr {
|
||||
}
|
||||
|
||||
/// \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
|
||||
///
|
||||
@ -3715,7 +3785,7 @@ class InitListExpr : public Expr {
|
||||
/// initializers will be destroyed. If there are fewer than @p
|
||||
/// NumInits initializers, NULL expressions will be added for the
|
||||
/// 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
|
||||
/// 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
|
||||
/// initializer list will be extended with NULL expressions to
|
||||
/// 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
|
||||
/// 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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3794,13 +3868,6 @@ class InitListExpr : public Expr {
|
||||
InitListExprBits.HadArrayRangeDesignator = ARD;
|
||||
}
|
||||
|
||||
bool initializesStdInitializerList() const {
|
||||
return InitListExprBits.InitializesStdInitializerList != 0;
|
||||
}
|
||||
void setInitializesStdInitializerList(bool ISIL = true) {
|
||||
InitListExprBits.InitializesStdInitializerList = ISIL;
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY;
|
||||
SourceLocation getLocEnd() const LLVM_READONLY;
|
||||
|
||||
@ -3851,7 +3918,7 @@ class InitListExpr : public Expr {
|
||||
/// The InitListExpr contains three DesignatedInitExprs, the first of
|
||||
/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
|
||||
/// 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 {
|
||||
public:
|
||||
/// \brief Forward declaration of the Designator class.
|
||||
@ -3879,7 +3946,7 @@ class DesignatedInitExpr : public Expr {
|
||||
Designator *Designators;
|
||||
|
||||
|
||||
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
|
||||
DesignatedInitExpr(const ASTContext &C, QualType Ty, unsigned NumDesignators,
|
||||
const Designator *Designators,
|
||||
SourceLocation EqualOrColonLoc, bool GNUSyntax,
|
||||
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,
|
||||
ArrayRef<Expr*> IndexExprs,
|
||||
SourceLocation EqualOrColonLoc,
|
||||
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.
|
||||
unsigned size() const { return NumDesignators; }
|
||||
@ -4085,7 +4154,7 @@ class DesignatedInitExpr : public Expr {
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
/// of designators in [First, Last).
|
||||
void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First,
|
||||
const Designator *Last);
|
||||
void ExpandDesignator(const ASTContext &C, unsigned Idx,
|
||||
const Designator *First, const Designator *Last);
|
||||
|
||||
SourceRange getDesignatorsSourceRange() const;
|
||||
|
||||
@ -4188,8 +4257,8 @@ class ParenListExpr : public Expr {
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
ParenListExpr(ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs,
|
||||
SourceLocation rparenloc);
|
||||
ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
|
||||
ArrayRef<Expr*> exprs, SourceLocation rparenloc);
|
||||
|
||||
/// \brief Build an empty paren list.
|
||||
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
|
||||
@ -4262,7 +4331,7 @@ class GenericSelectionExpr : public Expr {
|
||||
SourceLocation GenericLoc, DefaultLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
GenericSelectionExpr(ASTContext &Context,
|
||||
GenericSelectionExpr(const ASTContext &Context,
|
||||
SourceLocation GenericLoc, Expr *ControllingExpr,
|
||||
ArrayRef<TypeSourceInfo*> AssocTypes,
|
||||
ArrayRef<Expr*> AssocExprs,
|
||||
@ -4271,7 +4340,7 @@ class GenericSelectionExpr : public Expr {
|
||||
unsigned ResultIndex);
|
||||
|
||||
/// This constructor is used in the result-dependent case.
|
||||
GenericSelectionExpr(ASTContext &Context,
|
||||
GenericSelectionExpr(const ASTContext &Context,
|
||||
SourceLocation GenericLoc, Expr *ControllingExpr,
|
||||
ArrayRef<TypeSourceInfo*> AssocTypes,
|
||||
ArrayRef<Expr*> AssocExprs,
|
||||
@ -4450,7 +4519,7 @@ class BlockExpr : public Expr {
|
||||
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
|
||||
/// This AST node provides support for reinterpreting a type to another
|
||||
/// type of the same size.
|
||||
class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr?
|
||||
class AsTypeExpr : public Expr {
|
||||
private:
|
||||
Stmt *SrcExpr;
|
||||
SourceLocation BuiltinLoc, RParenLoc;
|
||||
@ -4552,13 +4621,13 @@ class PseudoObjectExpr : public Expr {
|
||||
public:
|
||||
/// NoResult - A value for the result index indicating that there is
|
||||
/// 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,
|
||||
unsigned resultIndex);
|
||||
|
||||
static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell,
|
||||
static PseudoObjectExpr *Create(const ASTContext &Context, EmptyShell shell,
|
||||
unsigned numSemanticExprs);
|
||||
|
||||
/// 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) {}
|
||||
|
||||
public:
|
||||
static ObjCArrayLiteral *Create(ASTContext &C,
|
||||
static ObjCArrayLiteral *Create(const ASTContext &C,
|
||||
ArrayRef<Expr *> Elements,
|
||||
QualType T, ObjCMethodDecl * Method,
|
||||
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 getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
|
||||
@ -289,13 +290,13 @@ class ObjCDictionaryLiteral : public Expr {
|
||||
}
|
||||
|
||||
public:
|
||||
static ObjCDictionaryLiteral *Create(ASTContext &C,
|
||||
static ObjCDictionaryLiteral *Create(const ASTContext &C,
|
||||
ArrayRef<ObjCDictionaryElement> VK,
|
||||
bool HasPackExpansions,
|
||||
QualType T, ObjCMethodDecl *method,
|
||||
SourceRange SR);
|
||||
|
||||
static ObjCDictionaryLiteral *CreateEmpty(ASTContext &C,
|
||||
static ObjCDictionaryLiteral *CreateEmpty(const ASTContext &C,
|
||||
unsigned NumElements,
|
||||
bool HasPackExpansions);
|
||||
|
||||
@ -807,7 +808,7 @@ class ObjCSubscriptRefExpr : public Expr {
|
||||
explicit ObjCSubscriptRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCSubscriptRefExprClass, Empty) {}
|
||||
|
||||
static ObjCSubscriptRefExpr *Create(ASTContext &C,
|
||||
static ObjCSubscriptRefExpr *Create(const ASTContext &C,
|
||||
Expr *base,
|
||||
Expr *key, QualType T,
|
||||
ObjCMethodDecl *getMethod,
|
||||
@ -1003,13 +1004,13 @@ class ObjCMessageExpr : public Expr {
|
||||
return getNumSelectorLocs();
|
||||
}
|
||||
|
||||
static ObjCMessageExpr *alloc(ASTContext &C,
|
||||
static ObjCMessageExpr *alloc(const ASTContext &C,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBraceLoc,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
Selector Sel,
|
||||
SelectorLocationsKind &SelLocsK);
|
||||
static ObjCMessageExpr *alloc(ASTContext &C,
|
||||
static ObjCMessageExpr *alloc(const ASTContext &C,
|
||||
unsigned NumArgs,
|
||||
unsigned NumStoredSelLocs);
|
||||
|
||||
@ -1051,7 +1052,7 @@ class ObjCMessageExpr : public Expr {
|
||||
/// \param Args The message send arguments.
|
||||
///
|
||||
/// \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,
|
||||
SourceLocation LBracLoc,
|
||||
SourceLocation SuperLoc,
|
||||
@ -1087,7 +1088,7 @@ class ObjCMessageExpr : public Expr {
|
||||
/// \param Args The message send arguments.
|
||||
///
|
||||
/// \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,
|
||||
SourceLocation LBracLoc,
|
||||
TypeSourceInfo *Receiver,
|
||||
@ -1121,7 +1122,7 @@ class ObjCMessageExpr : public Expr {
|
||||
/// \param Args The message send arguments.
|
||||
///
|
||||
/// \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,
|
||||
SourceLocation LBracLoc,
|
||||
Expr *Receiver,
|
||||
@ -1139,7 +1140,7 @@ class ObjCMessageExpr : public Expr {
|
||||
///
|
||||
/// \param NumArgs The number of message arguments, not including
|
||||
/// the receiver.
|
||||
static ObjCMessageExpr *CreateEmpty(ASTContext &Context,
|
||||
static ObjCMessageExpr *CreateEmpty(const ASTContext &Context,
|
||||
unsigned NumArgs,
|
||||
unsigned NumStoredSelLocs);
|
||||
|
||||
|
@ -329,7 +329,12 @@ struct LazyOffsetPtr {
|
||||
/// \brief Whether this pointer is non-NULL.
|
||||
///
|
||||
/// 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.
|
||||
bool isOffset() const { return Ptr & 0x01; }
|
||||
|
@ -41,6 +41,7 @@ class GlobalDecl {
|
||||
GlobalDecl(const VarDecl *D) { Init(D);}
|
||||
GlobalDecl(const FunctionDecl *D) { Init(D); }
|
||||
GlobalDecl(const BlockDecl *D) { Init(D); }
|
||||
GlobalDecl(const CapturedDecl *D) { Init(D); }
|
||||
GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
|
||||
|
||||
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/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace clang {
|
||||
@ -64,18 +65,29 @@ class MangleBuffer {
|
||||
/// MangleContext - Context for tracking state which persists across multiple
|
||||
/// calls to the C++ name mangler.
|
||||
class MangleContext {
|
||||
public:
|
||||
enum ManglerKind {
|
||||
MK_Itanium,
|
||||
MK_Microsoft
|
||||
};
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
|
||||
ASTContext &Context;
|
||||
DiagnosticsEngine &Diags;
|
||||
const ManglerKind Kind;
|
||||
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
|
||||
|
||||
|
||||
public:
|
||||
ManglerKind getKind() const { return Kind; }
|
||||
|
||||
explicit MangleContext(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags)
|
||||
: Context(Context), Diags(Diags) { }
|
||||
DiagnosticsEngine &Diags,
|
||||
ManglerKind Kind)
|
||||
: Context(Context), Diags(Diags), Kind(Kind) {}
|
||||
|
||||
virtual ~MangleContext() { }
|
||||
|
||||
@ -96,8 +108,12 @@ class MangleContext {
|
||||
/// @name Mangler Entry Points
|
||||
/// @{
|
||||
|
||||
virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
|
||||
virtual void mangleName(const NamedDecl *D, raw_ostream &)=0;
|
||||
bool shouldMangleDeclName(const NamedDecl *D);
|
||||
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,
|
||||
const ThunkInfo &Thunk,
|
||||
raw_ostream &) = 0;
|
||||
@ -106,13 +122,6 @@ class MangleContext {
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleReferenceTemporary(const VarDecl *D,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
|
||||
const CXXRecordDecl *Type,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
@ -129,36 +138,78 @@ class MangleContext {
|
||||
const BlockDecl *BD, raw_ostream &Out);
|
||||
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
||||
raw_ostream &Out);
|
||||
// Do the right thing.
|
||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out,
|
||||
const NamedDecl *ID=0);
|
||||
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD,
|
||||
raw_ostream &);
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &);
|
||||
|
||||
// This is pretty lame.
|
||||
virtual void mangleItaniumGuardVariable(const VarDecl *D,
|
||||
raw_ostream &) {
|
||||
llvm_unreachable("Target does not support mangling guard variables");
|
||||
}
|
||||
// FIXME: Revisit this once we know what we need to do for MSVC compatibility.
|
||||
virtual void mangleItaniumThreadLocalInit(const VarDecl *D,
|
||||
raw_ostream &) {
|
||||
llvm_unreachable("Target does not support mangling thread_local variables");
|
||||
}
|
||||
virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D,
|
||||
raw_ostream &) {
|
||||
llvm_unreachable("Target does not support mangling thread_local variables");
|
||||
}
|
||||
virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) = 0;
|
||||
|
||||
virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &) = 0;
|
||||
|
||||
virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
|
||||
raw_ostream &) = 0;
|
||||
|
||||
/// Generates a unique string for an externally visible type for use with TBAA
|
||||
/// or type uniquing.
|
||||
/// TODO: Extend this to internal types by generating names that are unique
|
||||
/// across translation units so it can be used with LTO.
|
||||
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
MangleContext *createItaniumMangleContext(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags);
|
||||
MangleContext *createMicrosoftMangleContext(ASTContext &Context,
|
||||
DiagnosticsEngine &Diags);
|
||||
class ItaniumMangleContext : public MangleContext {
|
||||
public:
|
||||
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
|
||||
: 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
|
||||
|
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
|
||||
/// 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
|
||||
/// refers.
|
||||
|
@ -29,6 +29,11 @@ class ParentMap {
|
||||
/// visited and updated or inserted but not the parents of 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 *getParentIgnoreParens(Stmt *) const;
|
||||
Stmt *getParentIgnoreParenCasts(Stmt *) const;
|
||||
|
@ -39,8 +39,9 @@ struct PrintingPolicy {
|
||||
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
|
||||
SuppressUnwrittenScope(false), SuppressInitializers(false),
|
||||
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
|
||||
SuppressStrongLifetime(false), Bool(LO.Bool),
|
||||
TerseOutput(false), PolishForDeclaration(false) { }
|
||||
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
|
||||
Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false),
|
||||
MSWChar(LO.MicrosoftExt && !LO.WChar) { }
|
||||
|
||||
/// \brief What language we're printing.
|
||||
LangOptions LangOpts;
|
||||
@ -131,6 +132,10 @@ struct PrintingPolicy {
|
||||
/// ARC.
|
||||
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
|
||||
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
|
||||
unsigned Bool : 1;
|
||||
@ -146,6 +151,10 @@ struct PrintingPolicy {
|
||||
/// declaration tag; such as, do not print attributes attached to the declaration.
|
||||
///
|
||||
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
|
||||
|
@ -107,12 +107,9 @@ class RawComment {
|
||||
return RawText;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return Range;
|
||||
}
|
||||
|
||||
unsigned getBeginLine(const SourceManager &SM) const;
|
||||
unsigned getEndLine(const SourceManager &SM) const;
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
|
||||
|
||||
const char *getBriefText(const ASTContext &Context) const {
|
||||
if (BriefTextValid)
|
||||
@ -146,11 +143,6 @@ class RawComment {
|
||||
/// considered as documentation comments.
|
||||
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.
|
||||
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
|
||||
bool IsAlmostTrailingComment,
|
||||
@ -158,8 +150,7 @@ class RawComment {
|
||||
Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
|
||||
IsAttached(false), IsTrailingComment(IsTrailingComment),
|
||||
IsAlmostTrailingComment(IsAlmostTrailingComment),
|
||||
ParseAllComments(ParseAllComments),
|
||||
BeginLineValid(false), EndLineValid(false)
|
||||
ParseAllComments(ParseAllComments)
|
||||
{ }
|
||||
|
||||
StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
|
||||
@ -178,8 +169,7 @@ class BeforeThanCompare<RawComment> {
|
||||
explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
|
||||
|
||||
bool operator()(const RawComment &LHS, const RawComment &RHS) {
|
||||
return SM.isBeforeInTranslationUnit(LHS.getSourceRange().getBegin(),
|
||||
RHS.getSourceRange().getBegin());
|
||||
return SM.isBeforeInTranslationUnit(LHS.getLocStart(), RHS.getLocStart());
|
||||
}
|
||||
|
||||
bool operator()(const RawComment *LHS, const RawComment *RHS) {
|
||||
@ -191,8 +181,7 @@ class BeforeThanCompare<RawComment> {
|
||||
/// sorted in order of appearance in the translation unit.
|
||||
class RawCommentList {
|
||||
public:
|
||||
RawCommentList(SourceManager &SourceMgr) :
|
||||
SourceMgr(SourceMgr), OnlyWhitespaceSeen(true) { }
|
||||
RawCommentList(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
|
||||
|
||||
void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator);
|
||||
|
||||
@ -203,15 +192,9 @@ class RawCommentList {
|
||||
private:
|
||||
SourceManager &SourceMgr;
|
||||
std::vector<RawComment *> Comments;
|
||||
SourceLocation PrevCommentEndLoc;
|
||||
bool OnlyWhitespaceSeen;
|
||||
|
||||
void addCommentsToFront(const std::vector<RawComment *> &C) {
|
||||
size_t OldSize = Comments.size();
|
||||
Comments.resize(C.size() + OldSize);
|
||||
std::copy_backward(Comments.begin(), Comments.begin() + OldSize,
|
||||
Comments.end());
|
||||
std::copy(C.begin(), C.end(), Comments.begin());
|
||||
Comments.insert(Comments.begin(), C.begin(), C.end());
|
||||
}
|
||||
|
||||
friend class ASTReader;
|
||||
|
@ -93,10 +93,22 @@ class ASTRecordLayout {
|
||||
/// HasOwnVFPtr - Does this class provide a virtual function table
|
||||
/// (vtable in Itanium, vftbl in Microsoft) that is independent from
|
||||
/// 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.
|
||||
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 :)
|
||||
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
|
||||
@ -122,13 +134,16 @@ class ASTRecordLayout {
|
||||
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
|
||||
ASTRecordLayout(const ASTContext &Ctx,
|
||||
CharUnits size, CharUnits alignment,
|
||||
bool hasOwnVFPtr, CharUnits vbptroffset,
|
||||
bool hasOwnVFPtr, bool hasExtendableVFPtr,
|
||||
CharUnits vbptroffset,
|
||||
CharUnits datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
|
||||
CharUnits SizeOfLargestEmptySubobject,
|
||||
const CXXRecordDecl *PrimaryBase,
|
||||
bool IsPrimaryBaseVirtual,
|
||||
const CXXRecordDecl *BaseSharingVBPtr,
|
||||
bool ForceAlign,
|
||||
const BaseOffsetsMapTy& BaseOffsets,
|
||||
const VBaseOffsetsMapTy& VBaseOffsets);
|
||||
|
||||
@ -226,6 +241,37 @@ class ASTRecordLayout {
|
||||
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.
|
||||
/// This is only meaningful with the Microsoft ABI.
|
||||
CharUnits getVBPtrOffset() const {
|
||||
@ -233,6 +279,11 @@ class ASTRecordLayout {
|
||||
return CXXInfo->VBPtrOffset;
|
||||
}
|
||||
|
||||
const CXXRecordDecl *getBaseSharingVBPtr() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->BaseSharingVBPtr;
|
||||
}
|
||||
|
||||
const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->VBaseOffsets;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/AST/StmtOpenMP.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
@ -108,7 +109,7 @@ namespace clang {
|
||||
/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar
|
||||
/// is Foo's super class) before calling VisitFoo(), the result is
|
||||
/// 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()).
|
||||
///
|
||||
/// This scheme guarantees that all Visit*() calls for the same AST
|
||||
@ -243,8 +244,16 @@ class RecursiveASTVisitor {
|
||||
/// \brief Recursively visit a lambda capture.
|
||||
///
|
||||
/// \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 ----
|
||||
|
||||
// Declare Traverse*() for all concrete Stmt classes.
|
||||
@ -342,7 +351,7 @@ class RecursiveASTVisitor {
|
||||
// ---- Methods on TypeLocs ----
|
||||
// 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 TYPELOC(CLASS, BASE) \
|
||||
bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
|
||||
@ -398,8 +407,12 @@ class RecursiveASTVisitor {
|
||||
private:
|
||||
// These are helper methods used by more than one Traverse* method.
|
||||
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
|
||||
bool TraverseClassInstantiations(ClassTemplateDecl *D);
|
||||
bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
|
||||
#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
|
||||
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,
|
||||
unsigned Count);
|
||||
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
||||
@ -409,6 +422,13 @@ class RecursiveASTVisitor {
|
||||
bool TraverseDeclContextHelper(DeclContext *DC);
|
||||
bool TraverseFunctionHelper(FunctionDecl *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 {
|
||||
Stmt *S;
|
||||
@ -802,10 +822,20 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
|
||||
TRY_TO(TraverseStmt(LE->getBody()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Type traversal -----------------
|
||||
|
||||
// This macro makes available a variable T, the passed-in type.
|
||||
@ -844,6 +874,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, {
|
||||
TRY_TO(TraverseType(T->getPointeeType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(DecayedType, {
|
||||
TRY_TO(TraverseType(T->getOriginalType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(ConstantArrayType, {
|
||||
TRY_TO(TraverseType(T->getElementType()));
|
||||
})
|
||||
@ -1050,6 +1084,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DecayedType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
|
||||
})
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
|
||||
// This isn't available for ArrayType, but is for the ArrayTypeLoc.
|
||||
@ -1420,59 +1458,44 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
|
||||
return true;
|
||||
}
|
||||
|
||||
// A helper method for traversing the implicit instantiations of a
|
||||
// class template.
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
|
||||
ClassTemplateDecl *D) {
|
||||
ClassTemplateDecl::spec_iterator end = D->spec_end();
|
||||
for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
|
||||
ClassTemplateSpecializationDecl* SD = *it;
|
||||
|
||||
switch (SD->getSpecializationKind()) {
|
||||
// Visit the implicit instantiations with the requested pattern.
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
TRY_TO(TraverseDecl(SD));
|
||||
break;
|
||||
|
||||
// We don't need to do anything on an explicit instantiation
|
||||
// or explicit specialization because there will be an explicit
|
||||
// node for it elsewhere.
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
case TSK_ExplicitSpecialization:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
|
||||
/* A helper method for traversing the implicit instantiations of a
|
||||
class or variable template. */ \
|
||||
template<typename Derived> \
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( \
|
||||
TMPLDECLKIND##TemplateDecl *D) { \
|
||||
TMPLDECLKIND##TemplateDecl::spec_iterator end = D->spec_end(); \
|
||||
for (TMPLDECLKIND##TemplateDecl::spec_iterator it = D->spec_begin(); \
|
||||
it != end; ++it) { \
|
||||
TMPLDECLKIND##TemplateSpecializationDecl* SD = *it; \
|
||||
\
|
||||
switch (SD->getSpecializationKind()) { \
|
||||
/* Visit the implicit instantiations with the requested pattern. */ \
|
||||
case TSK_Undeclared: \
|
||||
case TSK_ImplicitInstantiation: \
|
||||
TRY_TO(TraverseDecl(SD)); \
|
||||
break; \
|
||||
\
|
||||
/* We don't need to do anything on an explicit instantiation
|
||||
or explicit specialization because there will be an explicit
|
||||
node for it elsewhere. */ \
|
||||
case TSK_ExplicitInstantiationDeclaration: \
|
||||
case TSK_ExplicitInstantiationDefinition: \
|
||||
case TSK_ExplicitSpecialization: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_DECL(ClassTemplateDecl, {
|
||||
CXXRecordDecl* TempDecl = D->getTemplatedDecl();
|
||||
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.
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TMPL_INST(Class)
|
||||
DEF_TRAVERSE_TMPL_INST(Var)
|
||||
|
||||
// A helper method for traversing the instantiations of a
|
||||
// function while skipping its specializations.
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
|
||||
FunctionTemplateDecl *D) {
|
||||
FunctionTemplateDecl::spec_iterator end = D->spec_end();
|
||||
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
|
||||
@ -1500,21 +1523,32 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
|
||||
TRY_TO(TraverseDecl(D->getTemplatedDecl()));
|
||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
|
||||
// By default, we do not traverse the instantiations of
|
||||
// function templates since they do not appear in the user code. The
|
||||
// following code optionally traverses them.
|
||||
//
|
||||
// We only traverse the function 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(TraverseFunctionInstantiations(D));
|
||||
// This macro unifies the traversal of class, variable and function
|
||||
// template declarations.
|
||||
#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \
|
||||
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \
|
||||
TRY_TO(TraverseDecl(D->getTemplatedDecl())); \
|
||||
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(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, {
|
||||
// D is the "T" in something like
|
||||
// template <template <typename> class T> class container { };
|
||||
@ -1607,27 +1641,31 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, {
|
||||
TRY_TO(TraverseCXXRecordHelper(D));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
|
||||
// For implicit instantiations ("set<int> x;"), we don't want to
|
||||
// recurse at all, since the instatiated class isn't written in
|
||||
// the source code anywhere. (Note the instatiated *type* --
|
||||
// set<int> -- is written, and will still get a callback of
|
||||
// TemplateSpecializationType). For explicit instantiations
|
||||
// ("template set<int>;"), we do need a callback, since this
|
||||
// is the only callback that's made for this instantiation.
|
||||
// We use getTypeAsWritten() to distinguish.
|
||||
if (TypeSourceInfo *TSI = D->getTypeAsWritten())
|
||||
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
|
||||
|
||||
if (!getDerived().shouldVisitTemplateInstantiations() &&
|
||||
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
|
||||
// Returning from here skips traversing the
|
||||
// declaration context of the ClassTemplateSpecializationDecl
|
||||
// (embedded in the DEF_TRAVERSE_DECL() macro)
|
||||
// which contains the instantiated members of the class.
|
||||
return true;
|
||||
#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND) \
|
||||
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
|
||||
/* For implicit instantiations ("set<int> x;"), we don't want to
|
||||
recurse at all, since the instatiated template isn't written in
|
||||
the source code anywhere. (Note the instatiated *type* --
|
||||
set<int> -- is written, and will still get a callback of
|
||||
TemplateSpecializationType). For explicit instantiations
|
||||
("template set<int>;"), we do need a callback, since this
|
||||
is the only callback that's made for this instantiation.
|
||||
We use getTypeAsWritten() to distinguish. */ \
|
||||
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
|
||||
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
|
||||
\
|
||||
if (!getDerived().shouldVisitTemplateInstantiations() && \
|
||||
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \
|
||||
/* Returning from here skips traversing the
|
||||
declaration context of the *TemplateSpecializationDecl
|
||||
(embedded in the DEF_TRAVERSE_DECL() macro)
|
||||
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>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
|
||||
const TemplateArgumentLoc *TAL, unsigned Count) {
|
||||
@ -1637,26 +1675,31 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
|
||||
// The partial specialization.
|
||||
if (TemplateParameterList *TPL = D->getTemplateParameters()) {
|
||||
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
|
||||
I != E; ++I) {
|
||||
TRY_TO(TraverseDecl(*I));
|
||||
}
|
||||
}
|
||||
// The args that remains unspecialized.
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten()));
|
||||
|
||||
// Don't need the ClassTemplatePartialSpecializationHelper, even
|
||||
// though that's our parent class -- we already visit all the
|
||||
// template args here.
|
||||
TRY_TO(TraverseCXXRecordHelper(D));
|
||||
|
||||
// Instantiations will have been visited with the primary template.
|
||||
#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
|
||||
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
|
||||
/* The partial specialization. */ \
|
||||
if (TemplateParameterList *TPL = D->getTemplateParameters()) { \
|
||||
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \
|
||||
I != E; ++I) { \
|
||||
TRY_TO(TraverseDecl(*I)); \
|
||||
} \
|
||||
} \
|
||||
/* The args that remains unspecialized. */ \
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper( \
|
||||
D->getTemplateArgsAsWritten()->getTemplateArgs(), \
|
||||
D->getTemplateArgsAsWritten()->NumTemplateArgs)); \
|
||||
\
|
||||
/* Don't need the *TemplatePartialSpecializationHelper, even
|
||||
though that's our parent class -- we already visit all the
|
||||
template args here. */ \
|
||||
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, {
|
||||
TRY_TO(TraverseStmt(D->getInitExpr()));
|
||||
})
|
||||
@ -1736,6 +1779,14 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
|
||||
// including exception specifications.
|
||||
if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
|
||||
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)) {
|
||||
@ -2117,10 +2168,12 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
|
||||
// Walk only the visible parts of lambda expressions.
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
||||
TRY_TO(WalkUpFromLambdaExpr(S));
|
||||
|
||||
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
|
||||
CEnd = S->explicit_capture_end();
|
||||
C != CEnd; ++C) {
|
||||
TRY_TO(TraverseLambdaCapture(*C));
|
||||
TRY_TO(TraverseLambdaCapture(S, C));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2174,6 +2227,7 @@ DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
|
||||
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
|
||||
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
|
||||
@ -2211,6 +2265,7 @@ DEF_TRAVERSE_STMT(ParenExpr, { })
|
||||
DEF_TRAVERSE_STMT(ParenListExpr, { })
|
||||
DEF_TRAVERSE_STMT(PredefinedExpr, { })
|
||||
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
|
||||
DEF_TRAVERSE_STMT(ConvertVectorExpr, { })
|
||||
DEF_TRAVERSE_STMT(StmtExpr, { })
|
||||
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
@ -2269,6 +2324,61 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
|
||||
// Traverse OpenCL: AsType, Convert.
|
||||
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
|
||||
// need to recurse on anything. These are ones that have methods
|
||||
// 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
|
||||
/// is the only declaration.
|
||||
decl_type *getFirstDeclaration() {
|
||||
decl_type *getFirstDecl() {
|
||||
decl_type *D = static_cast<decl_type*>(this);
|
||||
while (D->getPreviousDecl())
|
||||
D = D->getPreviousDecl();
|
||||
@ -84,31 +84,29 @@ class Redeclarable {
|
||||
|
||||
/// \brief Return the first declaration of this declaration or itself if this
|
||||
/// is the only declaration.
|
||||
const decl_type *getFirstDeclaration() const {
|
||||
const decl_type *getFirstDecl() const {
|
||||
const decl_type *D = static_cast<const decl_type*>(this);
|
||||
while (D->getPreviousDecl())
|
||||
D = D->getPreviousDecl();
|
||||
return D;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this is the first declaration.
|
||||
bool isFirstDeclaration() const {
|
||||
return RedeclLink.NextIsLatest();
|
||||
}
|
||||
/// \brief True if this is the first declaration in its redeclaration chain.
|
||||
bool isFirstDecl() const { return RedeclLink.NextIsLatest(); }
|
||||
|
||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||
decl_type *getMostRecentDecl() {
|
||||
return getFirstDeclaration()->RedeclLink.getNext();
|
||||
return getFirstDecl()->RedeclLink.getNext();
|
||||
}
|
||||
|
||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||
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
|
||||
/// first and only declaration.
|
||||
void setPreviousDeclaration(decl_type *PrevDecl);
|
||||
void setPreviousDecl(decl_type *PrevDecl);
|
||||
|
||||
/// \brief Iterates through all the redeclarations of the same decl.
|
||||
class redecl_iterator {
|
||||
@ -134,7 +132,7 @@ class Redeclarable {
|
||||
redecl_iterator& operator++() {
|
||||
assert(Current && "Advancing while iterator has reached end");
|
||||
// Sanity check to avoid infinite loop on invalid redecl chain.
|
||||
if (Current->isFirstDeclaration()) {
|
||||
if (Current->isFirstDecl()) {
|
||||
if (PassedFirst) {
|
||||
assert(0 && "Passed first decl twice, invalid redecl chain!");
|
||||
Current = 0;
|
||||
@ -175,6 +173,40 @@ class Redeclarable {
|
||||
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
|
||||
|
@ -266,10 +266,6 @@ class Stmt {
|
||||
/// Whether this initializer list originally had a GNU array-range
|
||||
/// designator in it. This is a temporary marker used by CodeGen.
|
||||
unsigned HadArrayRangeDesignator : 1;
|
||||
|
||||
/// Whether this initializer list initializes a std::initializer_list
|
||||
/// object.
|
||||
unsigned InitializesStdInitializerList : 1;
|
||||
};
|
||||
|
||||
class TypeTraitExprBitfields {
|
||||
@ -289,7 +285,7 @@ class Stmt {
|
||||
/// \brief The number of arguments to this type trait.
|
||||
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
|
||||
};
|
||||
|
||||
|
||||
union {
|
||||
// FIXME: this is wasteful on 64-bit platforms.
|
||||
void *Aligner;
|
||||
@ -316,19 +312,21 @@ class Stmt {
|
||||
public:
|
||||
// Only allow allocation of Stmts using the allocator in ASTContext
|
||||
// or by doing a placement new.
|
||||
void* operator new(size_t bytes, ASTContext& C,
|
||||
unsigned alignment = 8) throw();
|
||||
void* operator new(size_t bytes, const ASTContext& C,
|
||||
unsigned alignment = 8);
|
||||
|
||||
void* operator new(size_t bytes, ASTContext* C,
|
||||
unsigned alignment = 8) throw();
|
||||
void* operator new(size_t bytes, const ASTContext* C,
|
||||
unsigned alignment = 8) {
|
||||
return operator new(bytes, *C, alignment);
|
||||
}
|
||||
|
||||
void* operator new(size_t bytes, void* mem) throw() {
|
||||
return mem;
|
||||
}
|
||||
|
||||
void operator delete(void*, ASTContext&, unsigned) throw() { }
|
||||
void operator delete(void*, ASTContext*, unsigned) throw() { }
|
||||
void operator delete(void*, std::size_t) throw() { }
|
||||
void operator delete(void*, const ASTContext&, unsigned) throw() { }
|
||||
void operator delete(void*, const ASTContext*, unsigned) throw() { }
|
||||
void operator delete(void*, size_t) throw() { }
|
||||
void operator delete(void*, void*) throw() { }
|
||||
|
||||
public:
|
||||
@ -382,7 +380,7 @@ class Stmt {
|
||||
|
||||
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
|
||||
/// 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,
|
||||
const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0) const;
|
||||
@ -401,13 +399,6 @@ class Stmt {
|
||||
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'
|
||||
/// to permit easy iteration over the substatements/subexpessions of an
|
||||
/// AST node. This permits easy iteration over all nodes in the AST.
|
||||
@ -553,10 +544,10 @@ class CompoundStmt : public Stmt {
|
||||
Stmt** Body;
|
||||
SourceLocation LBracLoc, RBracLoc;
|
||||
public:
|
||||
CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
|
||||
CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
|
||||
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)
|
||||
: Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) {
|
||||
CompoundStmtBits.NumStmts = 0;
|
||||
@ -568,7 +559,7 @@ class CompoundStmt : public Stmt {
|
||||
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; }
|
||||
unsigned size() const { return CompoundStmtBits.NumStmts; }
|
||||
@ -827,10 +818,10 @@ class AttributedStmt : public Stmt {
|
||||
}
|
||||
|
||||
public:
|
||||
static AttributedStmt *Create(ASTContext &C, SourceLocation Loc,
|
||||
static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
|
||||
ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
|
||||
// \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; }
|
||||
ArrayRef<const Attr*> getAttrs() const {
|
||||
@ -860,7 +851,7 @@ class IfStmt : public Stmt {
|
||||
SourceLocation ElseLoc;
|
||||
|
||||
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);
|
||||
|
||||
/// \brief Build an empty if/then/else statement
|
||||
@ -875,7 +866,7 @@ class IfStmt : public Stmt {
|
||||
/// }
|
||||
/// \endcode
|
||||
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
|
||||
/// associated with the creation of that condition variable.
|
||||
@ -933,7 +924,7 @@ class SwitchStmt : public Stmt {
|
||||
unsigned AllEnumCasesCovered : 1;
|
||||
|
||||
public:
|
||||
SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond);
|
||||
SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
|
||||
|
||||
/// \brief Build a empty switch statement.
|
||||
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
|
||||
@ -948,7 +939,7 @@ class SwitchStmt : public Stmt {
|
||||
/// }
|
||||
/// \endcode
|
||||
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
|
||||
/// associated with the creation of that condition variable.
|
||||
@ -967,9 +958,6 @@ class SwitchStmt : public Stmt {
|
||||
SwitchCase *getSwitchCaseList() { return FirstCase; }
|
||||
|
||||
/// \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; }
|
||||
|
||||
SourceLocation getSwitchLoc() const { return SwitchLoc; }
|
||||
@ -1021,7 +1009,7 @@ class WhileStmt : public Stmt {
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
SourceLocation WhileLoc;
|
||||
public:
|
||||
WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
|
||||
WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
|
||||
SourceLocation WL);
|
||||
|
||||
/// \brief Build an empty while statement.
|
||||
@ -1036,7 +1024,7 @@ class WhileStmt : public Stmt {
|
||||
/// }
|
||||
/// \endcode
|
||||
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
|
||||
/// associated with the creation of that condition variable.
|
||||
@ -1129,8 +1117,9 @@ class ForStmt : public Stmt {
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc,
|
||||
Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP);
|
||||
ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
|
||||
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
|
||||
SourceLocation RP);
|
||||
|
||||
/// \brief Build an empty for statement.
|
||||
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
|
||||
@ -1146,7 +1135,7 @@ class ForStmt : public Stmt {
|
||||
/// }
|
||||
/// \endcode
|
||||
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
|
||||
/// associated with the creation of that condition variable.
|
||||
@ -1417,7 +1406,7 @@ class AsmStmt : public Stmt {
|
||||
//===--- Asm String Analysis ---===//
|
||||
|
||||
/// Assemble final IR asm string.
|
||||
std::string generateAsmString(ASTContext &C) const;
|
||||
std::string generateAsmString(const ASTContext &C) const;
|
||||
|
||||
//===--- Output operands ---===//
|
||||
|
||||
@ -1520,7 +1509,7 @@ class GCCAsmStmt : public AsmStmt {
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
|
||||
GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
|
||||
bool isvolatile, unsigned numoutputs, unsigned numinputs,
|
||||
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
|
||||
StringLiteral *asmstr, unsigned numclobbers,
|
||||
@ -1586,10 +1575,10 @@ class GCCAsmStmt : public AsmStmt {
|
||||
/// translation of strings from GCC syntax to LLVM IR syntax, and handles
|
||||
//// flattening of named references like %[foo] to Operand AsmStringPiece's.
|
||||
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
|
||||
ASTContext &C, unsigned &DiagOffs) const;
|
||||
const ASTContext &C, unsigned &DiagOffs) const;
|
||||
|
||||
/// Assemble final IR asm string.
|
||||
std::string generateAsmString(ASTContext &C) const;
|
||||
std::string generateAsmString(const ASTContext &C) const;
|
||||
|
||||
//===--- Output operands ---===//
|
||||
|
||||
@ -1649,7 +1638,7 @@ class GCCAsmStmt : public AsmStmt {
|
||||
}
|
||||
|
||||
private:
|
||||
void setOutputsAndInputsAndClobbers(ASTContext &C,
|
||||
void setOutputsAndInputsAndClobbers(const ASTContext &C,
|
||||
IdentifierInfo **Names,
|
||||
StringLiteral **Constraints,
|
||||
Stmt **Exprs,
|
||||
@ -1695,9 +1684,9 @@ class MSAsmStmt : public AsmStmt {
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc,
|
||||
bool issimple, bool isvolatile, ArrayRef<Token> asmtoks,
|
||||
unsigned numoutputs, unsigned numinputs,
|
||||
MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
|
||||
SourceLocation lbraceloc, bool issimple, bool isvolatile,
|
||||
ArrayRef<Token> asmtoks, unsigned numoutputs, unsigned numinputs,
|
||||
ArrayRef<StringRef> constraints,
|
||||
ArrayRef<Expr*> exprs, StringRef asmstr,
|
||||
ArrayRef<StringRef> clobbers, SourceLocation endloc);
|
||||
@ -1720,7 +1709,7 @@ class MSAsmStmt : public AsmStmt {
|
||||
StringRef getAsmString() const { return AsmStr; }
|
||||
|
||||
/// Assemble final IR asm string.
|
||||
std::string generateAsmString(ASTContext &C) const;
|
||||
std::string generateAsmString(const ASTContext &C) const;
|
||||
|
||||
//===--- Output operands ---===//
|
||||
|
||||
@ -1765,12 +1754,9 @@ class MSAsmStmt : public AsmStmt {
|
||||
StringRef getClobber(unsigned i) const { return getClobbers()[i]; }
|
||||
|
||||
private:
|
||||
void initialize(ASTContext &C,
|
||||
StringRef AsmString,
|
||||
ArrayRef<Token> AsmToks,
|
||||
ArrayRef<StringRef> Constraints,
|
||||
ArrayRef<Expr*> Exprs,
|
||||
ArrayRef<StringRef> Clobbers);
|
||||
void initialize(const ASTContext &C, StringRef AsmString,
|
||||
ArrayRef<Token> AsmToks, ArrayRef<StringRef> Constraints,
|
||||
ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers);
|
||||
public:
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
|
||||
@ -1800,7 +1786,7 @@ class SEHExceptStmt : public Stmt {
|
||||
explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { }
|
||||
|
||||
public:
|
||||
static SEHExceptStmt* Create(ASTContext &C,
|
||||
static SEHExceptStmt* Create(const ASTContext &C,
|
||||
SourceLocation ExceptLoc,
|
||||
Expr *FilterExpr,
|
||||
Stmt *Block);
|
||||
@ -1841,7 +1827,7 @@ class SEHFinallyStmt : public Stmt {
|
||||
explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { }
|
||||
|
||||
public:
|
||||
static SEHFinallyStmt* Create(ASTContext &C,
|
||||
static SEHFinallyStmt* Create(const ASTContext &C,
|
||||
SourceLocation FinallyLoc,
|
||||
Stmt *Block);
|
||||
|
||||
@ -1880,10 +1866,8 @@ class SEHTryStmt : public Stmt {
|
||||
explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { }
|
||||
|
||||
public:
|
||||
static SEHTryStmt* Create(ASTContext &C,
|
||||
bool isCXXTry,
|
||||
SourceLocation TryLoc,
|
||||
Stmt *TryBlock,
|
||||
static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry,
|
||||
SourceLocation TryLoc, Stmt *TryBlock,
|
||||
Stmt *Handler);
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
|
||||
@ -2006,13 +1990,13 @@ class CapturedStmt : public Stmt {
|
||||
void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; }
|
||||
|
||||
public:
|
||||
static CapturedStmt *Create(ASTContext &Context, Stmt *S,
|
||||
static CapturedStmt *Create(const ASTContext &Context, Stmt *S,
|
||||
CapturedRegionKind Kind,
|
||||
ArrayRef<Capture> Captures,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
CapturedDecl *CD, RecordDecl *RD);
|
||||
|
||||
static CapturedStmt *CreateDeserialized(ASTContext &Context,
|
||||
static CapturedStmt *CreateDeserialized(const ASTContext &Context,
|
||||
unsigned NumCaptures);
|
||||
|
||||
/// \brief Retrieve the statement being captured.
|
||||
|
@ -79,10 +79,10 @@ class CXXTryStmt : public Stmt {
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc,
|
||||
static CXXTryStmt *Create(const ASTContext &C, SourceLocation tryLoc,
|
||||
Stmt *tryBlock, ArrayRef<Stmt*> handlers);
|
||||
|
||||
static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty,
|
||||
static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty,
|
||||
unsigned numHandlers);
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_CLANG_AST_STMT_ITR_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
@ -28,18 +29,14 @@ class VariableArrayType;
|
||||
|
||||
class StmtIteratorBase {
|
||||
protected:
|
||||
enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3,
|
||||
enum { StmtMode = 0x0, SizeOfTypeVAMode = 0x1, DeclGroupMode = 0x2,
|
||||
Flags = 0x3 };
|
||||
|
||||
Stmt **stmt;
|
||||
union { Decl *decl; Decl **DGI; };
|
||||
Decl **DGI;
|
||||
uintptr_t RawVAPtr;
|
||||
Decl **DGE;
|
||||
|
||||
bool inDecl() const {
|
||||
return (RawVAPtr & Flags) == DeclMode;
|
||||
}
|
||||
|
||||
bool inDeclGroup() const {
|
||||
return (RawVAPtr & Flags) == DeclGroupMode;
|
||||
}
|
||||
@ -49,7 +46,7 @@ class StmtIteratorBase {
|
||||
}
|
||||
|
||||
bool inStmt() const {
|
||||
return (RawVAPtr & Flags) == 0;
|
||||
return (RawVAPtr & Flags) == StmtMode;
|
||||
}
|
||||
|
||||
const VariableArrayType *getVAPtr() const {
|
||||
@ -57,7 +54,7 @@ class StmtIteratorBase {
|
||||
}
|
||||
|
||||
void setVAPtr(const VariableArrayType *P) {
|
||||
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
|
||||
assert (inDeclGroup() || inSizeOfTypeVA());
|
||||
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
||||
}
|
||||
|
||||
@ -67,11 +64,10 @@ class StmtIteratorBase {
|
||||
|
||||
Stmt*& GetDeclExpr() const;
|
||||
|
||||
StmtIteratorBase(Stmt **s) : stmt(s), decl(0), RawVAPtr(0) {}
|
||||
StmtIteratorBase(Decl *d, Stmt **s);
|
||||
StmtIteratorBase(Stmt **s) : stmt(s), DGI(0), RawVAPtr(0) {}
|
||||
StmtIteratorBase(const VariableArrayType *t);
|
||||
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(Stmt **s) : StmtIteratorBase(s) {}
|
||||
StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {}
|
||||
StmtIteratorImpl(Decl *d, Stmt **s) : StmtIteratorBase(d, s) {}
|
||||
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
|
||||
|
||||
DERIVED& operator++() {
|
||||
@ -107,15 +102,15 @@ class StmtIteratorImpl : public StmtIteratorBase,
|
||||
}
|
||||
|
||||
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 {
|
||||
return stmt != RHS.stmt || decl != RHS.decl || RawVAPtr != RHS.RawVAPtr;
|
||||
return stmt != RHS.stmt || DGI != RHS.DGI || RawVAPtr != RHS.RawVAPtr;
|
||||
}
|
||||
|
||||
REFERENCE operator*() const {
|
||||
return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
|
||||
return inStmt() ? *stmt : GetDeclExpr();
|
||||
}
|
||||
|
||||
REFERENCE operator->() const { return operator*(); }
|
||||
@ -131,9 +126,6 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
||||
|
||||
StmtIterator(const VariableArrayType *t)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||
|
||||
StmtIterator(Decl* D, Stmt **s = 0)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(D, s) {}
|
||||
};
|
||||
|
||||
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||
@ -156,7 +148,7 @@ struct StmtRange : std::pair<StmtIterator,StmtIterator> {
|
||||
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
|
||||
|
||||
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*(); }
|
||||
@ -199,7 +191,7 @@ struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||
|
||||
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*(); }
|
||||
|
@ -181,13 +181,12 @@ class ObjCAtTryStmt : public Stmt {
|
||||
HasFinally(HasFinally) { }
|
||||
|
||||
public:
|
||||
static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc,
|
||||
Stmt *atTryStmt,
|
||||
static ObjCAtTryStmt *Create(const ASTContext &Context,
|
||||
SourceLocation atTryLoc, Stmt *atTryStmt,
|
||||
Stmt **CatchStmts, unsigned NumCatchStmts,
|
||||
Stmt *atFinallyStmt);
|
||||
static ObjCAtTryStmt *CreateEmpty(ASTContext &Context,
|
||||
unsigned NumCatchStmts,
|
||||
bool HasFinally);
|
||||
static ObjCAtTryStmt *CreateEmpty(const ASTContext &Context,
|
||||
unsigned NumCatchStmts, bool HasFinally);
|
||||
|
||||
/// \brief Retrieve the location of the @ in the \@try.
|
||||
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