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:
Dimitry Andric 2013-12-22 00:07:40 +00:00
parent 6a0372513e
commit bfef399519
3456 changed files with 237497 additions and 49213 deletions

1
.clang-format Normal file
View File

@ -0,0 +1 @@
BasedOnStyle: LLVM

View File

@ -19,12 +19,14 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
endif() endif()
endif() endif()
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" ) if (EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
# Looking for bin/Debug/llvm-tblgen is a complete hack. How can we get set (PATH_TO_LLVM_CONFIG "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
elseif (EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
# Looking for bin/Debug/llvm-config is a complete hack. How can we get
# around this? # around this?
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" ) set (PATH_TO_LLVM_CONFIG "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.") else()
endif() message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
endif() endif()
list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake") list(APPEND CMAKE_MODULE_PATH "${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
@ -32,6 +34,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
get_filename_component(PATH_TO_LLVM_BUILD ${CLANG_PATH_TO_LLVM_BUILD} get_filename_component(PATH_TO_LLVM_BUILD ${CLANG_PATH_TO_LLVM_BUILD}
ABSOLUTE) ABSOLUTE)
option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install' target." OFF)
include(AddLLVM) include(AddLLVM)
include(TableGen) include(TableGen)
include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake") include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
@ -46,12 +50,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}") include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
link_directories("${PATH_TO_LLVM_BUILD}/lib") link_directories("${PATH_TO_LLVM_BUILD}/lib")
if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" ) exec_program("${PATH_TO_LLVM_CONFIG} --bindir" OUTPUT_VARIABLE LLVM_BINARY_DIR)
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}") set(LLVM_TABLEGEN_EXE "${LLVM_BINARY_DIR}/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
else()
# FIXME: This is an utter hack.
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
endif()
# Define the default arguments to use with 'lit', and an option for the user # Define the default arguments to use with 'lit', and an option for the user
# to override. # to override.
@ -90,6 +90,16 @@ if( CLANG_VENDOR )
add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " ) add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
endif() endif()
set(CLANG_REPOSITORY_STRING "" CACHE STRING
"Vendor-specific text for showing the repository the source is taken from.")
if(CLANG_REPOSITORY_STRING)
add_definitions(-DCLANG_REPOSITORY_STRING="${CLANG_REPOSITORY_STRING}")
endif()
set(CLANG_VENDOR_UTI "org.llvm.clang" CACHE STRING
"Vendor-specific uti.")
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
@ -151,7 +161,7 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
endif () endif ()
if (APPLE) if (APPLE)
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
endif () endif ()
configure_file( configure_file(
@ -189,6 +199,41 @@ function(clang_tablegen)
endif() endif()
endfunction(clang_tablegen) endfunction(clang_tablegen)
# FIXME: Generalize and move to llvm.
function(add_clang_symbol_exports target_name export_file)
# Makefile.rules contains special cases for different platforms.
# We restrict ourselves to Darwin for the time being.
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
add_custom_command(OUTPUT symbol.exports
COMMAND sed -e "s/^/_/" < ${export_file} > symbol.exports
DEPENDS ${export_file}
VERBATIM
COMMENT "Creating export file for ${target_name}")
add_custom_target(${target_name}_exports DEPENDS symbol.exports)
set_property(DIRECTORY APPEND
PROPERTY ADDITIONAL_MAKE_CLEAN_FILES symbol.exports)
get_property(srcs TARGET ${target_name} PROPERTY SOURCES)
foreach(src ${srcs})
get_filename_component(extension ${src} EXT)
if(extension STREQUAL ".cpp")
set(first_source_file ${src})
break()
endif()
endforeach()
# Force re-linking when the exports file changes. Actually, it
# forces recompilation of the source file. The LINK_DEPENDS target
# property only works for makefile-based generators.
set_property(SOURCE ${first_source_file} APPEND PROPERTY
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/symbol.exports)
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
LINK_FLAGS " -Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/symbol.exports")
add_dependencies(${target_name} ${target_name}_exports)
endif()
endfunction(add_clang_symbol_exports)
macro(add_clang_library name) macro(add_clang_library name)
llvm_process_sources(srcs ${ARGN}) llvm_process_sources(srcs ${ARGN})
if(MSVC_IDE OR XCODE) if(MSVC_IDE OR XCODE)
@ -228,11 +273,18 @@ macro(add_clang_library name)
llvm_config( ${name} ${LLVM_LINK_COMPONENTS} ) llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
target_link_libraries( ${name} ${LLVM_COMMON_LIBS} ) target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
link_system_libs( ${name} ) link_system_libs( ${name} )
if (SHARED_LIBRARY AND EXPORTED_SYMBOL_FILE)
add_clang_symbol_exports( ${name} ${EXPORTED_SYMBOL_FILE} )
endif()
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "libclang")
install(TARGETS ${name}
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
RUNTIME DESTINATION bin)
endif()
install(TARGETS ${name}
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
RUNTIME DESTINATION bin)
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries") set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
endmacro(add_clang_library) endmacro(add_clang_library)
@ -246,26 +298,58 @@ include_directories(BEFORE
${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include
) )
install(DIRECTORY include/ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
DESTINATION include install(DIRECTORY include/
FILES_MATCHING DESTINATION include
PATTERN "*.def" FILES_MATCHING
PATTERN "*.h" PATTERN "*.def"
PATTERN "config.h" EXCLUDE PATTERN "*.h"
PATTERN ".svn" EXCLUDE PATTERN "config.h" EXCLUDE
) PATTERN ".svn" EXCLUDE
)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
DESTINATION include
FILES_MATCHING
PATTERN "CMakeFiles" EXCLUDE
PATTERN "*.inc"
)
endif()
install(DIRECTORY include/clang-c
DESTINATION include DESTINATION include
FILES_MATCHING FILES_MATCHING
PATTERN "CMakeFiles" EXCLUDE PATTERN "*.h"
PATTERN "*.inc" PATTERN ".svn" EXCLUDE
) )
add_definitions( -D_GNU_SOURCE ) add_definitions( -D_GNU_SOURCE )
# FIXME: They should be options. option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
add_definitions(-DCLANG_ENABLE_ARCMT -DCLANG_ENABLE_REWRITER -DCLANG_ENABLE_STATIC_ANALYZER) option(CLANG_ENABLE_REWRITER "Build rewriter." ON)
option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
if (NOT CLANG_ENABLE_REWRITER AND CLANG_ENABLE_ARCMT)
message(FATAL_ERROR "Cannot disable rewriter while enabling ARCMT")
endif()
if (NOT CLANG_ENABLE_REWRITER AND CLANG_ENABLE_STATIC_ANALYZER)
message(FATAL_ERROR "Cannot disable rewriter while enabling static analyzer")
endif()
if (NOT CLANG_ENABLE_STATIC_ANALYZER AND CLANG_ENABLE_ARCMT)
message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT")
endif()
if(CLANG_ENABLE_ARCMT)
add_definitions(-DCLANG_ENABLE_ARCMT)
endif()
if(CLANG_ENABLE_REWRITER)
add_definitions(-DCLANG_ENABLE_REWRITER)
endif()
if(CLANG_ENABLE_STATIC_ANALYZER)
add_definitions(-DCLANG_ENABLE_STATIC_ANALYZER)
endif()
# Clang version information # Clang version information
set(CLANG_EXECUTABLE_VERSION set(CLANG_EXECUTABLE_VERSION
@ -290,13 +374,17 @@ option(CLANG_INCLUDE_TESTS
"Generate build targets for the Clang unit tests." "Generate build targets for the Clang unit tests."
${LLVM_INCLUDE_TESTS}) ${LLVM_INCLUDE_TESTS})
# TODO: docs.
add_subdirectory(test)
if( CLANG_INCLUDE_TESTS ) if( CLANG_INCLUDE_TESTS )
add_subdirectory(test)
add_subdirectory(unittests) add_subdirectory(unittests)
endif() endif()
option(CLANG_INCLUDE_DOCS "Generate build targets for the Clang docs."
${LLVM_INCLUDE_DOCS})
if( CLANG_INCLUDE_DOCS )
add_subdirectory(docs)
endif()
# Workaround for MSVS10 to avoid the Dialog Hell # Workaround for MSVS10 to avoid the Dialog Hell
# FIXME: This could be removed with future version of CMake. # FIXME: This could be removed with future version of CMake.
if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 ) if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
@ -309,3 +397,5 @@ endif()
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
"Default URL where bug reports are to be submitted.") "Default URL where bug reports are to be submitted.")
set(CLANG_ORDER_FILE "" CACHE FILEPATH
"Order file to use when compiling clang in order to improve startup time.")

View File

@ -32,7 +32,7 @@ E: rjmccall@apple.com
D: Clang LLVM IR generation D: Clang LLVM IR generation
N: Chad Rosier N: Chad Rosier
E: mcrosier@apple.com E: mcrosier@codeaurora.org
D: MS-inline asm, and the compiler driver D: MS-inline asm, and the compiler driver
N: Richard Smith N: Richard Smith

View File

@ -266,6 +266,29 @@ def __eq__(self, other):
def __ne__(self, other): def __ne__(self, other):
return not self.__eq__(other) return not self.__eq__(other)
def __contains__(self, other):
"""Useful to detect the Token/Lexer bug"""
if not isinstance(other, SourceLocation):
return False
if other.file is None and self.start.file is None:
pass
elif ( self.start.file.name != other.file.name or
other.file.name != self.end.file.name):
# same file name
return False
# same file, in between lines
if self.start.line < other.line < self.end.line:
return True
elif self.start.line == other.line:
# same file first line
if self.start.column <= other.column:
return True
elif other.line == self.end.line:
# same file last line
if other.column <= self.end.column:
return True
return False
def __repr__(self): def __repr__(self):
return "<SourceRange start %r, end %r>" % (self.start, self.end) return "<SourceRange start %r, end %r>" % (self.start, self.end)
@ -508,7 +531,7 @@ def name(self):
@staticmethod @staticmethod
def from_id(id): def from_id(id):
if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None: if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
raise ValueError,'Unknown cursor kind' raise ValueError,'Unknown cursor kind %d' % id
return CursorKind._kinds[id] return CursorKind._kinds[id]
@staticmethod @staticmethod
@ -721,10 +744,14 @@ def __repr__(self):
# A reference to a labeled statement. # A reference to a labeled statement.
CursorKind.LABEL_REF = CursorKind(48) CursorKind.LABEL_REF = CursorKind(48)
# A reference toa a set of overloaded functions or function templates # A reference to a set of overloaded functions or function templates
# that has not yet been resolved to a specific function or function template. # that has not yet been resolved to a specific function or function template.
CursorKind.OVERLOADED_DECL_REF = CursorKind(49) CursorKind.OVERLOADED_DECL_REF = CursorKind(49)
# A reference to a variable that occurs in some non-expression
# context, e.g., a C++ lambda capture list.
CursorKind.VARIABLE_REF = CursorKind(50)
### ###
# Invalid/Error Kinds # Invalid/Error Kinds
@ -908,6 +935,26 @@ def __repr__(self):
# pack. # pack.
CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143) CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143)
# Represents a C++ lambda expression that produces a local function
# object.
#
# \code
# void abssort(float *x, unsigned N) {
# std::sort(x, x + N,
# [](float a, float b) {
# return std::abs(a) < std::abs(b);
# });
# }
# \endcode
CursorKind.LAMBDA_EXPR = CursorKind(144)
# Objective-c Boolean Literal.
CursorKind.OBJ_BOOL_LITERAL_EXPR = CursorKind(145)
# Represents the "self" expression in a ObjC method.
CursorKind.OBJ_SELF_EXPR = CursorKind(146)
# A statement whose specific kind is not exposed via this interface. # A statement whose specific kind is not exposed via this interface.
# #
# Unexposed statements have the same operations as any other kind of statement; # Unexposed statements have the same operations as any other kind of statement;
@ -999,6 +1046,9 @@ def __repr__(self):
# Windows Structured Exception Handling's finally statement. # Windows Structured Exception Handling's finally statement.
CursorKind.SEH_FINALLY_STMT = CursorKind(228) CursorKind.SEH_FINALLY_STMT = CursorKind(228)
# A MS inline assembly statement extension.
CursorKind.MS_ASM_STMT = CursorKind(229)
# The null statement. # The null statement.
CursorKind.NULL_STMT = CursorKind(230) CursorKind.NULL_STMT = CursorKind(230)
@ -1028,6 +1078,7 @@ def __repr__(self):
CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405) CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
CursorKind.ANNOTATE_ATTR = CursorKind(406) CursorKind.ANNOTATE_ATTR = CursorKind(406)
CursorKind.ASM_LABEL_ATTR = CursorKind(407) CursorKind.ASM_LABEL_ATTR = CursorKind(407)
CursorKind.PACKED_ATTR = CursorKind(408)
### ###
# Preprocessing # Preprocessing
@ -1036,6 +1087,12 @@ def __repr__(self):
CursorKind.MACRO_INSTANTIATION = CursorKind(502) CursorKind.MACRO_INSTANTIATION = CursorKind(502)
CursorKind.INCLUSION_DIRECTIVE = CursorKind(503) CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
###
# Extra declaration
# A module import declaration.
CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
### Cursors ### ### Cursors ###
class Cursor(Structure): class Cursor(Structure):
@ -1282,6 +1339,16 @@ def referenced(self):
return self._referenced return self._referenced
@property
def brief_comment(self):
"""Returns the brief comment text associated with that Cursor"""
return conf.lib.clang_Cursor_getBriefCommentText(self)
@property
def raw_comment(self):
"""Returns the raw comment text associated with that Cursor"""
return conf.lib.clang_Cursor_getRawCommentText(self)
def get_arguments(self): def get_arguments(self):
"""Return an iterator for accessing the arguments of this cursor.""" """Return an iterator for accessing the arguments of this cursor."""
num_args = conf.lib.clang_Cursor_getNumArguments(self) num_args = conf.lib.clang_Cursor_getNumArguments(self)
@ -1450,6 +1517,54 @@ def __repr__(self):
TypeKind.FUNCTIONPROTO = TypeKind(111) TypeKind.FUNCTIONPROTO = TypeKind(111)
TypeKind.CONSTANTARRAY = TypeKind(112) TypeKind.CONSTANTARRAY = TypeKind(112)
TypeKind.VECTOR = TypeKind(113) TypeKind.VECTOR = TypeKind(113)
TypeKind.INCOMPLETEARRAY = TypeKind(114)
TypeKind.VARIABLEARRAY = TypeKind(115)
TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
TypeKind.MEMBERPOINTER = TypeKind(117)
class RefQualifierKind(object):
"""Describes a specific ref-qualifier of a type."""
# The unique kind objects, indexed by id.
_kinds = []
_name_map = None
def __init__(self, value):
if value >= len(RefQualifierKind._kinds):
num_kinds = value - len(RefQualifierKind._kinds) + 1
RefQualifierKind._kinds += [None] * num_kinds
if RefQualifierKind._kinds[value] is not None:
raise ValueError, 'RefQualifierKind already loaded'
self.value = value
RefQualifierKind._kinds[value] = self
RefQualifierKind._name_map = None
def from_param(self):
return self.value
@property
def name(self):
"""Get the enumeration name of this kind."""
if self._name_map is None:
self._name_map = {}
for key, value in RefQualifierKind.__dict__.items():
if isinstance(value, RefQualifierKind):
self._name_map[value] = key
return self._name_map[self]
@staticmethod
def from_id(id):
if (id >= len(RefQualifierKind._kinds) or
RefQualifierKind._kinds[id] is None):
raise ValueError, 'Unknown type kind %d' % id
return RefQualifierKind._kinds[id]
def __repr__(self):
return 'RefQualifierKind.%s' % (self.name,)
RefQualifierKind.NONE = RefQualifierKind(0)
RefQualifierKind.LVALUE = RefQualifierKind(1)
RefQualifierKind.RVALUE = RefQualifierKind(2)
class Type(Structure): class Type(Structure):
""" """
@ -1625,6 +1740,12 @@ def get_array_size(self):
""" """
return conf.lib.clang_getArraySize(self) return conf.lib.clang_getArraySize(self)
def get_class_type(self):
"""
Retrieve the class type of the member pointer type.
"""
return conf.lib.clang_Type_getClassType(self)
def get_align(self): def get_align(self):
""" """
Retrieve the alignment of the record. Retrieve the alignment of the record.
@ -1643,6 +1764,18 @@ def get_offset(self, fieldname):
""" """
return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname)) return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname))
def get_ref_qualifier(self):
"""
Retrieve the ref-qualifier of the type.
"""
return RefQualifierKind.from_id(
conf.lib.clang_Type_getCXXRefQualifier(self))
@property
def spelling(self):
"""Retrieve the spelling of this Type."""
return conf.lib.clang_getTypeSpelling(self)
def __eq__(self, other): def __eq__(self, other):
if type(other) != type(self): if type(other) != type(self):
return False return False
@ -1918,7 +2051,7 @@ def __del__(self):
def read(self, path): def read(self, path):
"""Load a TranslationUnit from the given AST file.""" """Load a TranslationUnit from the given AST file."""
return TranslationUnit.from_ast(path, self) return TranslationUnit.from_ast_file(path, self)
def parse(self, path, args=None, unsaved_files=None, options = 0): def parse(self, path, args=None, unsaved_files=None, options = 0):
"""Load the translation unit from the given source code file by running """Load the translation unit from the given source code file by running
@ -2590,6 +2723,10 @@ def cursor(self):
[Index, c_char_p], [Index, c_char_p],
c_object_p), c_object_p),
("clang_CXXMethod_isPureVirtual",
[Cursor],
bool),
("clang_CXXMethod_isStatic", ("clang_CXXMethod_isStatic",
[Cursor], [Cursor],
bool), bool),
@ -2973,6 +3110,11 @@ def cursor(self):
_CXString, _CXString,
_CXString.from_result), _CXString.from_result),
("clang_getTypeSpelling",
[Type],
_CXString,
_CXString.from_result),
("clang_hashCursor", ("clang_hashCursor",
[Cursor], [Cursor],
c_uint), c_uint),
@ -3077,17 +3219,36 @@ def cursor(self):
[Cursor], [Cursor],
bool), bool),
("clang_Cursor_getBriefCommentText",
[Cursor],
_CXString,
_CXString.from_result),
("clang_Cursor_getRawCommentText",
[Cursor],
_CXString,
_CXString.from_result),
("clang_Type_getAlignOf", ("clang_Type_getAlignOf",
[Type], [Type],
c_longlong), c_longlong),
("clang_Type_getClassType",
[Type],
Type,
Type.from_result),
("clang_Type_getOffsetOf", ("clang_Type_getOffsetOf",
[Type, c_char_p], [Type, c_char_p],
c_longlong), c_longlong),
("clang_Type_getSizeOf", ("clang_Type_getSizeOf",
[Type], [Type],
c_ulonglong), c_longlong),
("clang_Type_getCXXRefQualifier",
[Type],
c_uint),
] ]
class LibclangError(Exception): class LibclangError(Exception):

View 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

View File

@ -4,8 +4,15 @@ def test_name():
assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL' assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
def test_get_all_kinds(): def test_get_all_kinds():
assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds() kinds = CursorKind.get_all_kinds()
assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds() assert CursorKind.UNEXPOSED_DECL in kinds
assert CursorKind.TRANSLATION_UNIT in kinds
assert CursorKind.VARIABLE_REF in kinds
assert CursorKind.LAMBDA_EXPR in kinds
assert CursorKind.OBJ_BOOL_LITERAL_EXPR in kinds
assert CursorKind.OBJ_SELF_EXPR in kinds
assert CursorKind.MS_ASM_STMT in kinds
assert CursorKind.MODULE_IMPORT_DECL in kinds
def test_kind_groups(): def test_kind_groups():
"""Check that every kind classifies to exactly one group.""" """Check that every kind classifies to exactly one group."""

View File

@ -132,6 +132,22 @@ def test_equal():
assert a.type != None assert a.type != None
assert a.type != 'foo' assert a.type != 'foo'
def test_type_spelling():
"""Ensure Type.spelling works."""
tu = get_tu('int c[5]; int i[]; int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
x = get_cursor(tu, 'x')
v = get_cursor(tu, 'v')
assert c is not None
assert i is not None
assert x is not None
assert v is not None
assert c.type.spelling == "int [5]"
assert i.type.spelling == "int []"
assert x.type.spelling == "int"
assert v.type.spelling == "int [x]"
def test_typekind_spelling(): def test_typekind_spelling():
"""Ensure TypeKind.spelling works.""" """Ensure TypeKind.spelling works."""
tu = get_tu('int a;') tu = get_tu('int a;')
@ -237,12 +253,20 @@ def test_function_variadic():
def test_element_type(): def test_element_type():
"""Ensure Type.element_type works.""" """Ensure Type.element_type works."""
tu = get_tu('int i[5];') tu = get_tu('int c[5]; int i[]; int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i') i = get_cursor(tu, 'i')
v = get_cursor(tu, 'v')
assert c is not None
assert i is not None assert i is not None
assert v is not None
assert i.type.kind == TypeKind.CONSTANTARRAY assert c.type.kind == TypeKind.CONSTANTARRAY
assert c.type.element_type.kind == TypeKind.INT
assert i.type.kind == TypeKind.INCOMPLETEARRAY
assert i.type.element_type.kind == TypeKind.INT assert i.type.element_type.kind == TypeKind.INT
assert v.type.kind == TypeKind.VARIABLEARRAY
assert v.type.element_type.kind == TypeKind.INT
@raises(Exception) @raises(Exception)
def test_invalid_element_type(): def test_invalid_element_type():
@ -361,3 +385,13 @@ def test_offset():
assert teststruct.type.get_offset("bar") == bar assert teststruct.type.get_offset("bar") == bar
def test_decay():
"""Ensure decayed types are handled as the original type"""
tu = get_tu("void foo(int a[]);")
foo = get_cursor(tu, 'foo')
a = foo.type.argument_types()[0]
assert a.kind == TypeKind.INCOMPLETEARRAY
assert a.element_type.kind == TypeKind.INT
assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY

View File

@ -75,7 +75,6 @@
<optional> <optional>
<ref name="USR" /> <ref name="USR" />
</optional> </optional>
<!-- TODO: Add exception specification. -->
<optional> <optional>
<ref name="Headerfile" /> <ref name="Headerfile" />
</optional> </optional>
@ -91,6 +90,9 @@
<optional> <optional>
<ref name="Parameters" /> <ref name="Parameters" />
</optional> </optional>
<optional>
<ref name="Exceptions" />
</optional>
<zeroOrMore> <zeroOrMore>
<ref name="Availability" /> <ref name="Availability" />
</zeroOrMore> </zeroOrMore>
@ -410,9 +412,14 @@
</data> </data>
</element> </element>
<optional> <optional>
<element name="Index"> <choice>
<data type="nonNegativeInteger" /> <element name="Index">
</element> <data type="nonNegativeInteger" />
</element>
<element name="IsVarArg">
<empty />
</element>
</choice>
</optional> </optional>
<element name="Direction"> <element name="Direction">
<attribute name="isExplicit"> <attribute name="isExplicit">
@ -435,6 +442,14 @@
</element> </element>
</define> </define>
<define name="Exceptions">
<element name="Exceptions">
<oneOrMore>
<ref name="TextBlockContent" />
</oneOrMore>
</element>
</define>
<define name="Availability"> <define name="Availability">
<element name="Availability"> <element name="Availability">
<attribute name="distribution"> <attribute name="distribution">

View File

@ -16,6 +16,7 @@ following types of bugs:
* Use-after-free * Use-after-free
* Use-after-return (to some extent) * Use-after-return (to some extent)
* Double-free, invalid free * Double-free, invalid free
* Memory leaks (experimental)
Typical slowdown introduced by AddressSanitizer is **2x**. Typical slowdown introduced by AddressSanitizer is **2x**.
@ -114,8 +115,7 @@ function attribute
(or a deprecated synonym `no_address_safety_analysis`) (or a deprecated synonym `no_address_safety_analysis`)
to disable instrumentation of a particular function. This attribute may not be to disable instrumentation of a particular function. This attribute may not be
supported by other compilers, so we suggest to use it together with supported by other compilers, so we suggest to use it together with
``__has_feature(address_sanitizer)``. Note: currently, this attribute will be ``__has_feature(address_sanitizer)``.
lost if the function is inlined.
Initialization order checking Initialization order checking
----------------------------- -----------------------------
@ -126,6 +126,42 @@ globals defined in another translation unit. To enable this check at runtime,
you should set environment variable you should set environment variable
``ASAN_OPTIONS=check_initialization_order=1``. ``ASAN_OPTIONS=check_initialization_order=1``.
Blacklist
---------
AddressSanitizer supports ``src`` and ``fun`` entity types in
:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
in the specified source files or functions. Additionally, AddressSanitizer
introduces ``global`` and ``type`` entity types that can be used to
suppress error reports for out-of-bound access to globals with certain
names and types (you may only specify class or struct types).
You may use an ``init`` category to suppress reports about initialization-order
problems happening in certain source files or with certain global variables.
.. code-block:: bash
# Suppress error reports for code in a file or in a function:
src:bad_file.cpp
# Ignore all functions with names containing MyFooBar:
fun:*MyFooBar*
# Disable out-of-bound checks for global:
global:bad_array
# Disable out-of-bound checks for global instances of a given class ...
type:class.Namespace::BadClassName
# ... or a given struct. Use wildcard to deal with anonymous namespace.
type:struct.Namespace2::*::BadStructName
# Disable initialization-order checks for globals:
global:bad_init_global=init
type:*BadInitClassSubstring*=init
src:bad/init/files/*=init
Memory leak detection
---------------------
For the experimental memory leak detector in AddressSanitizer, see
:doc:`LeakSanitizer`.
Supported Platforms Supported Platforms
=================== ===================

51
docs/CMakeLists.txt Normal file
View 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()

View File

@ -15,26 +15,73 @@ to format C/C++/Obj-C code.
.. code-block:: console .. code-block:: console
$ clang-format --help $ clang-format -help
OVERVIEW: A tool to format C/C++/Obj-C code. OVERVIEW: A tool to format C/C++/Obj-C code.
If no arguments are specified, it formats the code from standard input If no arguments are specified, it formats the code from standard input
and writes the result to the standard output. and writes the result to the standard output.
If <file> is given, it reformats the file. If -i is specified together If <file>s are given, it reformats the files. If -i is specified
with <file>, the file is edited in-place. Otherwise, the result is together with <file>s, the files are edited in-place. Otherwise, the
written to the standard output. result is written to the standard output.
USAGE: clang-format [options] [<file>] USAGE: clang-format [options] [<file> ...]
OPTIONS: OPTIONS:
-fatal-assembler-warnings - Consider warnings as error
-help - Display available options (-help-hidden for more) Clang-format options:
-i - Inplace edit <file>, if specified.
-length=<int> - Format a range of this length, -1 for end of file. -cursor=<uint> - The position of the cursor when invoking
-offset=<int> - Format a range starting at this file offset. clang-format from an editor integration
-stats - Enable statistics output from program -dump-config - Dump configuration options to stdout and exit.
-style=<string> - Coding style, currently supports: LLVM, Google, Chromium. Can be used with -style option.
-version - Display the version of this program -i - Inplace edit <file>s, if specified.
-length=<uint> - Format a range of this length (in bytes).
Multiple ranges can be formatted by specifying
several -offset and -length pairs.
When only a single -offset is specified without
-length, clang-format will format up to the end
of the file.
Can only be used with one input file.
-lines=<string> - <start line>:<end line> - format a range of
lines (both 1-based).
Multiple ranges can be formatted by specifying
several -lines arguments.
Can't be used with -offset and -length.
Can only be used with one input file.
-offset=<uint> - Format a range starting at this byte offset.
Multiple ranges can be formatted by specifying
several -offset and -length pairs.
Can only be used with one input file.
-output-replacements-xml - Output replacements as XML.
-style=<string> - Coding style, currently supports:
LLVM, Google, Chromium, Mozilla, WebKit.
Use -style=file to load style configuration from
.clang-format file located in one of the parent
directories of the source file (or current
directory for stdin).
Use -style="{key: value, ...}" to set specific
parameters, e.g.:
-style="{BasedOnStyle: llvm, IndentWidth: 8}"
General options:
-help - Display available options (-help-hidden for more)
-help-list - Display list of available options (-help-list-hidden for more)
-version - Display the version of this program
When the desired code formatting style is different from the available options,
the style can be customized using the ``-style="{key: value, ...}"`` option or
by putting your style configuration in the ``.clang-format`` or ``_clang-format``
file in your project's directory and using ``clang-format -style=file``.
An easy way to create the ``.clang-format`` file is:
.. code-block:: console
clang-format -style=llvm -dump-config > .clang-format
Available style options are described in :doc:`ClangFormatStyleOptions`.
Vim Integration Vim Integration
@ -96,6 +143,13 @@ menu item by renaming the script, and can assign the menu item a keyboard
shortcut in the BBEdit preferences, under Menus & Shortcuts. shortcut in the BBEdit preferences, under Menus & Shortcuts.
Visual Studio Integration
=========================
Download the latest Visual Studio plugin from the `alpha build site
<http://llvm.org/builds/>`_. The default key-binding is Ctrl-R,Ctrl-F.
Script for patch reformatting Script for patch reformatting
============================= =============================
@ -106,18 +160,19 @@ a unified diff and reformats all contained lines with :program:`clang-format`.
usage: clang-format-diff.py [-h] [-p P] [-style STYLE] usage: clang-format-diff.py [-h] [-p P] [-style STYLE]
Reformat changed lines in diff Reformat changed lines in diff.
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
-p P strip the smallest prefix containing P slashes -p P strip the smallest prefix containing P slashes
-style STYLE formatting style to apply (LLVM, Google, Chromium) -style STYLE formatting style to apply (LLVM, Google, Chromium, Mozilla,
WebKit)
So to reformat all the lines in the latest :program:`git` commit, just do: So to reformat all the lines in the latest :program:`git` commit, just do:
.. code-block:: console .. code-block:: console
git diff -U0 HEAD^ | clang-format-diff.py git diff -U0 HEAD^ | clang-format-diff.py -p1
The :option:`-U0` will create a diff without context lines (the script would format The :option:`-U0` will create a diff without context lines (the script would format
those as well). those as well).

View 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();
}
}

View File

@ -88,8 +88,8 @@ Clang-format is both a :doc:`library <LibFormat>` and a :doc:`stand-alone tool
<ClangFormat>` with the goal of automatically reformatting C++ sources files <ClangFormat>` with the goal of automatically reformatting C++ sources files
according to configurable style guides. To do so, clang-format uses Clang's according to configurable style guides. To do so, clang-format uses Clang's
``Lexer`` to transform an input file into a token stream and then changes all ``Lexer`` to transform an input file into a token stream and then changes all
the whitespace around those tokens. The goal is for clang-format to both serve the whitespace around those tokens. The goal is for clang-format to serve both
both as a user tool (ideally with powerful IDE integrations) and part of other as a user tool (ideally with powerful IDE integrations) and as part of other
refactoring tools, e.g. to do a reformatting of all the lines changed during a refactoring tools, e.g. to do a reformatting of all the lines changed during a
renaming. renaming.
@ -125,7 +125,7 @@ Ideas for new Tools
``foo`` is a standard container. We could also detect similar patterns for ``foo`` is a standard container. We could also detect similar patterns for
arrays. arrays.
* ``make_shared`` / ``make_unique`` conversion. Part of this transformation * ``make_shared`` / ``make_unique`` conversion. Part of this transformation
can be incorporated into the ``auto`` transformation. Will convert can be incorporated into the ``auto`` transformation. Will convert
.. code-block:: c++ .. code-block:: c++

204
docs/CrossCompilation.rst Normal file
View 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
View 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>`.

View 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.

View File

@ -950,17 +950,13 @@ functions, Objective-C methods, C++ constructors, destructors, and operators
``DeclarationName`` is designed to efficiently represent any kind of name. ``DeclarationName`` is designed to efficiently represent any kind of name.
Given a ``DeclarationName`` ``N``, ``N.getNameKind()`` will produce a value Given a ``DeclarationName`` ``N``, ``N.getNameKind()`` will produce a value
that describes what kind of name ``N`` stores. There are 8 options (all of the that describes what kind of name ``N`` stores. There are 10 options (all of
names are inside the ``DeclarationName`` class). the names are inside the ``DeclarationName`` class).
``Identifier`` ``Identifier``
The name is a simple identifier. Use ``N.getAsIdentifierInfo()`` to retrieve The name is a simple identifier. Use ``N.getAsIdentifierInfo()`` to retrieve
the corresponding ``IdentifierInfo*`` pointing to the actual identifier. the corresponding ``IdentifierInfo*`` pointing to the actual identifier.
Note that C++ overloaded operators (e.g., "``operator+``") are represented as
special kinds of identifiers. Use ``IdentifierInfo``'s
``getOverloadedOperatorID`` function to determine whether an identifier is an
overloaded operator name.
``ObjCZeroArgSelector``, ``ObjCOneArgSelector``, ``ObjCMultiArgSelector`` ``ObjCZeroArgSelector``, ``ObjCOneArgSelector``, ``ObjCMultiArgSelector``
@ -999,6 +995,21 @@ names are inside the ``DeclarationName`` class).
Use ``N.getCXXOverloadedOperator()`` to retrieve the overloaded operator (a Use ``N.getCXXOverloadedOperator()`` to retrieve the overloaded operator (a
value of type ``OverloadedOperatorKind``). value of type ``OverloadedOperatorKind``).
``CXXLiteralOperatorName``
The name is a C++11 user defined literal operator. User defined
Literal operators are named according to the suffix they define,
e.g., "``_foo``" for "``operator "" _foo``". Use
``N.getCXXLiteralIdentifier()`` to retrieve the corresponding
``IdentifierInfo*`` pointing to the identifier.
``CXXUsingDirective``
The name is a C++ using directive. Using directives are not really
NamedDecls, in that they all have the same name, but they are
implemented as such in order to store them in DeclContext
effectively.
``DeclarationName``\ s are cheap to create, copy, and compare. They require ``DeclarationName``\ s are cheap to create, copy, and compare. They require
only a single pointer's worth of storage in the common cases (identifiers, only a single pointer's worth of storage in the common cases (identifiers,
zero- and one-argument Objective-C selectors) and use dense, uniqued storage zero- and one-argument Objective-C selectors) and use dense, uniqued storage

View File

@ -7,6 +7,12 @@ AST. It is targeted at developers who either want to contribute to
Clang, or use tools that work based on Clang's AST, like the AST Clang, or use tools that work based on Clang's AST, like the AST
matchers. matchers.
.. raw:: html
<center><iframe width="560" height="315" src="http://www.youtube.com/embed/VqCkCDFLSsc?vq=hd720" frameborder="0" allowfullscreen></iframe></center>
`Slides <http://llvm.org/devmtg/2013-04/klimek-slides.pdf>`_
Introduction Introduction
============ ============
@ -27,9 +33,8 @@ Examining the AST
================= =================
A good way to familarize yourself with the Clang AST is to actually look A good way to familarize yourself with the Clang AST is to actually look
at it on some simple example code. Clang has a builtin AST-dump modes, at it on some simple example code. Clang has a builtin AST-dump mode,
which can be enabled with the flags ``-ast-dump`` and ``-ast-dump-xml``. Note which can be enabled with the flag ``-ast-dump``.
that ``-ast-dump-xml`` currently only works with debug builds of clang.
Let's look at a simple example AST: Let's look at a simple example AST:
@ -41,40 +46,26 @@ Let's look at a simple example AST:
return result; return result;
} }
# Clang by default is a frontend for many tools; -cc1 tells it to directly # Clang by default is a frontend for many tools; -Xclang is used to pass
# use the C++ compiler mode. -undef leaves out some internal declarations. # options directly to the C++ frontend.
$ clang -cc1 -undef -ast-dump-xml test.cc $ clang -Xclang -ast-dump -fsyntax-only test.cc
TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
... cutting out internal declarations of clang ... ... cutting out internal declarations of clang ...
<TranslationUnit ptr="0x4871160"> `-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
<Function ptr="0x48a5800" name="f" prototype="true"> |-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
<FunctionProtoType ptr="0x4871de0" canonical="0x4871de0"> `-CompoundStmt 0x5aead88 <col:14, line:4:1>
<BuiltinType ptr="0x4871250" canonical="0x4871250"/> |-DeclStmt 0x5aead10 <line:2:3, col:24>
<parameters> | `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
<BuiltinType ptr="0x4871250" canonical="0x4871250"/> | `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
</parameters> | `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
</FunctionProtoType> | |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
<ParmVar ptr="0x4871d80" name="x" initstyle="c"> | | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
<BuiltinType ptr="0x4871250" canonical="0x4871250"/> | `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
</ParmVar> `-ReturnStmt 0x5aead68 <line:3:3, col:10>
<Stmt> `-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
(CompoundStmt 0x48a5a38 <t2.cc:1:14, line:4:1> `-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'
(DeclStmt 0x48a59c0 <line:2:3, col:24>
0x48a58c0 "int result =
(ParenExpr 0x48a59a0 <col:16, col:23> 'int'
(BinaryOperator 0x48a5978 <col:17, col:21> 'int' '/'
(ImplicitCastExpr 0x48a5960 <col:17> 'int' <LValueToRValue>
(DeclRefExpr 0x48a5918 <col:17> 'int' lvalue ParmVar 0x4871d80 'x' 'int'))
(IntegerLiteral 0x48a5940 <col:21> 'int' 42)))")
(ReturnStmt 0x48a5a18 <line:3:3, col:10>
(ImplicitCastExpr 0x48a5a00 <col:10> 'int' <LValueToRValue>
(DeclRefExpr 0x48a59d8 <col:10> 'int' lvalue Var 0x48a58c0 'result' 'int'))))
</Stmt> The toplevel declaration in
</Function>
</TranslationUnit>
In general, ``-ast-dump-xml`` dumps declarations in an XML-style format and
statements in an S-expression-style format. The toplevel declaration in
a translation unit is always the `translation unit a translation unit is always the `translation unit
declaration <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_. declaration <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_.
In this example, our first user written declaration is the `function In this example, our first user written declaration is the `function

View File

@ -159,12 +159,16 @@ include paths, or 0 otherwise:
# include "myinclude.h" # include "myinclude.h"
#endif #endif
To test for this feature, use ``#if defined(__has_include)``:
.. code-block:: c++
// To avoid problem with non-clang compilers not having this macro. // To avoid problem with non-clang compilers not having this macro.
#if defined(__has_include) && __has_include("myinclude.h") #if defined(__has_include)
#if __has_include("myinclude.h")
# include "myinclude.h" # include "myinclude.h"
#endif #endif
#endif
To test for this feature, use ``#if defined(__has_include)``.
.. _langext-__has_include_next: .. _langext-__has_include_next:
@ -185,9 +189,11 @@ or 0 otherwise:
#endif #endif
// To avoid problem with non-clang compilers not having this macro. // To avoid problem with non-clang compilers not having this macro.
#if defined(__has_include_next) && __has_include_next("myinclude.h") #if defined(__has_include_next)
#if __has_include_next("myinclude.h")
# include_next "myinclude.h" # include_next "myinclude.h"
#endif #endif
#endif
Note that ``__has_include_next``, like the GNU extension ``#include_next`` Note that ``__has_include_next``, like the GNU extension ``#include_next``
directive, is intended for use in headers only, and will issue a warning if directive, is intended for use in headers only, and will issue a warning if
@ -801,8 +807,7 @@ Use ``__has_feature(cxx_contextual_conversions)`` or
``__has_extension(cxx_contextual_conversions)`` to determine if the C++1y rules ``__has_extension(cxx_contextual_conversions)`` to determine if the C++1y rules
are used when performing an implicit conversion for an array bound in a are used when performing an implicit conversion for an array bound in a
*new-expression*, the operand of a *delete-expression*, an integral constant *new-expression*, the operand of a *delete-expression*, an integral constant
expression, or a condition in a ``switch`` statement. Clang does not yet expression, or a condition in a ``switch`` statement.
support this feature.
C++1y decltype(auto) C++1y decltype(auto)
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
@ -821,9 +826,9 @@ for default initializers in aggregate members is enabled.
C++1y generalized lambda capture C++1y generalized lambda capture
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_generalized_capture)`` or Use ``__has_feature(cxx_init_capture)`` or
``__has_extension(cxx_generalized_capture`` to determine if support for ``__has_extension(cxx_init_capture)`` to determine if support for
generalized lambda captures is enabled lambda captures with explicit initializers is enabled
(for instance, ``[n(0)] { return ++n; }``). (for instance, ``[n(0)] { return ++n; }``).
Clang does not yet support this feature. Clang does not yet support this feature.
@ -843,7 +848,6 @@ Use ``__has_feature(cxx_relaxed_constexpr)`` or
``__has_extension(cxx_relaxed_constexpr)`` to determine if variable ``__has_extension(cxx_relaxed_constexpr)`` to determine if variable
declarations, local variable modification, and control flow constructs declarations, local variable modification, and control flow constructs
are permitted in ``constexpr`` functions. are permitted in ``constexpr`` functions.
Clang's implementation of this feature is incomplete.
C++1y return type deduction C++1y return type deduction
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -852,7 +856,6 @@ Use ``__has_feature(cxx_return_type_deduction)`` or
``__has_extension(cxx_return_type_deduction)`` to determine if support ``__has_extension(cxx_return_type_deduction)`` to determine if support
for return type deduction for functions (using ``auto`` as a return type) for return type deduction for functions (using ``auto`` as a return type)
is enabled. is enabled.
Clang's implementation of this feature is incomplete.
C++1y runtime-sized arrays C++1y runtime-sized arrays
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -918,8 +921,8 @@ enabled.
C11 ``_Thread_local`` C11 ``_Thread_local``
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(c_thread_local)`` to determine if support for Use ``__has_feature(c_thread_local)`` or ``__has_extension(c_thread_local)``
``_Thread_local`` variables is enabled. to determine if support for ``_Thread_local`` variables is enabled.
Checks for Type Traits Checks for Type Traits
====================== ======================
@ -1173,8 +1176,52 @@ of this feature in version of clang being used.
.. _langext-objc_method_family: .. _langext-objc_method_family:
The ``objc_method_family`` attribute
------------------------------------ Objective-C requiring a call to ``super`` in an override
--------------------------------------------------------
Some Objective-C classes allow a subclass to override a particular method in a
parent class but expect that the overriding method also calls the overridden
method in the parent class. For these cases, we provide an attribute to
designate that a method requires a "call to ``super``" in the overriding
method in the subclass.
**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only
be placed at the end of a method declaration:
.. code-block:: objc
- (void)foo __attribute__((objc_requires_super));
This attribute can only be applied the method declarations within a class, and
not a protocol. Currently this attribute does not enforce any placement of
where the call occurs in the overriding method (such as in the case of
``-dealloc`` where the call must appear at the end). It checks only that it
exists.
Note that on both OS X and iOS that the Foundation framework provides a
convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this
attribute:
.. code-block:: objc
- (void)foo NS_REQUIRES_SUPER;
This macro is conditionally defined depending on the compiler's support for
this attribute. If the compiler does not support the attribute the macro
expands to nothing.
Operationally, when a method has this annotation the compiler will warn if the
implementation of an override in a subclass does not call super. For example:
.. code-block:: objc
warning: method possibly missing a [super AnnotMeth] call
- (void) AnnotMeth{};
^
Objective-C Method Families
---------------------------
Many methods in Objective-C have conventional meanings determined by their Many methods in Objective-C have conventional meanings determined by their
selectors. It is sometimes useful to be able to mark a method as having a selectors. It is sometimes useful to be able to mark a method as having a
@ -1253,6 +1300,21 @@ Query for these features with ``__has_attribute(ns_consumed)``,
``__has_attribute(ns_returns_retained)``, etc. ``__has_attribute(ns_returns_retained)``, etc.
Objective-C++ ABI: protocol-qualifier mangling of parameters
------------------------------------------------------------
Starting with LLVM 3.4, Clang produces a new mangling for parameters whose
type is a qualified-``id`` (e.g., ``id<Foo>``). This mangling allows such
parameters to be differentiated from those with the regular unqualified ``id``
type.
This was a non-backward compatible mangling change to the ABI. This change
allows proper overloading, and also prevents mangling conflicts with template
parameters of protocol-qualified type.
Query the presence of this new mangling with
``__has_feature(objc_protocol_qualifier_mangling)``.
Function Overloading in C Function Overloading in C
========================= =========================
@ -1411,7 +1473,9 @@ should only be used for timing small intervals. When not supported by the
target, the return value is always zero. This builtin takes no arguments and target, the return value is always zero. This builtin takes no arguments and
produces an unsigned long long result. produces an unsigned long long result.
Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``. Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``. Note
that even if present, its use may depend on run-time privilege or other OS
controlled state.
.. _langext-__builtin_shufflevector: .. _langext-__builtin_shufflevector:
@ -1433,8 +1497,8 @@ for the implementation of various target-specific header files like
.. code-block:: c++ .. code-block:: c++
// Identity operation - return 4-element vector V1. // identity operation - return 4-element vector v1.
__builtin_shufflevector(V1, V1, 0, 1, 2, 3) __builtin_shufflevector(v1, v1, 0, 1, 2, 3)
// "Splat" element 0 of V1 into a 4-element result. // "Splat" element 0 of V1 into a 4-element result.
__builtin_shufflevector(V1, V1, 0, 0, 0, 0) __builtin_shufflevector(V1, V1, 0, 0, 0, 0)
@ -1448,6 +1512,9 @@ for the implementation of various target-specific header files like
// Concatenate every other element of 8-element vectors V1 and V2. // Concatenate every other element of 8-element vectors V1 and V2.
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14) __builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
// Shuffle v1 with some elements being undefined
__builtin_shufflevector(v1, v1, 3, -1, 1, -1)
**Description**: **Description**:
The first two arguments to ``__builtin_shufflevector`` are vectors that have The first two arguments to ``__builtin_shufflevector`` are vectors that have
@ -1456,7 +1523,8 @@ specify the elements indices of the first two vectors that should be extracted
and returned in a new vector. These element indices are numbered sequentially and returned in a new vector. These element indices are numbered sequentially
starting with the first vector, continuing into the second vector. Thus, if starting with the first vector, continuing into the second vector. Thus, if
``vec1`` is a 4-element vector, index 5 would refer to the second element of ``vec1`` is a 4-element vector, index 5 would refer to the second element of
``vec2``. ``vec2``. An index of -1 can be used to indicate that the corresponding element
in the returned vector is a don't care and can be optimized by the backend.
The result of ``__builtin_shufflevector`` is a vector with the same element The result of ``__builtin_shufflevector`` is a vector with the same element
type as ``vec1``/``vec2`` but that has an element count equal to the number of type as ``vec1``/``vec2`` but that has an element count equal to the number of
@ -1464,6 +1532,50 @@ indices specified.
Query for this feature with ``__has_builtin(__builtin_shufflevector)``. Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
``__builtin_convertvector``
---------------------------
``__builtin_convertvector`` is used to express generic vector
type-conversion operations. The input vector and the output vector
type must have the same number of elements.
**Syntax**:
.. code-block:: c++
__builtin_convertvector(src_vec, dst_vec_type)
**Examples**:
.. code-block:: c++
typedef double vector4double __attribute__((__vector_size__(32)));
typedef float vector4float __attribute__((__vector_size__(16)));
typedef short vector4short __attribute__((__vector_size__(8)));
vector4float vf; vector4short vs;
// convert from a vector of 4 floats to a vector of 4 doubles.
__builtin_convertvector(vf, vector4double)
// equivalent to:
(vector4double) { (double) vf[0], (double) vf[1], (double) vf[2], (double) vf[3] }
// convert from a vector of 4 shorts to a vector of 4 floats.
__builtin_convertvector(vs, vector4float)
// equivalent to:
(vector4float) { (float) vf[0], (float) vf[1], (float) vf[2], (float) vf[3] }
**Description**:
The first argument to ``__builtin_convertvector`` is a vector, and the second
argument is a vector type with the same number of elements as the first
argument.
The result of ``__builtin_convertvector`` is a vector with the same element
type as the second argument, with a value defined in terms of the action of a
C-style cast applied to each element of the first argument.
Query for this feature with ``__has_builtin(__builtin_convertvector)``.
``__builtin_unreachable`` ``__builtin_unreachable``
------------------------- -------------------------
@ -1526,6 +1638,22 @@ correct code by avoiding expensive loops around
implementation details of ``__sync_lock_test_and_set()``. The implementation details of ``__sync_lock_test_and_set()``. The
``__sync_swap()`` builtin is a full barrier. ``__sync_swap()`` builtin is a full barrier.
``__builtin_addressof``
-----------------------
``__builtin_addressof`` performs the functionality of the built-in ``&``
operator, ignoring any ``operator&`` overload. This is useful in constant
expressions in C++11, where there is no other way to take the address of an
object that overloads ``operator&``.
**Example of use**:
.. code-block:: c++
template<typename T> constexpr T *addressof(T &value) {
return __builtin_addressof(value);
}
Multiprecision Arithmetic Builtins Multiprecision Arithmetic Builtins
---------------------------------- ----------------------------------
@ -1554,15 +1682,60 @@ The complete list of builtins are:
.. code-block:: c .. code-block:: c
unsigned char __builtin_addcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
unsigned short __builtin_addcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout); unsigned short __builtin_addcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
unsigned __builtin_addc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout); unsigned __builtin_addc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
unsigned long __builtin_addcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout); unsigned long __builtin_addcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
unsigned long long __builtin_addcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout); unsigned long long __builtin_addcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
unsigned char __builtin_subcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
unsigned short __builtin_subcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout); unsigned short __builtin_subcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
unsigned __builtin_subc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout); unsigned __builtin_subc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
unsigned long __builtin_subcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout); unsigned long __builtin_subcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
unsigned long long __builtin_subcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout); unsigned long long __builtin_subcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
Checked Arithmetic Builtins
---------------------------
Clang provides a set of builtins that implement checked arithmetic for security
critical applications in a manner that is fast and easily expressable in C. As
an example of their usage:
.. code-block:: c
errorcode_t security_critical_application(...) {
unsigned x, y, result;
...
if (__builtin_umul_overflow(x, y, &result))
return kErrorCodeHackers;
...
use_multiply(result);
...
}
A complete enumeration of the builtins are:
.. code-block:: c
bool __builtin_uadd_overflow (unsigned x, unsigned y, unsigned *sum);
bool __builtin_uaddl_overflow (unsigned long x, unsigned long y, unsigned long *sum);
bool __builtin_uaddll_overflow(unsigned long long x, unsigned long long y, unsigned long long *sum);
bool __builtin_usub_overflow (unsigned x, unsigned y, unsigned *diff);
bool __builtin_usubl_overflow (unsigned long x, unsigned long y, unsigned long *diff);
bool __builtin_usubll_overflow(unsigned long long x, unsigned long long y, unsigned long long *diff);
bool __builtin_umul_overflow (unsigned x, unsigned y, unsigned *prod);
bool __builtin_umull_overflow (unsigned long x, unsigned long y, unsigned long *prod);
bool __builtin_umulll_overflow(unsigned long long x, unsigned long long y, unsigned long long *prod);
bool __builtin_sadd_overflow (int x, int y, int *sum);
bool __builtin_saddl_overflow (long x, long y, long *sum);
bool __builtin_saddll_overflow(long long x, long long y, long long *sum);
bool __builtin_ssub_overflow (int x, int y, int *diff);
bool __builtin_ssubl_overflow (long x, long y, long *diff);
bool __builtin_ssubll_overflow(long long x, long long y, long long *diff);
bool __builtin_smul_overflow (int x, int y, int *prod);
bool __builtin_smull_overflow (long x, long y, long *prod);
bool __builtin_smulll_overflow(long long x, long long y, long long *prod);
.. _langext-__c11_atomic: .. _langext-__c11_atomic:
__c11_atomic builtins __c11_atomic builtins
@ -1588,6 +1761,37 @@ C11's ``<stdatomic.h>`` header. These builtins provide the semantics of the
* ``__c11_atomic_fetch_or`` * ``__c11_atomic_fetch_or``
* ``__c11_atomic_fetch_xor`` * ``__c11_atomic_fetch_xor``
Low-level ARM exclusive memory builtins
---------------------------------------
Clang provides overloaded builtins giving direct access to the three key ARM
instructions for implementing atomic operations.
.. code-block:: c
T __builtin_arm_ldrex(const volatile T *addr);
int __builtin_arm_strex(T val, volatile T *addr);
void __builtin_arm_clrex(void);
The types ``T`` currently supported are:
* Integer types with width at most 64 bits.
* Floating-point types
* Pointer types.
Note that the compiler does not guarantee it will not insert stores which clear
the exclusive monitor in between an ``ldrex`` and its paired ``strex``. In
practice this is only usually a risk when the extra store is on the same cache
line as the variable being modified and Clang will only insert stack stores on
its own, so it is best not to use these operations on variables with automatic
storage duration.
Also, loads and stores may be implicit in code written between the ``ldrex`` and
``strex``. Clang will not necessarily mitigate the effects of these either, so
care should be exercised.
For these reasons the higher level atomic primitives should be preferred where
possible.
Non-standard C++11 Attributes Non-standard C++11 Attributes
============================= =============================
@ -1649,7 +1853,7 @@ are accepted with the ``__attribute__((foo))`` syntax are also accepted as
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_, `GCC variable <http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_, `GCC variable
attributes <http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html>`_, and attributes <http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html>`_, and
`GCC type attributes `GCC type attributes
<http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html>`_. As with the GCC <http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html>`_). As with the GCC
implementation, these attributes must appertain to the *declarator-id* in a implementation, these attributes must appertain to the *declarator-id* in a
declaration, which means they must go either at the start of the declaration or declaration, which means they must go either at the start of the declaration or
immediately after the name being declared. immediately after the name being declared.
@ -1698,6 +1902,48 @@ Which compiles to (on X86-32):
movl %gs:(%eax), %eax movl %gs:(%eax), %eax
ret ret
ARM Language Extensions
-----------------------
Interrupt attribute
^^^^^^^^^^^^^^^^^^^
Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on
ARM targets. This attribute may be attached to a function definition and
instructs the backend to generate appropriate function entry/exit code so that
it can be used directly as an interrupt service routine.
The parameter passed to the interrupt attribute is optional, but if
provided it must be a string literal with one of the following values: "IRQ",
"FIQ", "SWI", "ABORT", "UNDEF".
The semantics are as follows:
- If the function is AAPCS, Clang instructs the backend to realign the stack to
8 bytes on entry. This is a general requirement of the AAPCS at public
interfaces, but may not hold when an exception is taken. Doing this allows
other AAPCS functions to be called.
- If the CPU is M-class this is all that needs to be done since the architecture
itself is designed in such a way that functions obeying the normal AAPCS ABI
constraints are valid exception handlers.
- If the CPU is not M-class, the prologue and epilogue are modified to save all
non-banked registers that are used, so that upon return the user-mode state
will not be corrupted. Note that to avoid unnecessary overhead, only
general-purpose (integer) registers are saved in this way. If VFP operations
are needed, that state must be saved manually.
Specifically, interrupt kinds other than "FIQ" will save all core registers
except "lr" and "sp". "FIQ" interrupts will save r0-r7.
- If the CPU is not M-class, the return instruction is changed to one of the
canonical sequences permitted by the architecture for exception return. Where
possible the function itself will make the necessary "lr" adjustments so that
the "preferred return address" is selected.
Unfortunately the compiler is unable to make this guarantee for an "UNDEF"
handler, where the offset from "lr" to the preferred return address depends on
the execution state of the code which generated the exception. In this case
a sequence equivalent to "movs pc, lr" will be used.
Extensions for Static Analysis Extensions for Static Analysis
============================== ==============================
@ -1735,8 +1981,8 @@ with :doc:`ThreadSanitizer`.
Use ``__attribute__((no_sanitize_thread))`` on a function declaration Use ``__attribute__((no_sanitize_thread))`` on a function declaration
to specify that checks for data races on plain (non-atomic) memory accesses to specify that checks for data races on plain (non-atomic) memory accesses
should not be inserted by ThreadSanitizer. should not be inserted by ThreadSanitizer.
The function may still be instrumented by the tool The function is still instrumented by the tool to avoid false positives and
to avoid false positives in other places. provide meaningful stack traces.
.. _langext-memory_sanitizer: .. _langext-memory_sanitizer:
@ -1905,15 +2151,72 @@ to specify that the function must be called while holding the listed shared
locks. Arguments must be lockable type, and there must be at least one locks. Arguments must be lockable type, and there must be at least one
argument. argument.
Consumed Annotation Checking
============================
Clang supports additional attributes for checking basic resource management
properties, specifically for unique objects that have a single owning reference.
The following attributes are currently supported, although **the implementation
for these annotations is currently in development and are subject to change.**
``consumable``
--------------
Each class that uses any of the following annotations must first be marked
using the consumable attribute. Failure to do so will result in a warning.
``set_typestate(new_state)``
----------------------------
Annotate methods that transition an object into a new state with
``__attribute__((set_typestate(new_state)))``. The new new state must be
unconsumed, consumed, or unknown.
``callable_when(...)``
----------------------
Use ``__attribute__((callable_when(...)))`` to indicate what states a method
may be called in. Valid states are unconsumed, consumed, or unknown. Each
argument to this attribute must be a quoted string. E.g.:
``__attribute__((callable_when("unconsumed", "unknown")))``
``tests_typestate(tested_state)``
---------------------------------
Use ``__attribute__((tests_typestate(tested_state)))`` to indicate that a method
returns true if the object is in the specified state..
``param_typestate(expected_state)``
-----------------------------------
This attribute specifies expectations about function parameters. Calls to an
function with annotated parameters will issue a warning if the corresponding
argument isn't in the expected state. The attribute is also used to set the
initial state of the parameter when analyzing the function's body.
``return_typestate(ret_state)``
-------------------------------
The ``return_typestate`` attribute can be applied to functions or parameters.
When applied to a function the attribute specifies the state of the returned
value. The function's body is checked to ensure that it always returns a value
in the specified state. On the caller side, values returned by the annotated
function are initialized to the given state.
If the attribute is applied to a function parameter it modifies the state of
an argument after a call to the function returns. The function's body is
checked to ensure that the parameter is in the expected state before returning.
Type Safety Checking Type Safety Checking
==================== ====================
Clang supports additional attributes to enable checking type safety properties Clang supports additional attributes to enable checking type safety properties
that can't be enforced by C type system. Usecases include: that can't be enforced by the C type system. Use cases include:
* MPI library implementations, where these attributes enable checking that * MPI library implementations, where these attributes enable checking that
buffer type matches the passed ``MPI_Datatype``; the buffer type matches the passed ``MPI_Datatype``;
* for HDF5 library there is a similar usecase as MPI; * for HDF5 library there is a similar use case to MPI;
* checking types of variadic functions' arguments for functions like * checking types of variadic functions' arguments for functions like
``fcntl()`` and ``ioctl()``. ``fcntl()`` and ``ioctl()``.
@ -1948,7 +2251,7 @@ accepts a type tag that determines the type of some other argument.
applicable type tags. applicable type tags.
This attribute is primarily useful for checking arguments of variadic functions This attribute is primarily useful for checking arguments of variadic functions
(``pointer_with_type_tag`` can be used in most of non-variadic cases). (``pointer_with_type_tag`` can be used in most non-variadic cases).
For example: For example:

32
docs/LeakSanitizer.rst Normal file
View 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

View File

@ -176,7 +176,7 @@ Builtin includes
Clang tools need their builtin headers and search for them the same way Clang Clang tools need their builtin headers and search for them the same way Clang
does. Thus, the default location to look for builtin headers is in a path does. Thus, the default location to look for builtin headers is in a path
``$(dirname /path/to/tool)/../lib/clang/3.3/include`` relative to the tool ``$(dirname /path/to/tool)/../lib/clang/3.4/include`` relative to the tool
binary. This works out-of-the-box for tools running from llvm's toplevel binary. This works out-of-the-box for tools running from llvm's toplevel
binary directory after building clang-headers, or if the tool is running from binary directory after building clang-headers, or if the tool is running from
the binary directory of a clang install next to the clang binary. the binary directory of a clang install next to the clang binary.

View File

@ -19,7 +19,12 @@ $(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
-e 's/@abs_srcdir@/./g' \ -e 's/@abs_srcdir@/./g' \
-e 's/@DOT@/dot/g' \ -e 's/@DOT@/dot/g' \
-e 's/@PACKAGE_VERSION@/mainline/' \ -e 's/@PACKAGE_VERSION@/mainline/' \
-e 's/@abs_builddir@/./g' > $@ -e 's/@abs_builddir@/./g' \
-e 's/@enable_searchengine@/NO/g' \
-e 's/@searchengine_url@//g' \
-e 's/@enable_server_based_search@/NO/g' \
-e 's/@enable_external_search@/NO/g' \
-e 's/@extra_search_mappings@//g' > $@
endif endif
include $(CLANG_LEVEL)/Makefile include $(CLANG_LEVEL)/Makefile
@ -73,10 +78,10 @@ doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
regendoc: regendoc:
$(Echo) Building doxygen documentation $(Echo) Building doxygen documentation
$(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \ $(Verb) $(RM) -rf $(PROJ_OBJ_DIR)/doxygen
$(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
fi
$(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg $(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
$(Verb) sed -i "s/[$$]LatestRev[$$]/`svnversion $(PROJ_SRC_DIR)`/g" \
$(PROJ_OBJ_DIR)/doxygen/html/*.html
$(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg $(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
$(Echo) Packaging doxygen documentation $(Echo) Packaging doxygen documentation

View File

@ -90,8 +90,16 @@ to disable uninitialized checks in a particular function.
MemorySanitizer may still instrument such functions to avoid false positives. MemorySanitizer may still instrument such functions to avoid false positives.
This attribute may not be This attribute may not be
supported by other compilers, so we suggest to use it together with supported by other compilers, so we suggest to use it together with
``__has_feature(memory_sanitizer)``. Note: currently, this attribute will be ``__has_feature(memory_sanitizer)``.
lost if the function is inlined.
Blacklist
---------
MemorySanitizer supports ``src`` and ``fun`` entity types in
:doc:`SanitizerSpecialCaseList`, that can be used to relax MemorySanitizer
checks for certain source files and functions. All "Use of uninitialized value"
warnings will be suppressed and all values loaded from memory will be
considered fully initialized.
Origin Tracking Origin Tracking
=============== ===============

View File

@ -2,13 +2,13 @@
Modules Modules
======= =======
.. warning::
The functionality described on this page is supported for C and
Objective-C. C++ support is experimental.
.. contents:: .. contents::
:local: :local:
.. warning::
The functionality described on this page is still experimental! Please
try it out and send us bug reports!
Introduction Introduction
============ ============
Most software is built using a number of software libraries, including libraries supplied by the platform, internal libraries built as part of the software itself to provide structure, and third-party libraries. For each library, one needs to access both its interface (API) and its implementation. In the C family of languages, the interface to a library is accessed by including the appropriate header files(s): Most software is built using a number of software libraries, including libraries supplied by the platform, internal libraries built as part of the software itself to provide structure, and third-party libraries. For each library, one needs to access both its interface (API) and its implementation. In the C family of languages, the interface to a library is accessed by including the appropriate header files(s):
@ -106,24 +106,25 @@ Using Modules
============= =============
To enable modules, pass the command-line flag ``-fmodules`` [#]_. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later. To enable modules, pass the command-line flag ``-fmodules`` [#]_. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later.
Import declaration Objective-C Import declaration
------------------ ------------------------------
The most direct way to import a module is with an *import declaration*, which imports the named module: Objective-C provides syntax for importing a module via an *@import declaration*, which imports the named module:
.. parsed-literal:: .. parsed-literal::
import std; @import std;
The import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g., The @import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
.. parsed-literal:: .. parsed-literal::
import std.io; @import std.io;
Redundant import declarations are ignored, and one is free to import modules at any point within the translation unit, so long as the import declaration is at global scope. Redundant import declarations are ignored, and one is free to import modules at any point within the translation unit, so long as the import declaration is at global scope.
.. warning:: At present, there is no C or C++ syntax for import declarations. Clang
The import declaration syntax described here does not actually exist. Rather, it is a straw man proposal that may very well change when modules are discussed in the C and C++ committees. See the section `Includes as imports`_ to see how modules get imported today. will track the modules proposal in the C++ committee. See the section
`Includes as imports`_ to see how modules get imported today.
Includes as imports Includes as imports
------------------- -------------------
@ -148,6 +149,8 @@ Module maps are specified as separate files (each named ``module.map``) alongsid
.. note:: .. note::
To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps. To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps.
One can use module maps without modules to check the integrity of the use of header files. To do this, use the ``-fmodule-maps`` option instead of the ``-fmodules`` option.
Compilation model Compilation model
----------------- -----------------
@ -165,6 +168,9 @@ Command-line parameters
``-fcxx-modules`` ``-fcxx-modules``
Enable the modules feature for C++ (EXPERIMENTAL and VERY BROKEN). Enable the modules feature for C++ (EXPERIMENTAL and VERY BROKEN).
``-fmodule-maps``
Enable interpretation of module maps (EXPERIMENTAL). This option is implied by ``-fmodules``.
``-fmodules-cache-path=<directory>`` ``-fmodules-cache-path=<directory>``
Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default. Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default.
@ -183,6 +189,15 @@ Command-line parameters
``-module-file-info <module file name>`` ``-module-file-info <module file name>``
Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with. Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with.
``-fmodules-decluse``
Enable checking of module ``use`` declarations.
``-fmodule-name=module-id``
Consider a source file as a part of the given module.
``-fmodule-map-file=<file>``
Load the given module map file if a header from its directory or one of its subdirectories is loaded.
Module Map Language Module Map Language
=================== ===================
@ -231,8 +246,9 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
``config_macros`` ``export`` ``module`` ``config_macros`` ``export`` ``module``
``conflict`` ``framework`` ``requires`` ``conflict`` ``framework`` ``requires``
``exclude`` ``header`` ``umbrella`` ``exclude`` ``header`` ``private``
``explicit`` ``link`` ``explicit`` ``link`` ``umbrella``
``extern`` ``use``
Module map file Module map file
--------------- ---------------
@ -258,6 +274,7 @@ A module declaration describes a module, including the headers that contribute t
*module-declaration*: *module-declaration*:
``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}' ``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}'
``extern`` ``module`` *module-id* *string-literal*
The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition. The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition.
@ -286,10 +303,13 @@ Modules can have a number of different kinds of members, each of which is descri
*umbrella-dir-declaration* *umbrella-dir-declaration*
*submodule-declaration* *submodule-declaration*
*export-declaration* *export-declaration*
*use-declaration*
*link-declaration* *link-declaration*
*config-macros-declaration* *config-macros-declaration*
*conflict-declaration* *conflict-declaration*
An extern module references a module defined by the *module-id* in a file given by the *string-literal*. The file can be referenced either by an absolute path or by a path relative to the current map file.
Requires declaration Requires declaration
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
A *requires-declaration* specifies the requirements that an importing translation unit must satisfy to use the module. A *requires-declaration* specifies the requirements that an importing translation unit must satisfy to use the module.
@ -300,9 +320,12 @@ A *requires-declaration* specifies the requirements that an importing translatio
``requires`` *feature-list* ``requires`` *feature-list*
*feature-list*: *feature-list*:
*identifier* (',' *identifier*)* *feature* (',' *feature*)*
The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module. *feature*:
``!``:sub:`opt` *identifier*
The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module. The optional ``!`` indicates that a feature is incompatible with the module.
The following features are defined: The following features are defined:
@ -360,6 +383,7 @@ A header declaration specifies that a particular header is associated with the e
*header-declaration*: *header-declaration*:
``umbrella``:sub:`opt` ``header`` *string-literal* ``umbrella``:sub:`opt` ``header`` *string-literal*
``private`` ``header`` *string-literal*
``exclude`` ``header`` *string-literal* ``exclude`` ``header`` *string-literal*
A header declaration that does not contain ``exclude`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule. A header declaration that does not contain ``exclude`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule.
@ -372,6 +396,8 @@ A header with the ``umbrella`` specifier is called an umbrella header. An umbrel
``-Wincomplete-umbrella`` warning option to ask Clang to complain ``-Wincomplete-umbrella`` warning option to ask Clang to complain
about headers not covered by the umbrella header or the module map. about headers not covered by the umbrella header or the module map.
A header with the ``private`` specifier may not be included from outside the module itself.
A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module. A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module.
**Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings). **Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings).
@ -521,6 +547,36 @@ Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard e
compatibility for programs that rely on transitive inclusion (i.e., compatibility for programs that rely on transitive inclusion (i.e.,
all of them). all of them).
Use declaration
~~~~~~~~~~~~~~~
A *use-declaration* specifies one of the other modules that the module is allowed to use. An import or include not matching one of these is rejected when the option *-fmodules-decluse*.
.. parsed-literal::
*use-declaration*:
``use`` *module-id*
**Example**:: In the following example, use of A from C is not declared, so will trigger a warning.
.. parsed-literal::
module A {
header "a.h"
}
module B {
header "b.h"
}
module C {
header "c.h"
use B
}
When compiling a source file that implements a module, use the option ``-fmodule-name=``module-id to indicate that the source file is logically part of that module.
The compiler at present only applies restrictions to the module directly being built.
Link declaration Link declaration
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program. A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.

View File

@ -218,12 +218,6 @@ character data is valid. Passing ``NULL`` as the character pointer will
raise an exception at runtime. When possible, the compiler will reject raise an exception at runtime. When possible, the compiler will reject
``NULL`` character pointers used in boxed expressions. ``NULL`` character pointers used in boxed expressions.
Availability
------------
Boxed expressions will be available in clang 3.2. It is not currently
available in any Apple compiler.
Container Literals Container Literals
================== ==================

View File

@ -1,40 +1,56 @@
======================= =======================
Clang 3.3 Release Notes Clang 3.4 Release Notes
======================= =======================
.. contents:: .. contents::
:local: :local:
:depth: 2 :depth: 2
Written by the `LLVM Team <http://llvm.org/>`_
Introduction Introduction
============ ============
This document contains the release notes for the Clang C/C++/Objective-C This document contains the release notes for the Clang C/C++/Objective-C
frontend, part of the LLVM Compiler Infrastructure, release 3.3. Here we frontend, part of the LLVM Compiler Infrastructure, release 3.4. Here we
describe the status of Clang in some detail, including major improvements from describe the status of Clang in some detail, including major
the previous release and new feature work. For the general LLVM release notes, improvements from the previous release and new feature work. For the
see `the LLVM documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM general LLVM release notes, see `the LLVM
releases may be downloaded from the `LLVM releases web site documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
<http://llvm.org/releases/>`_. releases may be downloaded from the `LLVM releases web
site <http://llvm.org/releases/>`_.
For more information about Clang or LLVM, including information about the latest For more information about Clang or LLVM, including information about
release, please check out the main please see the `Clang Web Site the latest release, please check out the main `Clang Web
<http://clang.llvm.org>`_ or the `LLVM Web Site <http://llvm.org>`_. Site <http://clang.llvm.org>`_ or the `LLVM Web
Site <http://llvm.org>`_.
Note that if you are reading this file from a Subversion checkout or the main Note that if you are reading this file from a Subversion checkout or the
Clang web page, this document applies to the *next* release, not the current main Clang web page, this document applies to the *next* release, not
one. To see the release notes for a specific release, please see the `releases the current one. To see the release notes for a specific release, please
page <http://llvm.org/releases/>`_. see the `releases page <http://llvm.org/releases/>`_.
What's New in Clang 3.3? What's New in Clang 3.4?
======================== ========================
Some of the major new features and improvements to Clang are listed Some of the major new features and improvements to Clang are listed
here. Generic improvements to Clang as a whole or to its underlying here. Generic improvements to Clang as a whole or to its underlying
infrastructure are described first, followed by language-specific sections with infrastructure are described first, followed by language-specific
improvements to Clang's support for those languages. sections with improvements to Clang's support for those languages.
Last release which will build as C++98
--------------------------------------
This is expected to be the last release of Clang which compiles using a C++98
toolchain. We expect to start using some C++11 features in Clang starting after
this release. That said, we are committed to supporting a reasonable set of
modern C++ toolchains as the host compiler on all of the platforms. This will
at least include Visual Studio 2012 on Windows, and Clang 3.1 or GCC 4.7.x on
Mac and Linux. The final set of compilers (and the C++11 features they support)
is not set in stone, but we wanted users of Clang to have a heads up that the
next release will involve a substantial change in the host toolchain
requirements.
Note that this change is part of a change for the entire LLVM project, not just
Clang.
Major New Features Major New Features
------------------ ------------------
@ -44,90 +60,210 @@ Improvements to Clang's diagnostics
Clang's diagnostics are constantly being improved to catch more issues, Clang's diagnostics are constantly being improved to catch more issues,
explain them more clearly, and provide more accurate source information explain them more clearly, and provide more accurate source information
about them. The improvements since the 3.2 release include: about them. The improvements since the 3.3 release include:
Extended Identifiers: Unicode Support and Universal Character Names - -Wheader-guard warns on mismatches between the #ifndef and #define lines
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in a header guard.
Clang 3.3 includes support for *extended identifiers* in C99 and C++. .. code-block:: c
This feature allows identifiers to contain certain Unicode characters, as
specified by the active language standard; these characters can be written #ifndef multiple
directly in the source file using the UTF-8 encoding, or referred to using #define multi
*universal character names* (``\u00E0``, ``\U000000E0``). #endif
returns
`warning: 'multiple' is used as a header guard here, followed by #define of a different macro [-Wheader-guard]`
- -Wlogical-not-parentheses warns when a logical not ('!') only applies to the
left-hand side of a comparison. This warning is part of -Wparentheses.
.. code-block:: c++
int i1 = 0, i2 = 1;
bool ret;
ret = !i1 == i2;
returns
`warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses]`
- Boolean increment, a deprecated feature, has own warning flag
-Wdeprecated-increment-bool, and is still part of -Wdeprecated.
- Clang errors on builtin enum increments and decrements.
.. code-block:: c++
enum A { A1, A2 };
void test() {
A a;
a++;
}
returns
`error: must use 'enum' tag to refer to type 'A'`
- -Wloop-analysis now warns on for-loops which have the same increment or
decrement in the loop header as the last statement in the loop.
.. code-block:: c
void foo(char *a, char *b, unsigned c) {
for (unsigned i = 0; i < c; ++i) {
a[i] = b[i];
++i;
}
}
returns
`warning: variable 'i' is incremented both in the loop header and in the loop body [-Wloop-analysis]`
- -Wuninitialized now performs checking across field initializers to detect
when one field in used uninitialized in another field initialization.
.. code-block:: c++
class A {
int x;
int y;
A() : x(y) {}
};
returns
`warning: field 'y' is uninitialized when used here [-Wuninitialized]`
- Clang can detect initializer list use inside a macro and suggest parentheses
if possible to fix.
- Many improvements to Clang's typo correction facilities, such as:
+ Adding global namespace qualifiers so that corrections can refer to shadowed
or otherwise ambiguous or unreachable namespaces.
+ Including accessible class members in the set of typo correction candidates,
so that corrections requiring a class name in the name specifier are now
possible.
+ Allowing typo corrections that involve removing a name specifier.
+ In some situations, correcting function names when a function was given the
wrong number of arguments, including situations where the original function
name was correct but was shadowed by a lexically closer function with the
same name yet took a different number of arguments.
+ Offering typo suggestions for 'using' declarations.
+ Providing better diagnostics and fixit suggestions in more situations when
a '->' was used instead of '.' or vice versa.
+ Providing more relevant suggestions for typos followed by '.' or '='.
+ Various performance improvements when searching for typo correction
candidates.
- `LeakSanitizer <LeakSanitizer.html>`_ is an experimental memory leak detector
which can be combined with AddressSanitizer.
New Compiler Flags
------------------
- Clang no longer special cases -O4 to enable lto. Explicitly pass -flto to
enable it.
- Clang no longer fails on >= -O5. These flags are mapped to -O3 instead.
- Command line "clang -O3 -flto a.c -c" and "clang -emit-llvm a.c -c"
are no longer equivalent.
- Clang now errors on unknown -m flags (``-munknown-to-clang``),
unknown -f flags (``-funknown-to-clang``) and unknown
options (``-what-is-this``).
C Language Changes in Clang C Language Changes in Clang
--------------------------- ---------------------------
- Added new checked arithmetic builtins for security critical applications.
C++ Language Changes in Clang C++ Language Changes in Clang
----------------------------- -----------------------------
- Clang now correctly implements language linkage for functions and variables. - Fixed an ABI regression, introduced in Clang 3.2, which affected
This means that, for example, it is now possible to overload static functions member offsets for classes inheriting from certain classes with tail padding.
declared in an ``extern "C"`` context. For backwards compatibility, an alias See PR16537.
with the unmangled name is still emitted if it is the only one and has the
``used`` attribute. - Clang 3.4 supports the 2013-08-28 draft of the ISO WG21 SG10 feature test
macro recommendations. These aim to provide a portable method to determine
whether a compiler supports a language feature, much like Clang's
|has_feature macro|_.
.. |has_feature macro| replace:: ``__has_feature`` macro
.. _has_feature macro: LanguageExtensions.html#has-feature-and-has-extension
C++1y Feature Support
^^^^^^^^^^^^^^^^^^^^^
Clang 3.4 supports all the features in the current working draft of the
upcoming C++ standard, provisionally named C++1y. Support for the following
major new features has been added since Clang 3.3:
- Generic lambdas and initialized lambda captures.
- Deduced function return types (``auto f() { return 0; }``).
- Generalized ``constexpr`` support (variable mutation and loops).
- Variable templates and static data member templates.
- Use of ``'`` as a digit separator in numeric literals.
- Support for sized ``::operator delete`` functions.
In addition, ``[[deprecated]]`` is now accepted as a synonym for Clang's
existing ``deprecated`` attribute.
Use ``-std=c++1y`` to enable C++1y mode.
OpenCL C Language Changes in Clang
----------------------------------
- OpenCL C "long" now always has a size of 64 bit, and all OpenCL C
types are aligned as specified in the OpenCL C standard. Also,
"char" is now always signed.
Internal API Changes Internal API Changes
-------------------- --------------------
These are major API changes that have happened since the 3.2 release of These are major API changes that have happened since the 3.3 release of
Clang. If upgrading an external codebase that uses Clang as a library, Clang. If upgrading an external codebase that uses Clang as a library,
this section should help get you past the largest hurdles of upgrading. this section should help get you past the largest hurdles of upgrading.
Value Casting Wide Character Types
^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
Certain type hierarchies (TypeLoc, CFGElement, ProgramPoint, and SVal) were The ASTContext class now keeps track of two different types for wide character
misusing the llvm::cast machinery to perform undefined operations. Their APIs types: WCharTy and WideCharTy. WCharTy represents the built-in wchar_t type
have been changed to use two member function templates that return values available in C++. WideCharTy is the type used for wide character literals; in
instead of pointers or references - "T castAs" and "Optional<T> getAs" (in the C++ it is the same as WCharTy, but in C99, where wchar_t is a typedef, it is an
case of the TypeLoc hierarchy the latter is "T getAs" and you can use the integer type.
boolean testability of a TypeLoc (or its 'validity') to verify that the cast
succeeded). Essentially all previous 'cast' usage should be replaced with
'castAs' and 'dyn_cast' should be replaced with 'getAs'. See r175462 for the
first example of such a change along with many examples of how code was
migrated to the new API.
Storage Class
^^^^^^^^^^^^^
For each variable and function Clang used to keep the storage class as written
in the source, the linkage and a semantic storage class. This was a bit
redundant and the semantic storage class has been removed. The method
getStorageClass now returns what is written in the source code for that decl.
libclang
--------
The clang_CXCursorSet_contains() function previously incorrectly returned 0
if it contained a CXCursor, contrary to what the documentation stated. This
has been fixed so that the function returns a non-zero value if the set
contains a cursor. This is API breaking change, but matches the intended
original behavior. Moreover, this also fixes the issue of an invalid CXCursorSet
appearing to contain any CXCursor.
Static Analyzer Static Analyzer
--------------- ---------------
The static analyzer (which contains additional code checking beyond compiler The static analyzer has been greatly improved. This impacts the overall analyzer quality and reduces a number of false positives.
warnings) has improved significantly in both in the core analysis engine and In particular, this release provides enhanced C++ support, reasoning about initializer lists, zeroing constructors, noreturn destructors and modeling of destructor calls on calls to delete.
also in the kinds of issues it can find.
Core Analysis Improvements Clang Format
========================== ------------
- Support for interprocedural reasoning about constructors and destructors. Clang now includes a new tool ``clang-format`` which can be used to
- New false positive suppression mechanisms that reduced the number of false automatically format C, C++ and Objective-C source code. ``clang-format``
null pointer dereference warnings due to interprocedural analysis. automatically chooses linebreaks and indentation and can be easily integrated
- Major performance enhancements to speed up interprocedural analysis into editors, IDEs and version control systems. It supports several pre-defined
styles as well as precise style control using a multitude of formatting
options. ``clang-format`` itself is just a thin wrapper around a library which
can also be used directly from code refactoring and code translation tools.
More information can be found on `Clang Format's
site <http://clang.llvm.org/docs/ClangFormat.html>`_.
New Issues Found Windows Support
================ ---------------
- New memory error checks such as use-after-free with C++ 'delete'. - `clang-cl <UsersManual.html#clang-cl>`_ provides a new driver mode that is
- Detection of mismatched allocators and deallocators (e.g., using 'new' with designed for compatibility with Visual Studio's compiler, cl.exe. This driver
'free()', 'malloc()' with 'delete'). mode makes Clang accept the same kind of command-line options as cl.exe. The
- Additional checks for misuses of Apple Foundation framework collection APIs. installer will attempt to expose clang-cl in any Visual Studio installations
on the system as a Platform Toolset, e.g. "LLVM-vs2012". clang-cl targets the
Microsoft ABI by default. Please note that this driver mode and compatibility
with the MS ABI is highly experimental.
Python Binding Changes
----------------------
The following methods have been added:
Significant Known Problems Significant Known Problems
========================== ==========================
@ -135,11 +271,13 @@ Significant Known Problems
Additional Information Additional Information
====================== ======================
A wide variety of additional information is available on the `Clang web page A wide variety of additional information is available on the `Clang web
<http://clang.llvm.org/>`_. The web page contains versions of the API page <http://clang.llvm.org/>`_. The web page contains versions of the
documentation which are up-to-date with the Subversion version of the source API documentation which are up-to-date with the Subversion revision of
code. You can access versions of these documents specific to this release by the source code. You can access versions of these documents specific to
going into the "``clang/docs/``" directory in the Clang tree. this release by going into the "``clang/docs/``" directory in the Clang
tree.
If you have any questions or comments about Clang, please feel free to contact If you have any questions or comments about Clang, please feel free to
us via the `mailing list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_. contact us via the `mailing
list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_.

View 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

View File

@ -91,11 +91,21 @@ Some code should not be instrumented by ThreadSanitizer.
One may use the function attribute One may use the function attribute
:ref:`no_sanitize_thread <langext-thread_sanitizer>` :ref:`no_sanitize_thread <langext-thread_sanitizer>`
to disable instrumentation of plain (non-atomic) loads/stores in a particular function. to disable instrumentation of plain (non-atomic) loads/stores in a particular function.
ThreadSanitizer may still instrument such functions to avoid false positives. ThreadSanitizer still instruments such functions to avoid false positives and
provide meaningful stack traces.
This attribute may not be This attribute may not be
supported by other compilers, so we suggest to use it together with supported by other compilers, so we suggest to use it together with
``__has_feature(thread_sanitizer)``. Note: currently, this attribute will be ``__has_feature(thread_sanitizer)``.
lost if the function is inlined.
Blacklist
---------
ThreadSanitizer supports ``src`` and ``fun`` entity types in
:doc:`SanitizerSpecialCaseList`, that can be used to suppress data race reports in
the specified source files or functions. Unlike functions marked with
:ref:`no_sanitize_thread <langext-thread_sanitizer>` attribute,
blacklisted functions are not instrumented at all. This can lead to false positives
due to missed synchronization via atomic operations and missed stack frames in reports.
Limitations Limitations
----------- -----------

View File

@ -44,6 +44,8 @@ as to improve functionality through Clang-specific features. The Clang
driver and language features are intentionally designed to be as driver and language features are intentionally designed to be as
compatible with the GNU GCC compiler as reasonably possible, easing compatible with the GNU GCC compiler as reasonably possible, easing
migration from GCC to Clang. In most cases, code "just works". migration from GCC to Clang. In most cases, code "just works".
Clang also provides an alternative driver, :ref:`clang-cl`, that is designed
to be compatible with the Visual C++ compiler, cl.exe.
In addition to language specific features, Clang has a variety of In addition to language specific features, Clang has a variety of
features that depend on what CPU architecture or operating system is features that depend on what CPU architecture or operating system is
@ -235,6 +237,11 @@ output format of the diagnostics that it generates.
^ ^
// //
**-fansi-escape-codes**
Controls whether ANSI escape codes are used instead of the Windows Console
API to output colored diagnostics. This option is only used on Windows and
defaults to off.
.. option:: -fdiagnostics-format=clang/msvc/vi .. option:: -fdiagnostics-format=clang/msvc/vi
Changes diagnostic output format to better match IDEs and command line tools. Changes diagnostic output format to better match IDEs and command line tools.
@ -422,7 +429,7 @@ output format of the diagnostics that it generates.
map< map<
[...], [...],
map< map<
[float != float], [float != double],
[...]>>> [...]>>>
.. _cl_diag_warning_groups: .. _cl_diag_warning_groups:
@ -853,7 +860,7 @@ Controlling Code Generation
Clang provides a number of ways to control code generation. The options Clang provides a number of ways to control code generation. The options
are listed below. are listed below.
**-fsanitize=check1,check2,...** **-f[no-]sanitize=check1,check2,...**
Turn on runtime checks for various forms of undefined or suspicious Turn on runtime checks for various forms of undefined or suspicious
behavior. behavior.
@ -889,13 +896,14 @@ are listed below.
includes all of the checks listed below other than includes all of the checks listed below other than
``unsigned-integer-overflow``. ``unsigned-integer-overflow``.
``-fsanitize=undefined-trap``: This includes all sanitizers - ``-fsanitize=undefined-trap``: This includes all sanitizers
included by ``-fsanitize=undefined``, except those that require included by ``-fsanitize=undefined``, except those that require
runtime support. This group of sanitizers are generally used runtime support. This group of sanitizers is intended to be
in conjunction with the ``-fsanitize-undefined-trap-on-error`` used in conjunction with the ``-fsanitize-undefined-trap-on-error``
flag, which causes traps to be emitted, rather than calls to flag. This includes all of the checks listed below other than
runtime libraries. This includes all of the checks listed below ``unsigned-integer-overflow`` and ``vptr``.
other than ``unsigned-integer-overflow`` and ``vptr``. - ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
flow analysis.
The following more fine-grained checks are also available: The following more fine-grained checks are also available:
@ -913,6 +921,8 @@ are listed below.
destination. destination.
- ``-fsanitize=float-divide-by-zero``: Floating point division by - ``-fsanitize=float-divide-by-zero``: Floating point division by
zero. zero.
- ``-fsanitize=function``: Indirect call of a function through a
function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero. - ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
- ``-fsanitize=null``: Use of a null pointer or creation of a null - ``-fsanitize=null``: Use of a null pointer or creation of a null
reference. reference.
@ -941,6 +951,15 @@ are listed below.
it is of the wrong dynamic type, or that its lifetime has not it is of the wrong dynamic type, or that its lifetime has not
begun or has ended. Incompatible with ``-fno-rtti``. begun or has ended. Incompatible with ``-fno-rtti``.
You can turn off or modify checks for certain source files, functions
or even variables by providing a special file:
- ``-fsanitize-blacklist=/path/to/blacklist/file``: disable or modify
sanitizer checks for objects listed in the file. See
:doc:`SanitizerSpecialCaseList` for file format description.
- ``-fno-sanitize-blacklist``: don't use blacklist file, if it was
specified earlier in the command line.
Experimental features of AddressSanitizer (not ready for widespread Experimental features of AddressSanitizer (not ready for widespread
use, require explicit ``-fsanitize=address``): use, require explicit ``-fsanitize=address``):
@ -958,10 +977,31 @@ are listed below.
uninitialized bits came from. Slows down execution by additional uninitialized bits came from. Slows down execution by additional
1.5x-2x. 1.5x-2x.
Extra features of UndefinedBehaviorSanitizer:
- ``-fno-sanitize-recover``: By default, after a sanitizer diagnoses
an issue, it will attempt to continue executing the program if there
is a reasonable behavior it can give to the faulting operation. This
option causes the program to abort instead.
- ``-fsanitize-undefined-trap-on-error``: Causes traps to be emitted
rather than calls to runtime libraries when a problem is detected.
This option is intended for use in cases where the sanitizer runtime
cannot be used (for instance, when building libc or a kernel module).
This is only compatible with the sanitizers in the ``undefined-trap``
group.
The ``-fsanitize=`` argument must also be provided when linking, in The ``-fsanitize=`` argument must also be provided when linking, in
order to link to the appropriate runtime library. It is not possible order to link to the appropriate runtime library. When using
to combine the ``-fsanitize=address`` and ``-fsanitize=thread`` ``-fsanitize=vptr`` (or a group that includes it, such as
checkers in the same program. ``-fsanitize=undefined``) with a C++ program, the link must be
performed by ``clang++``, not ``clang``, in order to link against the
C++-specific parts of the runtime library.
It is not possible to combine more than one of the ``-fsanitize=address``,
``-fsanitize=thread``, and ``-fsanitize=memory`` checkers in the same
program. The ``-fsanitize=undefined`` checks can be combined with other
sanitizers.
**-f[no-]address-sanitizer** **-f[no-]address-sanitizer**
Deprecated synonym for :ref:`-f[no-]sanitize=address Deprecated synonym for :ref:`-f[no-]sanitize=address
<opt_fsanitize_address>`. <opt_fsanitize_address>`.
@ -1007,6 +1047,26 @@ are listed below.
efficient model can be used. The TLS model can be overridden per efficient model can be used. The TLS model can be overridden per
variable using the ``tls_model`` attribute. variable using the ``tls_model`` attribute.
.. option:: -mhwdiv=[values]
Select the ARM modes (arm or thumb) that support hardware division
instructions.
Valid values are: ``arm``, ``thumb`` and ``arm,thumb``.
This option is used to indicate which mode (arm or thumb) supports
hardware division instructions. This only applies to the ARM
architecture.
.. option:: -m[no-]crc
Enable or disable CRC instructions.
This option is used to indicate whether CRC instructions are to
be generated. This only applies to the ARM architecture.
CRC instructions are enabled by default on ARMv8.
Controlling Size of Debug Information Controlling Size of Debug Information
------------------------------------- -------------------------------------
@ -1178,30 +1238,40 @@ Microsoft extensions
-------------------- --------------------
clang has some experimental support for extensions from Microsoft Visual clang has some experimental support for extensions from Microsoft Visual
C++; to enable it, use the -fms-extensions command-line option. This is C++; to enable it, use the ``-fms-extensions`` command-line option. This is
the default for Windows targets. Note that the support is incomplete; the default for Windows targets. Note that the support is incomplete.
enabling Microsoft extensions will silently drop certain constructs Some constructs such as ``dllexport`` on classes are ignored with a warning,
(including ``__declspec`` and Microsoft-style asm statements). and others such as `Microsoft IDL annotations
<http://msdn.microsoft.com/en-us/library/8tesw2eh.aspx>`_ are silently
ignored.
clang has a -fms-compatibility flag that makes clang accept enough clang has a ``-fms-compatibility`` flag that makes clang accept enough
invalid C++ to be able to parse most Microsoft headers. This flag is invalid C++ to be able to parse most Microsoft headers. For example, it
enabled by default for Windows targets. allows `unqualified lookup of dependent base class members
<http://clang.llvm.org/compatibility.html#dep_lookup_bases>`_, which is
a common compatibility issue with clang. This flag is enabled by default
for Windows targets.
-fdelayed-template-parsing lets clang delay all template instantiation ``-fdelayed-template-parsing`` lets clang delay parsing of function template
until the end of a translation unit. This flag is enabled by default for definitions until the end of a translation unit. This flag is enabled by
Windows targets. default for Windows targets.
- clang allows setting ``_MSC_VER`` with ``-fmsc-version=``. It defaults to - clang allows setting ``_MSC_VER`` with ``-fmsc-version=``. It defaults to
1300 which is the same as Visual C/C++ 2003. Any number is supported 1700 which is the same as Visual C/C++ 2012. Any number is supported
and can greatly affect what Windows SDK and c++stdlib headers clang and can greatly affect what Windows SDK and c++stdlib headers clang
can compile. This option will be removed when clang supports the full can compile.
set of MS extensions required for these headers.
- clang does not support the Microsoft extension where anonymous record - clang does not support the Microsoft extension where anonymous record
members can be declared using user defined typedefs. members can be declared using user defined typedefs.
- clang supports the Microsoft "#pragma pack" feature for controlling - clang supports the Microsoft ``#pragma pack`` feature for controlling
record layout. GCC also contains support for this feature, however record layout. GCC also contains support for this feature, however
where MSVC and GCC are incompatible clang follows the MSVC where MSVC and GCC are incompatible clang follows the MSVC
definition. definition.
- clang supports the Microsoft ``#pragma comment(lib, "foo.lib")`` feature for
automatically linking against the specified library. Currently this feature
only works with the Visual C++ linker.
- clang supports the Microsoft ``#pragma comment(linker, "/flag:foo")`` feature
for adding linker flags to COFF object files. The user is responsible for
ensuring that the linker understands the flags.
- clang defaults to C++11 for Windows targets. - clang defaults to C++11 for Windows targets.
.. _cxx: .. _cxx:
@ -1210,8 +1280,8 @@ C++ Language Features
===================== =====================
clang fully implements all of standard C++98 except for exported clang fully implements all of standard C++98 except for exported
templates (which were removed in C++11), and `many C++11 templates (which were removed in C++11), and all of standard C++11
features <http://clang.llvm.org/cxx_status.html>`_ are also implemented. and the current draft standard for C++1y.
Controlling implementation limits Controlling implementation limits
--------------------------------- ---------------------------------
@ -1229,7 +1299,12 @@ Controlling implementation limits
.. option:: -ftemplate-depth=N .. option:: -ftemplate-depth=N
Sets the limit for recursively nested template instantiations to N. The Sets the limit for recursively nested template instantiations to N. The
default is 1024. default is 256.
.. option:: -foperator-arrow-depth=N
Sets the limit for iterative calls to 'operator->' functions to N. The
default is 256.
.. _objc: .. _objc:
@ -1258,8 +1333,8 @@ Darwin (Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested
to correctly compile many large C, C++, Objective-C, and Objective-C++ to correctly compile many large C, C++, Objective-C, and Objective-C++
codebases. codebases.
On ``x86_64-mingw32``, passing i128(by value) is incompatible to Microsoft On ``x86_64-mingw32``, passing i128(by value) is incompatible with the
x64 calling conversion. You might need to tweak Microsoft x64 calling conversion. You might need to tweak
``WinX86_64ABIInfo::classify()`` in lib/CodeGen/TargetInfo.cpp. ``WinX86_64ABIInfo::classify()`` in lib/CodeGen/TargetInfo.cpp.
ARM ARM
@ -1271,11 +1346,19 @@ C++, Objective-C, and Objective-C++ codebases. Clang only supports a
limited number of ARM architectures. It does not yet fully support limited number of ARM architectures. It does not yet fully support
ARMv5, for example. ARMv5, for example.
PowerPC
^^^^^^^
The support for PowerPC (especially PowerPC64) is considered stable
on Linux and FreeBSD: it has been tested to correctly compile many
large C and C++ codebases. PowerPC (32bit) is still missing certain
features (e.g. PIC code on ELF platforms).
Other platforms Other platforms
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
clang currently contains some support for PPC and Sparc; however, clang currently contains some support for other architectures (e.g. Sparc);
significant pieces of code generation are still missing, and they however, significant pieces of code generation are still missing, and they
haven't undergone significant testing. haven't undergone significant testing.
clang contains limited support for the MSP430 embedded processor, but clang contains limited support for the MSP430 embedded processor, but
@ -1302,9 +1385,10 @@ None
Windows Windows
^^^^^^^ ^^^^^^^
Experimental supports are on Cygming. Clang has experimental support for targeting "Cygming" (Cygwin / MinGW)
platforms.
See also `Microsoft Extensions <c_ms>`. See also :ref:`Microsoft Extensions <c_ms>`.
Cygwin Cygwin
"""""" """"""
@ -1349,3 +1433,111 @@ Clang expects the GCC executable "gcc.exe" compiled for
`Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on `Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on
``x86_64-w64-mingw32``. ``x86_64-w64-mingw32``.
.. _clang-cl:
clang-cl
========
clang-cl is an alternative command-line interface to Clang driver, designed for
compatibility with the Visual C++ compiler, cl.exe.
To enable clang-cl to find system headers, libraries, and the linker when run
from the command-line, it should be executed inside a Visual Studio Native Tools
Command Prompt or a regular Command Prompt where the environment has been set
up using e.g. `vcvars32.bat <http://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx>`_.
clang-cl can also be used from inside Visual Studio by using an LLVM Platform
Toolset.
Command-Line Options
--------------------
To be compatible with cl.exe, clang-cl supports most of the same command-line
options. Those options can start with either ``/`` or ``-``. It also supports
some of Clang's core options, such as the ``-W`` options.
Options that are known to clang-cl, but not currently supported, are ignored
with a warning. For example:
::
clang-cl.exe: warning: argument unused during compilation: '/Zi'
To suppress warnings about unused arguments, use the ``-Qunused-arguments`` option.
Options that are not known to clang-cl will cause errors. If they are spelled with a
leading ``/``, they will be mistaken for a filename:
::
clang-cl.exe: error: no such file or directory: '/foobar'
Please `file a bug <http://llvm.org/bugs/enter_bug.cgi?product=clang&component=Driver>`_
for any valid cl.exe flags that clang-cl does not understand.
Execute ``clang-cl /?`` to see a list of supported options:
::
/? Display available options
/c Compile only
/D <macro[=value]> Define macro
/fallback Fall back to cl.exe if clang-cl fails to compile
/FA Output assembly code file during compilation
/Fa<file or directory> Output assembly code to this file during compilation
/Fe<file or directory> Set output executable file or directory (ends in / or \)
/FI<value> Include file before parsing
/Fo<file or directory> Set output object file, or directory (ends in / or \)
/GF- Disable string pooling
/GR- Disable RTTI
/GR Enable RTTI
/help Display available options
/I <dir> Add directory to include search path
/J Make char type unsigned
/LDd Create debug DLL
/LD Create DLL
/link <options> Forward options to the linker
/MDd Use DLL debug run-time
/MD Use DLL run-time
/MTd Use static debug run-time
/MT Use static run-time
/Ob0 Disable inlining
/Od Disable optimization
/Oi- Disable use of builtin functions
/Oi Enable use of builtin functions
/Os Optimize for size
/Ot Optimize for speed
/Ox Maximum optimization
/Oy- Disable frame pointer omission
/Oy Enable frame pointer omission
/O<n> Optimization level
/P Only run the preprocessor
/showIncludes Print info about included files to stderr
/TC Treat all source files as C
/Tc <filename> Specify a C source file
/TP Treat all source files as C++
/Tp <filename> Specify a C++ source file
/U <macro> Undefine macro
/W0 Disable all warnings
/W1 Enable -Wall
/W2 Enable -Wall
/W3 Enable -Wall
/W4 Enable -Wall
/Wall Enable -Wall
/WX- Do not treat warnings as errors
/WX Treat warnings as errors
/w Disable all warnings
/Zs Syntax-check only
The /fallback Option
^^^^^^^^^^^^^^^^^^^^
When clang-cl is run with the ``/fallback`` option, it will first try to
compile files itself. For any file that it fails to compile, it will fall back
and try to compile the file by invoking cl.exe.
This option is intended to be used as a temporary means to build projects where
clang-cl cannot successfully compile all the files. clang-cl may fail to compile
a file either because it cannot generate code for some C++ feature, or because
it cannot parse some Microsoft language extension.

View File

@ -30,6 +30,10 @@ using a 'dot' format viewer (such as Graphviz on OS X) instead.
- debug.DumpLiveVars: Show the results of live variable analysis for each - debug.DumpLiveVars: Show the results of live variable analysis for each
top-level function being analyzed. top-level function being analyzed.
- debug.ViewExplodedGraph: Show the Exploded Graphs generated for the
analysis of different functions in the input translation unit. When there
are several functions analyzed, display one graph per function. Beware
that these graphs may grow very large, even for small functions.
Path Tracking Path Tracking
============= =============
@ -121,6 +125,19 @@ ExprInspection checks
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}} clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
} }
- void clang_analyzer_warnIfReached();
Generate a warning if this line of code gets reached by the analyzer.
Example usage::
if (true) {
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
else {
clang_analyzer_warnIfReached(); // no-warning
}
Statistics Statistics
========== ==========

View File

@ -74,7 +74,7 @@ This option controls whether functions from the C++ standard library, including
methods of the container classes in the Standard Template Library, should be methods of the container classes in the Standard Template Library, should be
considered for inlining. considered for inlining.
-analyzer-config c++-template-inlining=[true | false] -analyzer-config c++-stdlib-inlining=[true | false]
Currently, C++ standard library functions are considered for inlining by Currently, C++ standard library functions are considered for inlining by
default. default.

View File

@ -48,9 +48,9 @@
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '3.3' version = '3.4'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '3.3' release = '3.4'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -48,9 +48,9 @@
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '3.3' version = '3.4'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '3.3' release = '3.4'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -1224,7 +1224,30 @@ DOT_CLEANUP = YES
# Configuration::additions related to the search engine # Configuration::additions related to the search engine
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# The SEARCHENGINE tag specifies whether or not a search engine should be # When the SEARCHENGINE tag is enabled doxygen will generate a search box
# used. If set to NO the values of all tags below this one will be ignored. # for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
# (GENERATE_DOCSET) there is already a search function so this one should
# typically be disabled. For large projects the javascript based search engine
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
SEARCHENGINE = NO SEARCHENGINE = @enable_searchengine@
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a PHP enabled web server instead of at the web client
# using Javascript. Doxygen will generate the search PHP script and index
# file to put on the web server. The advantage of the server
# based approach is that it scales better to large projects and allows
# full text search. The disadvances is that it is more difficult to setup
# and does not have live searching capabilities.
SERVER_BASED_SEARCH = @enable_server_based_search@
SEARCHENGINE_URL = @searchengine_url@
EXTERNAL_SEARCH = @enable_external_search@
EXTERNAL_SEARCH_ID = clang
EXTRA_SEARCH_MAPPINGS = @extra_search_mappings@

View File

@ -1,6 +1,6 @@
<hr> <hr>
<p class="footer"> <p class="footer">
Generated on $datetime by <a href="http://www.doxygen.org">Doxygen Generated on $datetime for r$LatestRev$ by <a href="http://www.doxygen.org">Doxygen
$doxygenversion</a>.</p> $doxygenversion</a>.</p>
<p class="footer"> <p class="footer">

View File

@ -18,9 +18,13 @@ Using Clang as a Compiler
UsersManual UsersManual
LanguageExtensions LanguageExtensions
CrossCompilation
AddressSanitizer AddressSanitizer
ThreadSanitizer ThreadSanitizer
MemorySanitizer MemorySanitizer
DataFlowSanitizer
LeakSanitizer
SanitizerSpecialCaseList
Modules Modules
FAQ FAQ
@ -51,6 +55,7 @@ Using Clang Tools
ClangTools ClangTools
ClangCheck ClangCheck
ClangFormat ClangFormat
ClangFormatStyleOptions
Design Documents Design Documents
================ ================

View File

@ -7,7 +7,7 @@ clang - the Clang C, C++, and Objective-C compiler
=head1 SYNOPSIS =head1 SYNOPSIS
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g> B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
[B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-Oz>|B<-O3>|B<-Ofast>|B<-O4>] [B<-O0>|B<-O1>|B<-O2>|B<-O3>|B<-Ofast>|B<-Os>|B<-Oz>|B<-O>|B<-O4>]
B<-W>I<warnings...> B<-pedantic> B<-W>I<warnings...> B<-pedantic>
B<-I>I<dir...> B<-L>I<dir...> B<-I>I<dir...> B<-L>I<dir...>
B<-D>I<macro[=defn]> B<-D>I<macro[=defn]>
@ -81,7 +81,8 @@ B<Clang Static Analyzer>
The Clang Static Analyzer is a tool that scans source code to try to find bugs The Clang Static Analyzer is a tool that scans source code to try to find bugs
through code analysis. This tool uses many parts of Clang and is built into the through code analysis. This tool uses many parts of Clang and is built into the
same driver. same driver. Please see L<http://clang-analyzer.llvm.org> for more details
on how to use the static analyzer.
=head1 OPTIONS =head1 OPTIONS
@ -112,10 +113,6 @@ Run all of the above, plus the assembler, generating a target ".o" object file.
If no stage selection option is specified, all stages above are run, and the If no stage selection option is specified, all stages above are run, and the
linker is run to combine the results into an executable or shared library. linker is run to combine the results into an executable or shared library.
=item B<--analyze>
Run the Clang Static Analyzer.
=back =back
@ -263,20 +260,52 @@ may not exist on earlier ones.
=over =over
=item B<-O0> B<-O1> B<-O2> B<-Os> B<-Oz> B<-O3> B<-Ofast> B<-O4> =item B<-O0> B<-O1> B<-O2> B<-O3> B<-Ofast> B<-Os> B<-Oz> B<-O> B<-O4>
Specify which optimization level to use. B<-O0> means "no optimization": this Specify which optimization level to use:
level compiles the fastest and generates the most debuggable code. B<-O2> is a
moderate level of optimization which enables most optimizations. B<-Os> is like =over
B<-O2> with extra optimizations to reduce code size. B<-Oz> is like B<-Os>
(and thus B<-O2>), but reduces code size further. B<-O3> is like B<-O2>, =item B<-O0>
except that it enables optimizations that take longer to perform or that may
generate larger code (in an attempt to make the program run faster). Means "no optimization": this level compiles the fastest and
B<-Ofast> enables all the optimizations from B<-O3> along with other aggressive generates the most debuggable code.
optimizations that may violate strict compliance with language standards. On
supported platforms, B<-O4> enables link-time optimization; object files are =item B<-O1>
stored in the LLVM bitcode file format and whole program optimization is done at
link time. B<-O1> is somewhere between B<-O0> and B<-O2>. Somewhere between B<-O0> and B<-O2>.
=item B<-O2>
Moderate level of optimization which enables most optimizations.
=item B<-O3>
Like B<-O2>, except that it enables optimizations that take longer to perform
or that may generate larger code (in an attempt to make the program run faster).
=item B<-Ofast>
Enables all the optimizations from B<-O3> along with other aggressive
optimizations that may violate strict compliance with language standards.
=item B<-Os>
Like B<-O2> with extra optimizations to reduce code size.
=item B<-Oz>
Like B<-Os> (and thus B<-O2>), but reduces code size further.
=item B<-O>
Equivalent to B<-O2>.
=item B<-O4> and higher
Currently equivalent to B<-O3>
=back
=item B<-g> =item B<-g>

View File

@ -154,20 +154,25 @@ def act_on_decl(declaration, comment, allowed_types):
inner, name = m.groups() inner, name = m.groups()
add_matcher('Type', name, 'Matcher<%s>...' % inner, add_matcher('Type', name, 'Matcher<%s>...' % inner,
comment, is_dyncast=True) comment, is_dyncast=True)
add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner, # FIXME: re-enable once we have implemented casting on the TypeLoc
comment, is_dyncast=True) # hierarchy.
# add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
# comment, is_dyncast=True)
return return
m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\( m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
\s*([^\s,]+\s*), \s*([^\s,]+\s*),
\s*(?:[^\s,]+\s*) \s*(?:[^\s,]+\s*),
\s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
\)\s*;\s*$""", declaration, flags=re.X) \)\s*;\s*$""", declaration, flags=re.X)
if m: if m:
loc = m.group(1) loc, name, n_results, results = m.groups()[0:4]
name = m.group(2) result_types = [r.strip() for r in results.split(',')]
result_types = extract_result_types(comment)
if not result_types: comment_result_types = extract_result_types(comment)
raise Exception('Did not find allowed result types for: %s' % name) if (comment_result_types and
sorted(result_types) != sorted(comment_result_types)):
raise Exception('Inconsistent documentation for: %s' % name)
for result_type in result_types: for result_type in result_types:
add_matcher(result_type, name, 'Matcher<Type>', comment) add_matcher(result_type, name, 'Matcher<Type>', comment)
if loc: if loc:
@ -175,7 +180,31 @@ def act_on_decl(declaration, comment, allowed_types):
comment) comment)
return return
m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)(?:_OVERLOAD)?\( m = re.match(r"""^\s*AST_POLYMORPHIC_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
\s*([^\s,]+)\s*,
\s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
(?:,\s*([^\s,]+)\s*
,\s*([^\s,]+)\s*)?
(?:,\s*([^\s,]+)\s*
,\s*([^\s,]+)\s*)?
(?:,\s*\d+\s*)?
\)\s*{\s*$""", declaration, flags=re.X)
if m:
p, n, name, n_results, results = m.groups()[0:5]
args = m.groups()[5:]
result_types = [r.strip() for r in results.split(',')]
if allowed_types and allowed_types != result_types:
raise Exception('Inconsistent documentation for: %s' % name)
if n not in ['', '2']:
raise Exception('Cannot parse "%s"' % declaration)
args = ', '.join('%s %s' % (args[i], args[i+1])
for i in range(0, len(args), 2) if args[i])
for result_type in result_types:
add_matcher(result_type, name, args, comment)
return
m = re.match(r"""^\s*AST_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
(?:\s*([^\s,]+)\s*,)? (?:\s*([^\s,]+)\s*,)?
\s*([^\s,]+)\s* \s*([^\s,]+)\s*
(?:,\s*([^\s,]+)\s* (?:,\s*([^\s,]+)\s*
@ -185,8 +214,8 @@ def act_on_decl(declaration, comment, allowed_types):
(?:,\s*\d+\s*)? (?:,\s*\d+\s*)?
\)\s*{\s*$""", declaration, flags=re.X) \)\s*{\s*$""", declaration, flags=re.X)
if m: if m:
p, n, result, name = m.groups()[1:5] p, n, result, name = m.groups()[0:4]
args = m.groups()[5:] args = m.groups()[4:]
if not result: if not result:
if not allowed_types: if not allowed_types:
raise Exception('Did not find allowed result types for: %s' % name) raise Exception('Did not find allowed result types for: %s' % name)
@ -201,6 +230,26 @@ def act_on_decl(declaration, comment, allowed_types):
add_matcher(result_type, name, args, comment) add_matcher(result_type, name, args, comment)
return return
# Parse ArgumentAdapting matchers.
m = re.match(
r"""^.*ArgumentAdaptingMatcherFunc<.*>\s*(?:LLVM_ATTRIBUTE_UNUSED\s*)
([a-zA-Z]*)\s*=\s*{};$""",
declaration, flags=re.X)
if m:
name = m.groups()[0]
add_matcher('*', name, 'Matcher<*>', comment)
return
# Parse Variadic operator matchers.
m = re.match(
r"""^.*VariadicOperatorMatcherFunc\s*([a-zA-Z]*)\s*=\s*{.*};$""",
declaration, flags=re.X)
if m:
name = m.groups()[0]
add_matcher('*', name, 'Matcher<*>, ..., Matcher<*>', comment)
return
# Parse free standing matcher functions, like: # Parse free standing matcher functions, like:
# Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) { # Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
m = re.match(r"""^\s*(.*)\s+ m = re.match(r"""^\s*(.*)\s+
@ -270,7 +319,7 @@ def sort_table(matcher_type, matcher_map):
declaration += ' ' + line declaration += ' ' + line
if ((not line.strip()) or if ((not line.strip()) or
line.rstrip()[-1] == ';' or line.rstrip()[-1] == ';' or
line.rstrip()[-1] == '{'): (line.rstrip()[-1] == '{' and line.rstrip()[-3:] != '= {')):
if line.strip() and line.rstrip()[-1] == '{': if line.strip() and line.rstrip()[-1] == '{':
body = True body = True
else: else:

View 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)

View File

@ -15,8 +15,8 @@ NO_INSTALL = 1
# No plugins, optimize startup time. # No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1 TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \ LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter irreader \
linker selectiondag asmparser instrumentation ipo linker selectiondag asmparser instrumentation option
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \ USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \ clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \ clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \

View File

@ -21,6 +21,7 @@
#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JIT.h" #include "llvm/ExecutionEngine/JIT.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h" #include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h" #include "llvm/Support/Path.h"
@ -34,11 +35,11 @@ using namespace clang::driver;
// GetMainExecutable (since some platforms don't support taking the // GetMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement GetMainExecutable // address of main, and some platforms can't implement GetMainExecutable
// without being given the address of a function in the main executable). // without being given the address of a function in the main executable).
llvm::sys::Path GetExecutablePath(const char *Argv0) { std::string GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't // This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however. // allow taking the address of ::main however.
void *MainAddr = (void*) (intptr_t) GetExecutablePath; void *MainAddr = (void*) (intptr_t) GetExecutablePath;
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
} }
static int Execute(llvm::Module *Mod, char * const *envp) { static int Execute(llvm::Module *Mod, char * const *envp) {
@ -67,14 +68,14 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
int main(int argc, const char **argv, char * const *envp) { int main(int argc, const char **argv, char * const *envp) {
void *MainAddr = (void*) (intptr_t) GetExecutablePath; void *MainAddr = (void*) (intptr_t) GetExecutablePath;
llvm::sys::Path Path = GetExecutablePath(argv[0]); std::string Path = GetExecutablePath(argv[0]);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient = TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
Driver TheDriver(Path.str(), llvm::sys::getProcessTriple(), "a.out", Diags); Driver TheDriver(Path, llvm::sys::getProcessTriple(), "a.out", Diags);
TheDriver.setTitle("clang interpreter"); TheDriver.setTitle("clang interpreter");
// FIXME: This is a hack to try to force the driver to do something we can // FIXME: This is a hack to try to force the driver to do something we can
@ -94,7 +95,7 @@ int main(int argc, const char **argv, char * const *envp) {
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
SmallString<256> Msg; SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg); llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true); Jobs.Print(OS, "; ", true);
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
return 1; return 1;
} }
@ -117,7 +118,7 @@ int main(int argc, const char **argv, char * const *envp) {
// Show the invocation, with -v. // Show the invocation, with -v.
if (CI->getHeaderSearchOpts().Verbose) { if (CI->getHeaderSearchOpts().Verbose) {
llvm::errs() << "clang invocation:\n"; llvm::errs() << "clang invocation:\n";
C->PrintJob(llvm::errs(), C->getJobs(), "\n", true); Jobs.Print(llvm::errs(), "\n", true);
llvm::errs() << "\n"; llvm::errs() << "\n";
} }

View File

@ -58,7 +58,7 @@ typedef void * CXCompileCommand;
*/ */
typedef enum { typedef enum {
/* /*
* \brief No error occured * \brief No error occurred
*/ */
CXCompilationDatabase_NoError = 0, CXCompilationDatabase_NoError = 0,
@ -141,6 +141,24 @@ clang_CompileCommand_getNumArgs(CXCompileCommand);
CINDEX_LINKAGE CXString CINDEX_LINKAGE CXString
clang_CompileCommand_getArg(CXCompileCommand, unsigned I); clang_CompileCommand_getArg(CXCompileCommand, unsigned I);
/**
* \brief Get the number of source mappings for the compiler invocation.
*/
CINDEX_LINKAGE unsigned
clang_CompileCommand_getNumMappedSources(CXCompileCommand);
/**
* \brief Get the I'th mapped source path for the compiler invocation.
*/
CINDEX_LINKAGE CXString
clang_CompileCommand_getMappedSourcePath(CXCompileCommand, unsigned I);
/**
* \brief Get the I'th mapped source content for the compiler invocation.
*/
CINDEX_LINKAGE CXString
clang_CompileCommand_getMappedSourceContent(CXCompileCommand, unsigned I);
/** /**
* @} * @}
*/ */

View File

@ -46,7 +46,7 @@ typedef struct {
CINDEX_LINKAGE const char *clang_getCString(CXString string); CINDEX_LINKAGE const char *clang_getCString(CXString string);
/** /**
* \brief Free the given string, * \brief Free the given string.
*/ */
CINDEX_LINKAGE void clang_disposeString(CXString string); CINDEX_LINKAGE void clang_disposeString(CXString string);

View File

@ -16,9 +16,7 @@
#ifndef CLANG_C_INDEX_H #ifndef CLANG_C_INDEX_H
#define CLANG_C_INDEX_H #define CLANG_C_INDEX_H
#include <sys/stat.h>
#include <time.h> #include <time.h>
#include <stdio.h>
#include "clang-c/Platform.h" #include "clang-c/Platform.h"
#include "clang-c/CXString.h" #include "clang-c/CXString.h"
@ -32,7 +30,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/ */
#define CINDEX_VERSION_MAJOR 0 #define CINDEX_VERSION_MAJOR 0
#define CINDEX_VERSION_MINOR 19 #define CINDEX_VERSION_MINOR 20
#define CINDEX_VERSION_ENCODE(major, minor) ( \ #define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \ ((major) * 10000) \
@ -413,6 +411,12 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
*/ */
CINDEX_LINKAGE int clang_Location_isInSystemHeader(CXSourceLocation location); CINDEX_LINKAGE int clang_Location_isInSystemHeader(CXSourceLocation location);
/**
* \brief Returns non-zero if the given source location is in the main file of
* the corresponding translation unit.
*/
CINDEX_LINKAGE int clang_Location_isFromMainFile(CXSourceLocation location);
/** /**
* \brief Retrieve a NULL (invalid) source range. * \brief Retrieve a NULL (invalid) source range.
*/ */
@ -723,7 +727,7 @@ CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
* \brief Retrieve the child diagnostics of a CXDiagnostic. * \brief Retrieve the child diagnostics of a CXDiagnostic.
* *
* This CXDiagnosticSet does not need to be released by * This CXDiagnosticSet does not need to be released by
* clang_diposeDiagnosticSet. * clang_disposeDiagnosticSet.
*/ */
CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D); CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
@ -763,7 +767,7 @@ CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic);
* \brief Options to control the display of diagnostics. * \brief Options to control the display of diagnostics.
* *
* The values in this enum are meant to be combined to customize the * The values in this enum are meant to be combined to customize the
* behavior of \c clang_displayDiagnostic(). * behavior of \c clang_formatDiagnostic().
*/ */
enum CXDiagnosticDisplayOptions { enum CXDiagnosticDisplayOptions {
/** /**
@ -850,7 +854,7 @@ CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic,
* default behavior of the clang compiler. * default behavior of the clang compiler.
* *
* \returns A set of display options suitable for use with \c * \returns A set of display options suitable for use with \c
* clang_displayDiagnostic(). * clang_formatDiagnostic().
*/ */
CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void); CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void);
@ -1942,7 +1946,7 @@ enum CXCursorKind {
*/ */
CXCursor_CompoundStmt = 202, CXCursor_CompoundStmt = 202,
/** \brief A case statment. /** \brief A case statement.
*/ */
CXCursor_CaseStmt = 203, CXCursor_CaseStmt = 203,
@ -2062,7 +2066,11 @@ enum CXCursorKind {
*/ */
CXCursor_DeclStmt = 231, CXCursor_DeclStmt = 231,
CXCursor_LastStmt = CXCursor_DeclStmt, /** \brief OpenMP parallel directive.
*/
CXCursor_OMPParallelDirective = 232,
CXCursor_LastStmt = CXCursor_OMPParallelDirective,
/** /**
* \brief Cursor that represents the translation unit itself. * \brief Cursor that represents the translation unit itself.
@ -2087,7 +2095,8 @@ enum CXCursorKind {
CXCursor_CXXOverrideAttr = 405, CXCursor_CXXOverrideAttr = 405,
CXCursor_AnnotateAttr = 406, CXCursor_AnnotateAttr = 406,
CXCursor_AsmLabelAttr = 407, CXCursor_AsmLabelAttr = 407,
CXCursor_LastAttr = CXCursor_AsmLabelAttr, CXCursor_PackedAttr = 408,
CXCursor_LastAttr = CXCursor_PackedAttr,
/* Preprocessing */ /* Preprocessing */
CXCursor_PreprocessingDirective = 500, CXCursor_PreprocessingDirective = 500,
@ -2666,7 +2675,11 @@ enum CXTypeKind {
CXType_FunctionNoProto = 110, CXType_FunctionNoProto = 110,
CXType_FunctionProto = 111, CXType_FunctionProto = 111,
CXType_ConstantArray = 112, CXType_ConstantArray = 112,
CXType_Vector = 113 CXType_Vector = 113,
CXType_IncompleteArray = 114,
CXType_VariableArray = 115,
CXType_DependentSizedArray = 116,
CXType_MemberPointer = 117
}; };
/** /**
@ -2683,6 +2696,8 @@ enum CXCallingConv {
CXCallingConv_AAPCS_VFP = 7, CXCallingConv_AAPCS_VFP = 7,
CXCallingConv_PnaclCall = 8, CXCallingConv_PnaclCall = 8,
CXCallingConv_IntelOclBicc = 9, CXCallingConv_IntelOclBicc = 9,
CXCallingConv_X86_64Win64 = 10,
CXCallingConv_X86_64SysV = 11,
CXCallingConv_Invalid = 100, CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200 CXCallingConv_Unexposed = 200
@ -2954,6 +2969,13 @@ enum CXTypeLayoutError {
*/ */
CINDEX_LINKAGE long long clang_Type_getAlignOf(CXType T); CINDEX_LINKAGE long long clang_Type_getAlignOf(CXType T);
/**
* \brief Return the class type of an member pointer type.
*
* If a non-member-pointer type is passed in, an invalid type is returned.
*/
CINDEX_LINKAGE CXType clang_Type_getClassType(CXType T);
/** /**
* \brief Return the size of a type in bytes as per C++[expr.sizeof] standard. * \brief Return the size of a type in bytes as per C++[expr.sizeof] standard.
* *
@ -2980,6 +3002,23 @@ CINDEX_LINKAGE long long clang_Type_getSizeOf(CXType T);
*/ */
CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S); CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S);
enum CXRefQualifierKind {
/** \brief No ref-qualifier was provided. */
CXRefQualifier_None = 0,
/** \brief An lvalue ref-qualifier was provided (\c &). */
CXRefQualifier_LValue,
/** \brief An rvalue ref-qualifier was provided (\c &&). */
CXRefQualifier_RValue
};
/**
* \brief Retrieve the ref-qualifier kind of a function or method.
*
* The ref-qualifier is returned for C++ functions or methods. For other types
* or non-C++ declarations, CXRefQualifier_None is returned.
*/
CINDEX_LINKAGE enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T);
/** /**
* \brief Returns non-zero if the cursor specifies a Record member that is a * \brief Returns non-zero if the cursor specifies a Record member that is a
* bitfield. * bitfield.
@ -3413,6 +3452,13 @@ typedef enum {
*/ */
CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C); CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
/**
* \brief Given a cursor that represents an ObjC method or property declaration,
* return non-zero if the declaration was affected by "@optional".
* Returns zero if the cursor is not such a declaration or it is "@required".
*/
CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
/** /**
* \brief Returns non-zero if the given cursor is a variadic function or method. * \brief Returns non-zero if the given cursor is a variadic function or method.
*/ */
@ -4034,6 +4080,12 @@ CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
* @{ * @{
*/ */
/**
* \brief Determine if a C++ member function or member function template is
* pure virtual.
*/
CINDEX_LINKAGE unsigned clang_CXXMethod_isPureVirtual(CXCursor C);
/** /**
* \brief Determine if a C++ member function or member function template is * \brief Determine if a C++ member function or member function template is
* declared 'static'. * declared 'static'.

View File

@ -97,6 +97,8 @@ class MigrationProcess {
FileRemapper Remapper; FileRemapper Remapper;
public: public:
bool HadARCErrors;
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient, MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
StringRef outputDir = StringRef()); StringRef outputDir = StringRef());

View File

@ -57,14 +57,12 @@ class MigrateAction : public WrapperFrontendAction {
/// \brief Migrates to modern ObjC syntax. /// \brief Migrates to modern ObjC syntax.
class ObjCMigrateAction : public WrapperFrontendAction { class ObjCMigrateAction : public WrapperFrontendAction {
std::string MigrateDir; std::string MigrateDir;
bool MigrateLiterals; unsigned ObjCMigAction;
bool MigrateSubscripting;
FileRemapper Remapper; FileRemapper Remapper;
CompilerInstance *CompInst; CompilerInstance *CompInst;
public: public:
ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir, ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
bool migrateLiterals, unsigned migrateAction);
bool migrateSubscripting);
protected: protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile); virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);

View File

@ -53,7 +53,6 @@ class FileRemapper {
StringRef outputDir = StringRef()); StringRef outputDir = StringRef());
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf); void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
void remap(StringRef filePath, StringRef newPath);
void applyMappings(PreprocessorOptions &PPOpts) const; void applyMappings(PreprocessorOptions &PPOpts) const;

View File

@ -168,6 +168,13 @@ class APValue {
MakeUninit(); MakeUninit();
} }
/// \brief Returns whether the object performed allocations.
///
/// If APValues are constructed via placement new, \c needsCleanup()
/// indicates whether the destructor must be called in order to correctly
/// free all allocated memory.
bool needsCleanup() const;
/// \brief Swaps the contents of this and the given APValue. /// \brief Swaps the contents of this and the given APValue.
void swap(APValue &RHS); void swap(APValue &RHS);

View File

@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H #ifndef LLVM_CLANG_AST_ASTCONSUMER_H
#define LLVM_CLANG_AST_ASTCONSUMER_H #define LLVM_CLANG_AST_ASTCONSUMER_H
#include "llvm/ADT/StringRef.h"
namespace clang { namespace clang {
class ASTContext; class ASTContext;
class CXXRecordDecl; class CXXRecordDecl;
@ -70,6 +72,10 @@ class ASTConsumer {
/// can be defined in declspecs). /// can be defined in declspecs).
virtual void HandleTagDeclDefinition(TagDecl *D) {} virtual void HandleTagDeclDefinition(TagDecl *D) {}
/// \brief This callback is invoked the first time each TagDecl is required to
/// be complete.
virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) {}
/// \brief Invoked when a function is implicitly instantiated. /// \brief Invoked when a function is implicitly instantiated.
/// Note that at this point point it does not have a body, its body is /// Note that at this point point it does not have a body, its body is
/// instantiated at the end of the translation unit and passed to /// instantiated at the end of the translation unit and passed to
@ -86,6 +92,21 @@ class ASTConsumer {
/// The default implementation passes it to HandleTopLevelDecl. /// The default implementation passes it to HandleTopLevelDecl.
virtual void HandleImplicitImportDecl(ImportDecl *D); virtual void HandleImplicitImportDecl(ImportDecl *D);
/// \brief Handle a pragma that appends to Linker Options. Currently this
/// only exists to support Microsoft's #pragma comment(linker, "/foo").
virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
/// \brief Handle a pragma that emits a mismatch identifier and value to the
/// object file for the linker to work with. Currently, this only exists to
/// support Microsoft's #pragma detect_mismatch.
virtual void HandleDetectMismatch(llvm::StringRef Name,
llvm::StringRef Value) {}
/// \brief Handle a dependent library created by a pragma in the source.
/// Currently this only exists to support Microsoft's
/// #pragma comment(lib, "/foo").
virtual void HandleDependentLibrary(llvm::StringRef Lib) {}
/// CompleteTentativeDefinition - Callback invoked at the end of a translation /// CompleteTentativeDefinition - Callback invoked at the end of a translation
/// unit to notify the consumer that the given tentative definition should be /// unit to notify the consumer that the given tentative definition should be
/// completed. /// completed.

View File

@ -19,11 +19,9 @@
#include "clang/AST/CanonicalType.h" #include "clang/AST/CanonicalType.h"
#include "clang/AST/CommentCommandTraits.h" #include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "clang/AST/LambdaMangleContext.h"
#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h" #include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RawCommentList.h" #include "clang/AST/RawCommentList.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateName.h" #include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AddressSpaces.h"
@ -47,6 +45,7 @@ namespace llvm {
namespace clang { namespace clang {
class FileManager; class FileManager;
class AtomicExpr;
class ASTRecordLayout; class ASTRecordLayout;
class BlockExpr; class BlockExpr;
class CharUnits; class CharUnits;
@ -55,9 +54,11 @@ namespace clang {
class ExternalASTSource; class ExternalASTSource;
class ASTMutationListener; class ASTMutationListener;
class IdentifierTable; class IdentifierTable;
class MaterializeTemporaryExpr;
class SelectorTable; class SelectorTable;
class TargetInfo; class TargetInfo;
class CXXABI; class CXXABI;
class MangleNumberingContext;
// Decls // Decls
class MangleContext; class MangleContext;
class ObjCIvarDecl; class ObjCIvarDecl;
@ -81,6 +82,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes; mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
mutable llvm::FoldingSet<ComplexType> ComplexTypes; mutable llvm::FoldingSet<ComplexType> ComplexTypes;
mutable llvm::FoldingSet<PointerType> PointerTypes; mutable llvm::FoldingSet<PointerType> PointerTypes;
mutable llvm::FoldingSet<DecayedType> DecayedTypes;
mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes; mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes; mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes; mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
@ -146,7 +148,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable TypeInfoMap MemoizedTypeInfo; mutable TypeInfoMap MemoizedTypeInfo;
/// \brief A cache mapping from CXXRecordDecls to key functions. /// \brief A cache mapping from CXXRecordDecls to key functions.
llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions; llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions;
/// \brief Mapping from ObjCContainers to their ObjCImplementations. /// \brief Mapping from ObjCContainers to their ObjCImplementations.
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls; llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
@ -163,6 +165,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
llvm::DenseMap<const FunctionDecl*, FunctionDecl*> llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
ClassScopeSpecializationPattern; ClassScopeSpecializationPattern;
/// \brief Mapping from materialized temporaries with static storage duration
/// that appear in constant initializers to their evaluated values.
llvm::DenseMap<const MaterializeTemporaryExpr*, APValue>
MaterializedTemporaryValues;
/// \brief Representation of a "canonical" template template parameter that /// \brief Representation of a "canonical" template template parameter that
/// is used in canonical template names. /// is used in canonical template names.
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode { class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
@ -190,6 +197,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The typedef for the __uint128_t type. /// \brief The typedef for the __uint128_t type.
mutable TypedefDecl *UInt128Decl; mutable TypedefDecl *UInt128Decl;
/// \brief The typedef for the __float128 stub type.
mutable TypeDecl *Float128StubDecl;
/// \brief The typedef for the target specific predefined /// \brief The typedef for the target specific predefined
/// __builtin_va_list type. /// __builtin_va_list type.
@ -261,13 +271,30 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// wasting space in the Decl class. /// wasting space in the Decl class.
llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs; llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs;
/// \brief Keeps track of the static data member templates from which /// \brief A mapping from non-redeclarable declarations in modules that were
/// static data members of class template specializations were instantiated. /// merged with other declarations to the canonical declaration that they were
/// merged into.
llvm::DenseMap<Decl*, Decl*> MergedDecls;
public:
/// \brief A type synonym for the TemplateOrInstantiation mapping.
typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *>
TemplateOrSpecializationInfo;
private:
/// \brief A mapping to contain the template or declaration that
/// a variable declaration describes or was instantiated from,
/// respectively.
/// ///
/// This data structure stores the mapping from instantiations of static /// For non-templates, this value will be NULL. For variable
/// data members to the static data member representations within the /// declarations that describe a variable template, this will be a
/// class template from which they were instantiated along with the kind /// pointer to a VarTemplateDecl. For static data members
/// of instantiation or specialization (a TemplateSpecializationKind - 1). /// of class template specializations, this will be the
/// MemberSpecializationInfo referring to the member variable that was
/// instantiated or specialized. Thus, the mapping will keep track of
/// the static data member templates from which static data members of
/// class template specializations were instantiated.
/// ///
/// Given the following example: /// Given the following example:
/// ///
@ -286,8 +313,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// This mapping will contain an entry that maps from the VarDecl for /// This mapping will contain an entry that maps from the VarDecl for
/// X<int>::value to the corresponding VarDecl for X<T>::value (within the /// X<int>::value to the corresponding VarDecl for X<T>::value (within the
/// class template X) and will be marked TSK_ImplicitInstantiation. /// class template X) and will be marked TSK_ImplicitInstantiation.
llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *> llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>
InstantiatedFromStaticDataMember; TemplateOrInstantiation;
/// \brief Keeps track of the declaration from which a UsingDecl was /// \brief Keeps track of the declaration from which a UsingDecl was
/// created during instantiation. /// created during instantiation.
@ -328,12 +355,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector; typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods; llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
/// \brief Mapping from each declaration context to its corresponding lambda /// \brief Mapping from each declaration context to its corresponding
/// mangling context. /// mangling numbering context (used for constructs like lambdas which
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts; /// need to be consistently numbered for the mangler).
llvm::DenseMap<const DeclContext *, MangleNumberingContext *>
MangleNumberingContexts;
llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts; /// \brief Side-table of mangling numbers for declarations which rarely
llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers; /// need them (like static local vars).
llvm::DenseMap<const NamedDecl *, unsigned> MangleNumbers;
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when /// \brief Mapping that stores parameterIndex values for ParmVarDecls when
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex. /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
@ -368,6 +398,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The logical -> physical address space map. /// \brief The logical -> physical address space map.
const LangAS::Map *AddrSpaceMap; const LangAS::Map *AddrSpaceMap;
/// \brief Address space map mangling must be used with language specific
/// address spaces (e.g. OpenCL/CUDA)
bool AddrSpaceMapMangling;
friend class ASTDeclReader; friend class ASTDeclReader;
friend class ASTReader; friend class ASTReader;
friend class ASTWriter; friend class ASTWriter;
@ -419,22 +453,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getParents(ast_type_traits::DynTypedNode::create(Node)); return getParents(ast_type_traits::DynTypedNode::create(Node));
} }
ParentVector getParents(const ast_type_traits::DynTypedNode &Node) { ParentVector getParents(const ast_type_traits::DynTypedNode &Node);
assert(Node.getMemoizationData() &&
"Invariant broken: only nodes that support memoization may be "
"used in the parent map.");
if (!AllParents) {
// We always need to run over the whole translation unit, as
// hasAncestor can escape any subtree.
AllParents.reset(
ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
}
ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
if (I == AllParents->end()) {
return ParentVector();
}
return I->second;
}
const clang::PrintingPolicy &getPrintingPolicy() const { const clang::PrintingPolicy &getPrintingPolicy() const {
return PrintingPolicy; return PrintingPolicy;
@ -451,7 +470,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
return BumpAlloc; return BumpAlloc;
} }
void *Allocate(unsigned Size, unsigned Align = 8) const { void *Allocate(size_t Size, unsigned Align = 8) const {
return BumpAlloc.Allocate(Size, Align); return BumpAlloc.Allocate(Size, Align);
} }
void Deallocate(void *Ptr) const { } void Deallocate(void *Ptr) const { }
@ -470,6 +489,19 @@ class ASTContext : public RefCountedBase<ASTContext> {
const TargetInfo &getTargetInfo() const { return *Target; } const TargetInfo &getTargetInfo() const { return *Target; }
/// getIntTypeForBitwidth -
/// sets integer QualTy according to specified details:
/// bitwidth, signed/unsigned.
/// Returns empty type if there is no appropriate target types.
QualType getIntTypeForBitwidth(unsigned DestWidth,
unsigned Signed) const;
/// getRealTypeForBitwidth -
/// sets floating point QualTy according to specified bitwidth.
/// Returns empty type if there is no appropriate target types.
QualType getRealTypeForBitwidth(unsigned DestWidth) const;
bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const;
const LangOptions& getLangOpts() const { return LangOpts; } const LangOptions& getLangOpts() const { return LangOpts; }
DiagnosticsEngine &getDiagnostics() const; DiagnosticsEngine &getDiagnostics() const;
@ -580,7 +612,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// preprocessor is not available. /// preprocessor is not available.
comments::FullComment *getCommentForDecl(const Decl *D, comments::FullComment *getCommentForDecl(const Decl *D,
const Preprocessor *PP) const; const Preprocessor *PP) const;
/// Return parsed documentation comment attached to a given declaration.
/// Returns NULL if no comment is attached. Does not look at any
/// redeclarations of the declaration.
comments::FullComment *getLocalCommentForDeclUncached(const Decl *D) const;
comments::FullComment *cloneFullComment(comments::FullComment *FC, comments::FullComment *cloneFullComment(comments::FullComment *FC,
const Decl *D) const; const Decl *D) const;
@ -601,9 +638,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief If this variable is an instantiated static data member of a /// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member /// class template specialization, returns the templated static data member
/// from which it was instantiated. /// from which it was instantiated.
// FIXME: Remove ?
MemberSpecializationInfo *getInstantiatedFromStaticDataMember( MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
const VarDecl *Var); const VarDecl *Var);
TemplateOrSpecializationInfo
getTemplateOrSpecializationInfo(const VarDecl *Var);
FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD); FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
void setClassScopeSpecializationPattern(FunctionDecl *FD, void setClassScopeSpecializationPattern(FunctionDecl *FD,
@ -615,6 +656,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
TemplateSpecializationKind TSK, TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation = SourceLocation()); SourceLocation PointOfInstantiation = SourceLocation());
void setTemplateOrSpecializationInfo(VarDecl *Inst,
TemplateOrSpecializationInfo TSI);
/// \brief If the given using decl \p Inst is an instantiation of a /// \brief If the given using decl \p Inst is an instantiation of a
/// (possibly unresolved) using decl from a template instantiation, /// (possibly unresolved) using decl from a template instantiation,
/// return it. /// return it.
@ -632,31 +676,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl); void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
/// \brief Return \c true if \p FD is a zero-length bitfield which follows
/// the non-bitfield \p LastFD.
bool ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const;
/// \brief Return \c true if \p FD is a zero-length bitfield which follows
/// the bitfield \p LastFD.
bool ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const;
/// \brief Return \c true if \p FD is a bitfield which follows the bitfield
/// \p LastFD.
bool BitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const;
/// \brief Return \c true if \p FD is not a bitfield which follows the
/// bitfield \p LastFD.
bool NonBitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const;
/// \brief Return \c true if \p FD is a bitfield which follows the
/// non-bitfield \p LastFD.
bool BitfieldFollowsNonBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const;
// Access to the set of methods overridden by the given C++ method. // Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator; typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
overridden_cxx_method_iterator overridden_cxx_method_iterator
@ -732,7 +751,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
return import_iterator(FirstLocalImport); return import_iterator(FirstLocalImport);
} }
import_iterator local_import_end() const { return import_iterator(); } import_iterator local_import_end() const { return import_iterator(); }
Decl *getPrimaryMergedDecl(Decl *D) {
Decl *Result = MergedDecls.lookup(D);
return Result ? Result : D;
}
void setPrimaryMergedDecl(Decl *D, Decl *Primary) {
MergedDecls[D] = Primary;
}
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
@ -740,7 +767,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
CanQualType VoidTy; CanQualType VoidTy;
CanQualType BoolTy; CanQualType BoolTy;
CanQualType CharTy; CanQualType CharTy;
CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99. CanQualType WCharTy; // [C++ 3.9.1p5].
CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99.
CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions. CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions.
CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99. CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99. CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
@ -809,6 +837,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Retrieve the declaration for the 128-bit unsigned integer type. /// \brief Retrieve the declaration for the 128-bit unsigned integer type.
TypedefDecl *getUInt128Decl() const; TypedefDecl *getUInt128Decl() const;
/// \brief Retrieve the declaration for a 128-bit float stub type.
TypeDecl *getFloat128StubType() const;
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Type Constructors // Type Constructors
@ -884,6 +915,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
return CanQualType::CreateUnsafe(getPointerType((QualType) T)); return CanQualType::CreateUnsafe(getPointerType((QualType) T));
} }
/// \brief Return the uniqued reference to the decayed version of the given
/// type. Can only be called on array and function types which decay to
/// pointer types.
QualType getDecayedType(QualType T) const;
CanQualType getDecayedType(CanQualType T) const {
return CanQualType::CreateUnsafe(getDecayedType((QualType) T));
}
/// \brief Return the uniqued reference to the atomic type for the specified /// \brief Return the uniqued reference to the atomic type for the specified
/// type. /// type.
QualType getAtomicType(QualType T) const; QualType getAtomicType(QualType T) const;
@ -1104,7 +1143,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief C++11 deduced auto type. /// \brief C++11 deduced auto type.
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto, QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
bool IsDependent = false) const; bool IsDependent) const;
/// \brief C++11 deduction pattern for 'auto' type. /// \brief C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const; QualType getAutoDeductType() const;
@ -1130,11 +1169,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// <stdint.h>. /// <stdint.h>.
CanQualType getUIntMaxType() const; CanQualType getUIntMaxType() const;
/// \brief In C++, this returns the unique wchar_t type. In C99, this /// \brief Return the unique wchar_t type available in C++ (and available as
/// returns a type compatible with the type defined in <stddef.h> as defined /// __wchar_t as a Microsoft extension).
/// by the target.
QualType getWCharType() const { return WCharTy; } QualType getWCharType() const { return WCharTy; }
/// \brief Return the type of wide characters. In C++, this returns the
/// unique wchar_t type. In C99, this returns a type compatible with the type
/// defined in <stddef.h> as defined by the target.
QualType getWideCharType() const { return WideCharTy; }
/// \brief Return the type of "signed wchar_t". /// \brief Return the type of "signed wchar_t".
/// ///
/// Used when in C++, as a GCC extension. /// Used when in C++, as a GCC extension.
@ -1607,14 +1650,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \pre \p D must not be a bitfield type, as bitfields do not have a valid /// \pre \p D must not be a bitfield type, as bitfields do not have a valid
/// alignment. /// alignment.
/// ///
/// If \p RefAsPointee, references are treated like their underlying type /// If \p ForAlignof, references are treated like their underlying type
/// (for alignof), else they're treated like pointers (for CodeGen). /// and large arrays don't get any special treatment. If not \p ForAlignof
CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false) const; /// it computes the value expected by CodeGen: references are treated like
/// pointers and large arrays get extra alignment.
CharUnits getDeclAlign(const Decl *D, bool ForAlignof = false) const;
/// \brief Get or compute information about the layout of the specified /// \brief Get or compute information about the layout of the specified
/// record (struct/union/class) \p D, which indicates its size and field /// record (struct/union/class) \p D, which indicates its size and field
/// position information. /// position information.
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const; const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const;
const ASTRecordLayout *BuildMicrosoftASTRecordLayout(const RecordDecl *D) const;
/// \brief Get or compute information about the layout of the specified /// \brief Get or compute information about the layout of the specified
/// Objective-C interface. /// Objective-C interface.
@ -1721,6 +1767,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
getCanonicalType(T2).getTypePtr(); getCanonicalType(T2).getTypePtr();
} }
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
const ObjCMethodDecl *MethodImp);
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
/// \brief Retrieves the "canonical" nested name specifier for a /// \brief Retrieves the "canonical" nested name specifier for a
@ -1749,19 +1798,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
NestedNameSpecifier * NestedNameSpecifier *
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
/// \brief Retrieves the default calling convention to use for /// \brief Retrieves the default calling convention for the current target.
/// C++ instance methods. CallingConv getDefaultCallingConvention(bool isVariadic,
CallingConv getDefaultCXXMethodCallConv(bool isVariadic); bool IsCXXMethod) const;
/// \brief Retrieves the canonical representation of the given
/// calling convention.
CallingConv getCanonicalCallConv(CallingConv CC) const;
/// \brief Determines whether two calling conventions name the same
/// calling convention.
bool isSameCallConv(CallingConv lcc, CallingConv rcc) {
return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc));
}
/// \brief Retrieves the "canonical" template name that refers to a /// \brief Retrieves the "canonical" template name that refers to a
/// given template. /// given template.
@ -1899,6 +1938,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
return (*AddrSpaceMap)[AS - LangAS::Offset]; return (*AddrSpaceMap)[AS - LangAS::Offset];
} }
bool addressSpaceMapManglingFor(unsigned AS) const {
return AddrSpaceMapMangling ||
AS < LangAS::Offset ||
AS >= LangAS::Offset + LangAS::Count;
}
private: private:
// Helper for integer ordering // Helper for integer ordering
unsigned getIntegerRank(const Type *T) const; unsigned getIntegerRank(const Type *T) const;
@ -1925,7 +1970,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool isObjCSelType(QualType T) const { bool isObjCSelType(QualType T) const {
return T == getObjCSelType(); return T == getObjCSelType();
} }
bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
bool ForCompare); bool ForCompare);
@ -2092,12 +2136,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// it is not used. /// it is not used.
bool DeclMustBeEmitted(const Decl *D); bool DeclMustBeEmitted(const Decl *D);
void addUnnamedTag(const TagDecl *Tag); void setManglingNumber(const NamedDecl *ND, unsigned Number);
int getUnnamedTagManglingNumber(const TagDecl *Tag) const; unsigned getManglingNumber(const NamedDecl *ND) const;
/// \brief Retrieve the context for computing mangling numbers in the given
/// DeclContext.
MangleNumberingContext &getManglingNumberContext(const DeclContext *DC);
MangleNumberingContext *createMangleNumberingContext() const;
/// \brief Retrieve the lambda mangling number for a lambda expression.
unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator);
/// \brief Used by ParmVarDecl to store on the side the /// \brief Used by ParmVarDecl to store on the side the
/// index of the parameter when it exceeds the size of the normal bitfield. /// index of the parameter when it exceeds the size of the normal bitfield.
void setParameterIndex(const ParmVarDecl *D, unsigned index); void setParameterIndex(const ParmVarDecl *D, unsigned index);
@ -2105,7 +2152,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Used by ParmVarDecl to retrieve on the side the /// \brief Used by ParmVarDecl to retrieve on the side the
/// index of the parameter when it exceeds the size of the normal bitfield. /// index of the parameter when it exceeds the size of the normal bitfield.
unsigned getParameterIndex(const ParmVarDecl *D) const; unsigned getParameterIndex(const ParmVarDecl *D) const;
/// \brief Get the storage for the constant value of a materialized temporary
/// of static storage duration.
APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
bool MayCreate);
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Statistics // Statistics
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
@ -2197,93 +2249,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
const ObjCImplementationDecl *Impl) const; const ObjCImplementationDecl *Impl) const;
private: private:
/// \brief A set of deallocations that should be performed when the /// \brief A set of deallocations that should be performed when the
/// ASTContext is destroyed. /// ASTContext is destroyed.
SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations; typedef llvm::SmallDenseMap<void(*)(void*), llvm::SmallVector<void*, 16> >
DeallocationMap;
DeallocationMap Deallocations;
// FIXME: This currently contains the set of StoredDeclMaps used // FIXME: This currently contains the set of StoredDeclMaps used
// by DeclContext objects. This probably should not be in ASTContext, // by DeclContext objects. This probably should not be in ASTContext,
// but we include it here so that ASTContext can quickly deallocate them. // but we include it here so that ASTContext can quickly deallocate them.
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM; llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
/// \brief A counter used to uniquely identify "blocks".
mutable unsigned int UniqueBlockByRefTypeID;
friend class DeclContext; friend class DeclContext;
friend class DeclarationNameTable; friend class DeclarationNameTable;
void ReleaseDeclContextMaps(); void ReleaseDeclContextMaps();
/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
/// parents as defined by the \c RecursiveASTVisitor.
///
/// Note that the relationship described here is purely in terms of AST
/// traversal - there are other relationships (for example declaration context)
/// in the AST that are better modeled by special matchers.
///
/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
public:
/// \brief Builds and returns the translation unit's parent map.
///
/// The caller takes ownership of the returned \c ParentMap.
static ParentMap *buildMap(TranslationUnitDecl &TU) {
ParentMapASTVisitor Visitor(new ParentMap);
Visitor.TraverseDecl(&TU);
return Visitor.Parents;
}
private:
typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {
}
bool shouldVisitTemplateInstantiations() const {
return true;
}
bool shouldVisitImplicitCode() const {
return true;
}
// Disables data recursion. We intercept Traverse* methods in the RAV, which
// are not triggered during data recursion.
bool shouldUseDataRecursionFor(clang::Stmt *S) const {
return false;
}
template <typename T>
bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
if (Node == NULL)
return true;
if (ParentStack.size() > 0)
// FIXME: Currently we add the same parent multiple times, for example
// when we visit all subexpressions of template instantiations; this is
// suboptimal, bug benign: the only way to visit those is with
// hasAncestor / hasParent, and those do not create new matches.
// The plan is to enable DynTypedNode to be storable in a map or hash
// map. The main problem there is to implement hash functions /
// comparison operators for all types that DynTypedNode supports that
// do not have pointer identity.
(*Parents)[Node].push_back(ParentStack.back());
ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
bool Result = (this ->* traverse) (Node);
ParentStack.pop_back();
return Result;
}
bool TraverseDecl(Decl *DeclNode) {
return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
}
bool TraverseStmt(Stmt *StmtNode) {
return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
}
ParentMap *Parents;
llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
friend class RecursiveASTVisitor<ParentMapASTVisitor>;
};
llvm::OwningPtr<ParentMap> AllParents; llvm::OwningPtr<ParentMap> AllParents;
}; };

View File

@ -16,7 +16,7 @@ namespace clang {
namespace diag { namespace diag {
enum { enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define ASTSTART #define ASTSTART
#include "clang/Basic/DiagnosticASTKinds.inc" #include "clang/Basic/DiagnosticASTKinds.inc"
#undef DIAG #undef DIAG

View 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

View File

@ -271,6 +271,14 @@ namespace clang {
/// Subclasses can override this function to observe all of the \c From -> /// Subclasses can override this function to observe all of the \c From ->
/// \c To declaration mappings as they are imported. /// \c To declaration mappings as they are imported.
virtual Decl *Imported(Decl *From, Decl *To); virtual Decl *Imported(Decl *From, Decl *To);
/// \brief Called by StructuralEquivalenceContext. If a RecordDecl is
/// being compared to another RecordDecl as part of import, completing the
/// other RecordDecl may trigger importation of the first RecordDecl. This
/// happens especially for anonymous structs. If the original of the second
/// RecordDecl can be found, we can complete it without the need for
/// importation, eliminating this loop.
virtual Decl *GetOriginalDecl(Decl *To) { return NULL; }
/// \brief Determine whether the given types are structurally /// \brief Determine whether the given types are structurally
/// equivalent. /// equivalent.

View 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

View File

@ -27,8 +27,11 @@ namespace clang {
class ObjCContainerDecl; class ObjCContainerDecl;
class ObjCInterfaceDecl; class ObjCInterfaceDecl;
class ObjCPropertyDecl; class ObjCPropertyDecl;
class QualType;
class TagDecl; class TagDecl;
class VarDecl; class VarDecl;
class VarTemplateDecl;
class VarTemplateSpecializationDecl;
/// \brief An abstract interface that should be implemented by listeners /// \brief An abstract interface that should be implemented by listeners
/// that want to be notified when an AST entity gets modified after its /// that want to be notified when an AST entity gets modified after its
@ -51,11 +54,20 @@ class ASTMutationListener {
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D) {} const ClassTemplateSpecializationDecl *D) {}
/// \brief A template specialization (or partial one) was added to the
/// template declaration.
virtual void
AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
const VarTemplateSpecializationDecl *D) {}
/// \brief A template specialization (or partial one) was added to the /// \brief A template specialization (or partial one) was added to the
/// template declaration. /// template declaration.
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {} const FunctionDecl *D) {}
/// \brief A function's return type has been deduced.
virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
/// \brief An implicit member got a definition. /// \brief An implicit member got a definition.
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {} virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
@ -78,6 +90,11 @@ class ASTMutationListener {
const ObjCPropertyDecl *OrigProp, const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt) {} const ObjCCategoryDecl *ClassExt) {}
/// \brief A declaration is marked used which was not previously marked used.
///
/// \param D the declaration marked used
virtual void DeclarationMarkedUsed(const Decl *D) {}
// NOTE: If new methods are added they should also be added to // NOTE: If new methods are added they should also be added to
// MultiplexASTMutationListener. // MultiplexASTMutationListener.
}; };

View File

@ -7,22 +7,132 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// Provides a dynamically typed node container that can be used to store // Provides a dynamic type identifier and a dynamically typed node container
// an AST base node at runtime in the same storage in a type safe way. // that can be used to store an AST base node at runtime in the same storage in
// a type safe way.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H #ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
#include "clang/AST/ASTFwd.h"
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Stmt.h" #include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLoc.h"
#include "clang/Basic/LLVM.h"
#include "llvm/Support/AlignOf.h" #include "llvm/Support/AlignOf.h"
namespace llvm {
class raw_ostream;
}
namespace clang { namespace clang {
struct PrintingPolicy;
namespace ast_type_traits { namespace ast_type_traits {
/// \brief Kind identifier.
///
/// It can be constructed from any node kind and allows for runtime type
/// hierarchy checks.
/// Use getFromNodeKind<T>() to construct them.
class ASTNodeKind {
public:
/// \brief Empty identifier. It matches nothing.
ASTNodeKind() : KindId(NKI_None) {}
/// \brief Construct an identifier for T.
template <class T>
static ASTNodeKind getFromNodeKind() {
return ASTNodeKind(KindToKindId<T>::Id);
}
/// \brief Returns \c true if \c this and \c Other represent the same kind.
bool isSame(ASTNodeKind Other) const;
/// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
bool isBaseOf(ASTNodeKind Other) const;
/// \brief String representation of the kind.
StringRef asStringRef() const;
private:
/// \brief Kind ids.
///
/// Includes all possible base and derived kinds.
enum NodeKindId {
NKI_None,
NKI_CXXCtorInitializer,
NKI_TemplateArgument,
NKI_NestedNameSpecifier,
NKI_NestedNameSpecifierLoc,
NKI_QualType,
NKI_TypeLoc,
NKI_Decl,
#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
#include "clang/AST/DeclNodes.inc"
NKI_Stmt,
#define STMT(DERIVED, BASE) NKI_##DERIVED,
#include "clang/AST/StmtNodes.inc"
NKI_Type,
#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
#include "clang/AST/TypeNodes.def"
NKI_NumberOfKinds
};
/// \brief Use getFromNodeKind<T>() to construct the kind.
ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
/// \brief Returns \c true if \c Base is a base kind of (or same as) \c
/// Derived.
static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
/// \brief Helper meta-function to convert a kind T to its enum value.
///
/// This struct is specialized below for all known kinds.
template <class T> struct KindToKindId {
static const NodeKindId Id = NKI_None;
};
/// \brief Per kind info.
struct KindInfo {
/// \brief The id of the parent kind, or None if it has no parent.
NodeKindId ParentId;
/// \brief Name of the kind.
const char *Name;
};
static const KindInfo AllKindInfo[NKI_NumberOfKinds];
NodeKindId KindId;
};
#define KIND_TO_KIND_ID(Class) \
template <> struct ASTNodeKind::KindToKindId<Class> { \
static const NodeKindId Id = NKI_##Class; \
};
KIND_TO_KIND_ID(CXXCtorInitializer)
KIND_TO_KIND_ID(TemplateArgument)
KIND_TO_KIND_ID(NestedNameSpecifier)
KIND_TO_KIND_ID(NestedNameSpecifierLoc)
KIND_TO_KIND_ID(QualType)
KIND_TO_KIND_ID(TypeLoc)
KIND_TO_KIND_ID(Decl)
KIND_TO_KIND_ID(Stmt)
KIND_TO_KIND_ID(Type)
#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
#include "clang/AST/DeclNodes.inc"
#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
#include "clang/AST/StmtNodes.inc"
#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
#include "clang/AST/TypeNodes.def"
#undef KIND_TO_KIND_ID
/// \brief A dynamically typed AST node container. /// \brief A dynamically typed AST node container.
/// ///
/// Stores an AST node in a type safe way. This allows writing code that /// Stores an AST node in a type safe way. This allows writing code that
@ -32,7 +142,7 @@ namespace ast_type_traits {
/// Use \c create(Node) to create a \c DynTypedNode from an AST node, /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
/// and \c get<T>() to retrieve the node as type T if the types match. /// and \c get<T>() to retrieve the node as type T if the types match.
/// ///
/// See \c NodeTypeTag for which node base types are currently supported; /// See \c ASTNodeKind for which node base types are currently supported;
/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
/// the supported base types. /// the supported base types.
class DynTypedNode { class DynTypedNode {
@ -49,15 +159,15 @@ class DynTypedNode {
/// convertible to \c T. /// convertible to \c T.
/// ///
/// For types that have identity via their pointer in the AST /// For types that have identity via their pointer in the AST
/// (like \c Stmt and \c Decl) the returned pointer points to the /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
/// referenced AST node. /// pointer points to the referenced AST node.
/// For other types (like \c QualType) the value is stored directly /// For other types (like \c QualType) the value is stored directly
/// in the \c DynTypedNode, and the returned pointer points at /// in the \c DynTypedNode, and the returned pointer points at
/// the storage inside DynTypedNode. For those nodes, do not /// the storage inside DynTypedNode. For those nodes, do not
/// use the pointer outside the scope of the DynTypedNode. /// use the pointer outside the scope of the DynTypedNode.
template <typename T> template <typename T>
const T *get() const { const T *get() const {
return BaseConverter<T>::get(Tag, Storage.buffer); return BaseConverter<T>::get(NodeKind, Storage.buffer);
} }
/// \brief Returns a pointer that identifies the stored AST node. /// \brief Returns a pointer that identifies the stored AST node.
@ -67,142 +177,171 @@ class DynTypedNode {
/// method returns NULL. /// method returns NULL.
const void *getMemoizationData() const; const void *getMemoizationData() const;
/// \brief Prints the node to the given output stream.
void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
/// \brief Dumps the node to the given output stream.
void dump(llvm::raw_ostream &OS, SourceManager &SM) const;
/// \brief For nodes which represent textual entities in the source code,
/// return their SourceRange. For all other nodes, return SourceRange().
SourceRange getSourceRange() const;
/// @{
/// \brief Imposes an order on \c DynTypedNode.
///
/// Supports comparison of nodes that support memoization.
/// FIXME: Implement comparsion for other node types (currently
/// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
bool operator<(const DynTypedNode &Other) const {
assert(getMemoizationData() && Other.getMemoizationData());
return getMemoizationData() < Other.getMemoizationData();
}
bool operator==(const DynTypedNode &Other) const {
// Nodes with different types cannot be equal.
if (!NodeKind.isSame(Other.NodeKind))
return false;
// FIXME: Implement for other types.
if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
return *get<QualType>() == *Other.get<QualType>();
}
assert(getMemoizationData() && Other.getMemoizationData());
return getMemoizationData() == Other.getMemoizationData();
}
bool operator!=(const DynTypedNode &Other) const {
return !operator==(Other);
}
/// @}
private: private:
/// \brief Takes care of converting from and to \c T. /// \brief Takes care of converting from and to \c T.
template <typename T, typename EnablerT = void> struct BaseConverter; template <typename T, typename EnablerT = void> struct BaseConverter;
/// \brief Supported base node types. /// \brief Converter that uses dyn_cast<T> from a stored BaseT*.
enum NodeTypeTag { template <typename T, typename BaseT> struct DynCastPtrConverter {
NT_Decl, static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
NT_Stmt, if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
NT_NestedNameSpecifier, return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
NT_NestedNameSpecifierLoc, return NULL;
NT_QualType, }
NT_Type, static DynTypedNode create(const BaseT &Node) {
NT_TypeLoc DynTypedNode Result;
} Tag; Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
new (Result.Storage.buffer) const BaseT * (&Node);
return Result;
}
};
/// \brief Converter that stores T* (by pointer).
template <typename T> struct PtrConverter {
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
return *reinterpret_cast<T *const *>(Storage);
return NULL;
}
static DynTypedNode create(const T &Node) {
DynTypedNode Result;
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
new (Result.Storage.buffer) const T * (&Node);
return Result;
}
};
/// \brief Converter that stores T (by value).
template <typename T> struct ValueConverter {
static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
return reinterpret_cast<const T *>(Storage);
return NULL;
}
static DynTypedNode create(const T &Node) {
DynTypedNode Result;
Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
new (Result.Storage.buffer) T(Node);
return Result;
}
};
ASTNodeKind NodeKind;
/// \brief Stores the data of the node. /// \brief Stores the data of the node.
/// ///
/// Note that we can store \c Decls and \c Stmts by pointer as they are /// Note that we can store \c Decls, \c Stmts, \c Types,
/// guaranteed to be unique pointers pointing to dedicated storage in the /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
/// AST. \c QualTypes on the other hand do not have storage or unique /// guaranteed to be unique pointers pointing to dedicated storage in the AST.
/// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and
/// \c TemplateArguments on the other hand do not have storage or unique
/// pointers and thus need to be stored by value. /// pointers and thus need to be stored by value.
llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier, typedef llvm::AlignedCharArrayUnion<
NestedNameSpecifierLoc, QualType, Type, Decl *, Stmt *, Type *, NestedNameSpecifier *, CXXCtorInitializer *>
TypeLoc> Storage; KindsByPointer;
llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
NestedNameSpecifierLoc, QualType, TypeLoc>
Storage;
}; };
// FIXME: Pull out abstraction for the following. template <typename T>
template<typename T> struct DynTypedNode::BaseConverter<T, struct DynTypedNode::BaseConverter<
typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> { T, typename llvm::enable_if<llvm::is_base_of<
static const T *get(NodeTypeTag Tag, const char Storage[]) { Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {};
if (Tag == NT_Decl)
return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage)); template <typename T>
return NULL; struct DynTypedNode::BaseConverter<
} T, typename llvm::enable_if<llvm::is_base_of<
static DynTypedNode create(const Decl &Node) { Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {};
DynTypedNode Result;
Result.Tag = NT_Decl; template <typename T>
new (Result.Storage.buffer) const Decl*(&Node); struct DynTypedNode::BaseConverter<
return Result; T, typename llvm::enable_if<llvm::is_base_of<
} Type, T> >::type> : public DynCastPtrConverter<T, Type> {};
};
template<typename T> struct DynTypedNode::BaseConverter<T, template <>
typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> { struct DynTypedNode::BaseConverter<
static const T *get(NodeTypeTag Tag, const char Storage[]) { NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
if (Tag == NT_Stmt)
return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage)); template <>
return NULL; struct DynTypedNode::BaseConverter<
} CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
static DynTypedNode create(const Stmt &Node) {
DynTypedNode Result; template <>
Result.Tag = NT_Stmt; struct DynTypedNode::BaseConverter<
new (Result.Storage.buffer) const Stmt*(&Node); TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
return Result;
} template <>
}; struct DynTypedNode::BaseConverter<
template<typename T> struct DynTypedNode::BaseConverter<T, NestedNameSpecifierLoc,
typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> { void> : public ValueConverter<NestedNameSpecifierLoc> {};
static const T *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_Type) template <>
return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage)); struct DynTypedNode::BaseConverter<QualType,
return NULL; void> : public ValueConverter<QualType> {};
}
static DynTypedNode create(const Type &Node) { template <>
DynTypedNode Result; struct DynTypedNode::BaseConverter<
Result.Tag = NT_Type; TypeLoc, void> : public ValueConverter<TypeLoc> {};
new (Result.Storage.buffer) const Type*(&Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_NestedNameSpecifier)
return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
return NULL;
}
static DynTypedNode create(const NestedNameSpecifier &Node) {
DynTypedNode Result;
Result.Tag = NT_NestedNameSpecifier;
new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
const char Storage[]) {
if (Tag == NT_NestedNameSpecifierLoc)
return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
return NULL;
}
static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
DynTypedNode Result;
Result.Tag = NT_NestedNameSpecifierLoc;
new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<QualType, void> {
static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_QualType)
return reinterpret_cast<const QualType*>(Storage);
return NULL;
}
static DynTypedNode create(const QualType &Node) {
DynTypedNode Result;
Result.Tag = NT_QualType;
new (Result.Storage.buffer) QualType(Node);
return Result;
}
};
template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
if (Tag == NT_TypeLoc)
return reinterpret_cast<const TypeLoc*>(Storage);
return NULL;
}
static DynTypedNode create(const TypeLoc &Node) {
DynTypedNode Result;
Result.Tag = NT_TypeLoc;
new (Result.Storage.buffer) TypeLoc(Node);
return Result;
}
};
// The only operation we allow on unsupported types is \c get. // The only operation we allow on unsupported types is \c get.
// This allows to conveniently use \c DynTypedNode when having an arbitrary // This allows to conveniently use \c DynTypedNode when having an arbitrary
// AST node that is not supported, but prevents misuse - a user cannot create // AST node that is not supported, but prevents misuse - a user cannot create
// a DynTypedNode from arbitrary types. // a DynTypedNode from arbitrary types.
template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; } static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
return NULL;
}
}; };
inline const void *DynTypedNode::getMemoizationData() const { inline const void *DynTypedNode::getMemoizationData() const {
switch (Tag) { if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer); return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer); } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
default: return NULL; return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
}; } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) {
return BaseConverter<Type>::get(NodeKind, Storage.buffer);
} else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
}
return NULL;
} }
} // end namespace ast_type_traits } // end namespace ast_type_traits

View File

@ -22,12 +22,21 @@ namespace clang {
/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator. /// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
class ASTUnresolvedSet { class ASTUnresolvedSet {
typedef ASTVector<DeclAccessPair> DeclsTy; struct DeclsTy : ASTVector<DeclAccessPair> {
DeclsTy() {}
DeclsTy(ASTContext &C, unsigned N) : ASTVector<DeclAccessPair>(C, N) {}
bool isLazy() const { return getTag(); }
void setLazy(bool Lazy) { setTag(Lazy); }
};
DeclsTy Decls; DeclsTy Decls;
ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION; ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION; void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
friend class LazyASTUnresolvedSet;
public: public:
ASTUnresolvedSet() {} ASTUnresolvedSet() {}
ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {} ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
@ -48,7 +57,7 @@ class ASTUnresolvedSet {
/// Replaces the given declaration with the new one, once. /// Replaces the given declaration with the new one, once.
/// ///
/// \return true if the set changed /// \return true if the set changed
bool replace(const NamedDecl* Old, NamedDecl *New, AccessSpecifier AS) { bool replace(const NamedDecl *Old, NamedDecl *New, AccessSpecifier AS) {
for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
if (I->getDecl() == Old) { if (I->getDecl() == Old) {
I->set(New, AS); I->set(New, AS);
@ -58,10 +67,7 @@ class ASTUnresolvedSet {
return false; return false;
} }
void erase(unsigned I) { void erase(unsigned I) { Decls[I] = Decls.pop_back_val(); }
Decls[I] = Decls.back();
Decls.pop_back();
}
void clear() { Decls.clear(); } void clear() { Decls.clear(); }
@ -79,7 +85,29 @@ class ASTUnresolvedSet {
DeclAccessPair &operator[](unsigned I) { return Decls[I]; } DeclAccessPair &operator[](unsigned I) { return Decls[I]; }
const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; } const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; }
}; };
/// \brief An UnresolvedSet-like class that might not have been loaded from the
/// external AST source yet.
class LazyASTUnresolvedSet {
mutable ASTUnresolvedSet Impl;
void getFromExternalSource(ASTContext &C) const;
public:
ASTUnresolvedSet &get(ASTContext &C) const {
if (Impl.Decls.isLazy())
getFromExternalSource(C);
return Impl;
}
void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }
void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
assert(Impl.empty() || Impl.Decls.isLazy());
Impl.Decls.setLazy(true);
Impl.addDecl(C, reinterpret_cast<NamedDecl*>(ID << 2), AS);
}
};
} // namespace clang } // namespace clang
#endif #endif

View File

@ -55,16 +55,24 @@ namespace clang {
template<typename T> template<typename T>
class ASTVector { class ASTVector {
T *Begin, *End, *Capacity; private:
T *Begin, *End;
llvm::PointerIntPair<T*, 1, bool> Capacity;
void setEnd(T *P) { this->End = P; } void setEnd(T *P) { this->End = P; }
protected:
// Make a tag bit available to users of this class.
// FIXME: This is a horrible hack.
bool getTag() const { return Capacity.getInt(); }
void setTag(bool B) { Capacity.setInt(B); }
public: public:
// Default ctor - Initialize to empty. // Default ctor - Initialize to empty.
ASTVector() : Begin(NULL), End(NULL), Capacity(NULL) { } ASTVector() : Begin(0), End(0), Capacity(0, false) {}
ASTVector(ASTContext &C, unsigned N) ASTVector(const ASTContext &C, unsigned N)
: Begin(NULL), End(NULL), Capacity(NULL) { : Begin(0), End(0), Capacity(0, false) {
reserve(C, N); reserve(C, N);
} }
@ -155,8 +163,8 @@ class ASTVector {
return const_pointer(Begin); return const_pointer(Begin);
} }
void push_back(const_reference Elt, ASTContext &C) { void push_back(const_reference Elt, const ASTContext &C) {
if (End < Capacity) { if (End < this->capacity_ptr()) {
Retry: Retry:
new (End) T(Elt); new (End) T(Elt);
++End; ++End;
@ -166,19 +174,19 @@ class ASTVector {
goto Retry; goto Retry;
} }
void reserve(ASTContext &C, unsigned N) { void reserve(const ASTContext &C, unsigned N) {
if (unsigned(Capacity-Begin) < N) if (unsigned(this->capacity_ptr()-Begin) < N)
grow(C, N); grow(C, N);
} }
/// capacity - Return the total number of elements in the currently allocated /// capacity - Return the total number of elements in the currently allocated
/// buffer. /// buffer.
size_t capacity() const { return Capacity - Begin; } size_t capacity() const { return this->capacity_ptr() - Begin; }
/// append - Add the specified range to the end of the SmallVector. /// append - Add the specified range to the end of the SmallVector.
/// ///
template<typename in_iter> template<typename in_iter>
void append(ASTContext &C, in_iter in_start, in_iter in_end) { void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
size_type NumInputs = std::distance(in_start, in_end); size_type NumInputs = std::distance(in_start, in_end);
if (NumInputs == 0) if (NumInputs == 0)
@ -197,7 +205,7 @@ class ASTVector {
/// append - Add the specified range to the end of the SmallVector. /// append - Add the specified range to the end of the SmallVector.
/// ///
void append(ASTContext &C, size_type NumInputs, const T &Elt) { void append(const ASTContext &C, size_type NumInputs, const T &Elt) {
// Grow allocated space if needed. // Grow allocated space if needed.
if (NumInputs > size_type(this->capacity_ptr()-this->end())) if (NumInputs > size_type(this->capacity_ptr()-this->end()))
this->grow(C, this->size()+NumInputs); this->grow(C, this->size()+NumInputs);
@ -214,13 +222,13 @@ class ASTVector {
std::uninitialized_copy(I, E, Dest); std::uninitialized_copy(I, E, Dest);
} }
iterator insert(ASTContext &C, iterator I, const T &Elt) { iterator insert(const ASTContext &C, iterator I, const T &Elt) {
if (I == this->end()) { // Important special case for empty vector. if (I == this->end()) { // Important special case for empty vector.
push_back(Elt); push_back(Elt, C);
return this->end()-1; return this->end()-1;
} }
if (this->EndX < this->CapacityX) { if (this->End < this->capacity_ptr()) {
Retry: Retry:
new (this->end()) T(this->back()); new (this->end()) T(this->back());
this->setEnd(this->end()+1); this->setEnd(this->end()+1);
@ -235,7 +243,7 @@ class ASTVector {
goto Retry; goto Retry;
} }
iterator insert(ASTContext &C, iterator I, size_type NumToInsert, iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
const T &Elt) { const T &Elt) {
if (I == this->end()) { // Important special case for empty vector. if (I == this->end()) { // Important special case for empty vector.
append(C, NumToInsert, Elt); append(C, NumToInsert, Elt);
@ -284,7 +292,7 @@ class ASTVector {
} }
template<typename ItTy> template<typename ItTy>
iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) { iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) {
if (I == this->end()) { // Important special case for empty vector. if (I == this->end()) { // Important special case for empty vector.
append(C, From, To); append(C, From, To);
return this->end()-1; return this->end()-1;
@ -335,7 +343,7 @@ class ASTVector {
return I; return I;
} }
void resize(ASTContext &C, unsigned N, const T &NV) { void resize(const ASTContext &C, unsigned N, const T &NV) {
if (N < this->size()) { if (N < this->size()) {
this->destroy_range(this->begin()+N, this->end()); this->destroy_range(this->begin()+N, this->end());
this->setEnd(this->begin()+N); this->setEnd(this->begin()+N);
@ -350,7 +358,7 @@ class ASTVector {
private: private:
/// grow - double the size of the allocated memory, guaranteeing space for at /// grow - double the size of the allocated memory, guaranteeing space for at
/// least one more element or MinSize if specified. /// least one more element or MinSize if specified.
void grow(ASTContext &C, size_type MinSize = 1); void grow(const ASTContext &C, size_type MinSize = 1);
void construct_range(T *S, T *E, const T &Elt) { void construct_range(T *S, T *E, const T &Elt) {
for (; S != E; ++S) for (; S != E; ++S)
@ -365,13 +373,16 @@ class ASTVector {
} }
protected: protected:
iterator capacity_ptr() { return (iterator)this->Capacity; } const_iterator capacity_ptr() const {
return (iterator) Capacity.getPointer();
}
iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
}; };
// Define this out-of-line to dissuade the C++ compiler from inlining it. // Define this out-of-line to dissuade the C++ compiler from inlining it.
template <typename T> template <typename T>
void ASTVector<T>::grow(ASTContext &C, size_t MinSize) { void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
size_t CurCapacity = Capacity-Begin; size_t CurCapacity = this->capacity();
size_t CurSize = size(); size_t CurSize = size();
size_t NewCapacity = 2*CurCapacity; size_t NewCapacity = 2*CurCapacity;
if (NewCapacity < MinSize) if (NewCapacity < MinSize)
@ -394,7 +405,7 @@ void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
// ASTContext never frees any memory. // ASTContext never frees any memory.
Begin = NewElts; Begin = NewElts;
End = NewElts+CurSize; End = NewElts+CurSize;
Capacity = Begin+NewCapacity; Capacity.setPointer(Begin+NewCapacity);
} }
} // end: clang namespace } // end: clang namespace

View File

@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_ATTR_H #define LLVM_CLANG_AST_ATTR_H
#include "clang/AST/AttrIterator.h" #include "clang/AST/AttrIterator.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/Basic/AttrKinds.h" #include "clang/Basic/AttrKinds.h"
#include "clang/Basic/LLVM.h" #include "clang/Basic/LLVM.h"
@ -145,7 +146,7 @@ class MSInheritanceAttr : public InheritableAttr {
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { static bool classof(const Attr *A) {
// Relies on relative order of enum emission with respect to param attrs. // Relies on relative order of enum emission with respect to param attrs.
return (A->getKind() <= attr::LAST_MS_INHERITABLE && return (A->getKind() <= attr::LAST_MS_INHERITANCE &&
A->getKind() > attr::LAST_INHERITABLE_PARAM); A->getKind() > attr::LAST_INHERITABLE_PARAM);
} }
}; };

View File

@ -287,9 +287,9 @@ class OverridingMethods {
// Iterate over the set of overriding virtual methods in a given // Iterate over the set of overriding virtual methods in a given
// subobject. // subobject.
typedef SmallVector<UniqueVirtualMethod, 4>::iterator typedef SmallVectorImpl<UniqueVirtualMethod>::iterator
overriding_iterator; overriding_iterator;
typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator typedef SmallVectorImpl<UniqueVirtualMethod>::const_iterator
overriding_const_iterator; overriding_const_iterator;
// Add a new overriding method for a particular subobject. // Add a new overriding method for a particular subobject.

View File

@ -81,7 +81,7 @@ class CanQual {
operator QualType() const { return Stored; } operator QualType() const { return Stored; }
/// \brief Implicit conversion to bool. /// \brief Implicit conversion to bool.
operator bool() const { return !isNull(); } LLVM_EXPLICIT operator bool() const { return !isNull(); }
bool isNull() const { bool isNull() const {
return Stored.isNull(); return Stored.isNull();

View File

@ -19,21 +19,20 @@
#include "llvm/Support/MathExtras.h" #include "llvm/Support/MathExtras.h"
namespace clang { namespace clang {
/// CharUnits - This is an opaque type for sizes expressed in character units. /// CharUnits - This is an opaque type for sizes expressed in character units.
/// Instances of this type represent a quantity as a multiple of the size /// Instances of this type represent a quantity as a multiple of the size
/// of the standard C type, char, on the target architecture. As an opaque /// of the standard C type, char, on the target architecture. As an opaque
/// type, CharUnits protects you from accidentally combining operations on /// type, CharUnits protects you from accidentally combining operations on
/// quantities in bit units and character units. /// quantities in bit units and character units.
/// ///
/// It should be noted that characters and bytes are distinct concepts. Bytes /// In both C and C++, an object of type 'char', 'signed char', or 'unsigned
/// refer to addressable units of data storage on the target machine, and /// char' occupies exactly one byte, so 'character unit' and 'byte' refer to
/// characters are members of a set of elements used for the organization, /// the same quantity of storage. However, we use the term 'character unit'
/// control, or representation of data. According to C99, bytes are allowed /// rather than 'byte' to avoid an implication that a character unit is
/// to exceed characters in size, although currently, clang only supports /// exactly 8 bits.
/// architectures where the two are the same size. ///
/// /// For portability, never assume that a target character is 8 bits wide. Use
/// For portability, never assume that a target character is 8 bits wide. Use
/// CharUnit values wherever you calculate sizes, offsets, or alignments /// CharUnit values wherever you calculate sizes, offsets, or alignments
/// in character units. /// in character units.
class CharUnits { class CharUnits {

View File

@ -699,7 +699,10 @@ class ParamCommandComment : public BlockCommandComment {
unsigned ParamIndex; unsigned ParamIndex;
public: public:
enum { InvalidParamIndex = ~0U }; enum LLVM_ENUM_INT_TYPE(unsigned) {
InvalidParamIndex = ~0U,
VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U
};
ParamCommandComment(SourceLocation LocBegin, ParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd, SourceLocation LocEnd,
@ -755,14 +758,25 @@ class ParamCommandComment : public BlockCommandComment {
return ParamIndex != InvalidParamIndex; return ParamIndex != InvalidParamIndex;
} }
bool isVarArgParam() const LLVM_READONLY {
return ParamIndex == VarArgParamIndex;
}
void setIsVarArgParam() {
ParamIndex = VarArgParamIndex;
assert(isParamIndexValid());
}
unsigned getParamIndex() const LLVM_READONLY { unsigned getParamIndex() const LLVM_READONLY {
assert(isParamIndexValid()); assert(isParamIndexValid());
assert(!isVarArgParam());
return ParamIndex; return ParamIndex;
} }
void setParamIndex(unsigned Index) { void setParamIndex(unsigned Index) {
ParamIndex = Index; ParamIndex = Index;
assert(isParamIndexValid()); assert(isParamIndexValid());
assert(!isVarArgParam());
} }
}; };
@ -1097,10 +1111,6 @@ class FullComment : public Comment {
return ThisDeclInfo; return ThisDeclInfo;
} }
DeclInfo *getThisDeclInfo() const LLVM_READONLY {
return ThisDeclInfo;
}
ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; } ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
}; };

View File

@ -67,6 +67,9 @@ struct CommandInfo {
/// a template parameter (\\tparam or an alias). /// a template parameter (\\tparam or an alias).
unsigned IsTParamCommand : 1; unsigned IsTParamCommand : 1;
/// True if this command is \\throws or an alias.
unsigned IsThrowsCommand : 1;
/// True if this command is \\deprecated or an alias. /// True if this command is \\deprecated or an alias.
unsigned IsDeprecatedCommand : 1; unsigned IsDeprecatedCommand : 1;
@ -142,6 +145,8 @@ class CommandTraits {
llvm_unreachable("the command should be known"); llvm_unreachable("the command should be known");
} }
const CommandInfo *getTypoCorrectCommandInfo(StringRef Typo) const;
const CommandInfo *getCommandInfo(unsigned CommandID) const; const CommandInfo *getCommandInfo(unsigned CommandID) const;
const CommandInfo *registerUnknownCommand(StringRef CommandName); const CommandInfo *registerUnknownCommand(StringRef CommandName);

View File

@ -15,6 +15,7 @@ class Command<string name> {
bit IsReturnsCommand = 0; bit IsReturnsCommand = 0;
bit IsParamCommand = 0; bit IsParamCommand = 0;
bit IsTParamCommand = 0; bit IsTParamCommand = 0;
bit IsThrowsCommand = 0;
bit IsDeprecatedCommand = 0; bit IsDeprecatedCommand = 0;
bit IsHeaderfileCommand = 0; bit IsHeaderfileCommand = 0;
@ -109,6 +110,10 @@ def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
// HeaderDoc command for template parameter documentation. // HeaderDoc command for template parameter documentation.
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; } def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; }
def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; }
def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; }
def Deprecated : BlockCommand<"deprecated"> { def Deprecated : BlockCommand<"deprecated"> {
let IsEmptyParagraphAllowed = 1; let IsEmptyParagraphAllowed = 1;
let IsDeprecatedCommand = 1; let IsDeprecatedCommand = 1;
@ -200,11 +205,17 @@ def Mainpage : VerbatimLineCommand<"mainpage">;
def Subpage : VerbatimLineCommand<"subpage">; def Subpage : VerbatimLineCommand<"subpage">;
def Ref : VerbatimLineCommand<"ref">; def Ref : VerbatimLineCommand<"ref">;
def Relates : VerbatimLineCommand<"relates">;
def Related : VerbatimLineCommand<"related">;
def RelatesAlso : VerbatimLineCommand<"relatesalso">;
def RelatedAlso : VerbatimLineCommand<"relatedalso">;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// DeclarationVerbatimLineCommand // DeclarationVerbatimLineCommand
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Doxygen commands. // Doxygen commands.
def Def : DeclarationVerbatimLineCommand<"def">;
def Fn : DeclarationVerbatimLineCommand<"fn">; def Fn : DeclarationVerbatimLineCommand<"fn">;
def Namespace : DeclarationVerbatimLineCommand<"namespace">; def Namespace : DeclarationVerbatimLineCommand<"namespace">;
def Overload : DeclarationVerbatimLineCommand<"overload">; def Overload : DeclarationVerbatimLineCommand<"overload">;

View File

@ -16,7 +16,7 @@ namespace clang {
namespace diag { namespace diag {
enum { enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ #define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define COMMENTSTART #define COMMENTSTART
#include "clang/Basic/DiagnosticCommentKinds.inc" #include "clang/Basic/DiagnosticCommentKinds.inc"
#undef DIAG #undef DIAG

View File

@ -61,10 +61,8 @@ class Parser {
void consumeToken() { void consumeToken() {
if (MoreLATokens.empty()) if (MoreLATokens.empty())
L.lex(Tok); L.lex(Tok);
else { else
Tok = MoreLATokens.back(); Tok = MoreLATokens.pop_back_val();
MoreLATokens.pop_back();
}
} }
void putBack(const Token &OldTok) { void putBack(const Token &OldTok) {

View File

@ -58,9 +58,6 @@ class Sema {
/// AST node for the \\brief command and its aliases. /// AST node for the \\brief command and its aliases.
const BlockCommandComment *BriefCommand; const BlockCommandComment *BriefCommand;
/// AST node for the \\returns command and its aliases.
const BlockCommandComment *ReturnsCommand;
/// AST node for the \\headerfile command. /// AST node for the \\headerfile command.
const BlockCommandComment *HeaderfileCommand; const BlockCommandComment *HeaderfileCommand;
@ -211,7 +208,11 @@ class Sema {
bool isFunctionDecl(); bool isFunctionDecl();
bool isAnyFunctionDecl(); bool isAnyFunctionDecl();
/// \returns \c true if declaration that this comment is attached to declares
/// a function pointer.
bool isFunctionPointerVarDecl(); bool isFunctionPointerVarDecl();
bool isFunctionOrMethodVariadic();
bool isObjCMethodDecl(); bool isObjCMethodDecl();
bool isObjCPropertyDecl(); bool isObjCPropertyDecl();
bool isTemplateOrSpecialization(); bool isTemplateOrSpecialization();
@ -220,6 +221,8 @@ class Sema {
bool isUnionDecl(); bool isUnionDecl();
bool isObjCInterfaceDecl(); bool isObjCInterfaceDecl();
bool isObjCProtocolDecl(); bool isObjCProtocolDecl();
bool isClassTemplateDecl();
bool isFunctionTemplateDecl();
ArrayRef<const ParmVarDecl *> getParamVars(); ArrayRef<const ParmVarDecl *> getParamVars();

View File

@ -24,6 +24,7 @@
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
namespace clang { namespace clang {
struct ASTTemplateArgumentListInfo; struct ASTTemplateArgumentListInfo;
@ -43,6 +44,7 @@ class TemplateArgumentList;
class TemplateParameterList; class TemplateParameterList;
class TypeLoc; class TypeLoc;
class UnresolvedSetImpl; class UnresolvedSetImpl;
class VarTemplateDecl;
/// \brief A container of type source information. /// \brief A container of type source information.
/// ///
@ -109,7 +111,6 @@ class NamedDecl : public Decl {
private: private:
NamedDecl *getUnderlyingDeclImpl(); NamedDecl *getUnderlyingDeclImpl();
void verifyLinkage() const;
protected: protected:
NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
@ -142,7 +143,7 @@ class NamedDecl : public Decl {
// FIXME: Deprecated, move clients to getName(). // FIXME: Deprecated, move clients to getName().
std::string getNameAsString() const { return Name.getAsString(); } std::string getNameAsString() const { return Name.getAsString(); }
void printName(raw_ostream &os) const { return Name.printName(os); } void printName(raw_ostream &os) const { os << Name; }
/// getDeclName - Get the actual, stored name of the declaration, /// getDeclName - Get the actual, stored name of the declaration,
/// which may be a special name. /// which may be a special name.
@ -189,10 +190,13 @@ class NamedDecl : public Decl {
using Decl::isModulePrivate; using Decl::isModulePrivate;
using Decl::setModulePrivate; using Decl::setModulePrivate;
/// \brief Determine whether this declaration is hidden from name lookup. /// \brief Determine whether this declaration is hidden from name lookup.
bool isHidden() const { return Hidden; } bool isHidden() const { return Hidden; }
/// \brief Set whether this declaration is hidden from name lookup.
void setHidden(bool Hide) { Hidden = Hide; }
/// \brief Determine whether this declaration is a C++ class member. /// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const { bool isCXXClassMember() const {
const DeclContext *DC = getDeclContext(); const DeclContext *DC = getDeclContext();
@ -212,11 +216,24 @@ class NamedDecl : public Decl {
bool isCXXInstanceMember() const; bool isCXXInstanceMember() const;
/// \brief Determine what kind of linkage this entity has. /// \brief Determine what kind of linkage this entity has.
Linkage getLinkage() const; /// This is not the linkage as defined by the standard or the codegen notion
/// of linkage. It is just an implementation detail that is used to compute
/// those.
Linkage getLinkageInternal() const;
/// \brief Get the linkage from a semantic point of view. Entities in
/// anonymous namespaces are external (in c++98).
Linkage getFormalLinkage() const {
return clang::getFormalLinkage(getLinkageInternal());
}
/// \brief True if this decl has external linkage. /// \brief True if this decl has external linkage.
bool hasExternalLinkage() const { bool hasExternalFormalLinkage() const {
return getLinkage() == ExternalLinkage; return isExternalFormalLinkage(getLinkageInternal());
}
bool isExternallyVisible() const {
return clang::isExternallyVisible(getLinkageInternal());
} }
/// \brief Determines the visibility of this entity. /// \brief Determines the visibility of this entity.
@ -256,6 +273,13 @@ class NamedDecl : public Decl {
return const_cast<NamedDecl*>(this)->getUnderlyingDecl(); return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
} }
NamedDecl *getMostRecentDecl() {
return cast<NamedDecl>(static_cast<Decl *>(this)->getMostRecentDecl());
}
const NamedDecl *getMostRecentDecl() const {
return const_cast<NamedDecl*>(this)->getMostRecentDecl();
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; } static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
}; };
@ -351,6 +375,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
/// \brief Returns true if this is an anonymous namespace declaration. /// \brief Returns true if this is an anonymous namespace declaration.
/// ///
@ -377,7 +402,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
/// \brief Get the original (first) namespace declaration. /// \brief Get the original (first) namespace declaration.
NamespaceDecl *getOriginalNamespace() { NamespaceDecl *getOriginalNamespace() {
if (isFirstDeclaration()) if (isFirstDecl())
return this; return this;
return AnonOrFirstNamespaceAndInline.getPointer(); return AnonOrFirstNamespaceAndInline.getPointer();
@ -385,7 +410,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
/// \brief Get the original (first) namespace declaration. /// \brief Get the original (first) namespace declaration.
const NamespaceDecl *getOriginalNamespace() const { const NamespaceDecl *getOriginalNamespace() const {
if (isFirstDeclaration()) if (isFirstDecl())
return this; return this;
return AnonOrFirstNamespaceAndInline.getPointer(); return AnonOrFirstNamespaceAndInline.getPointer();
@ -394,9 +419,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
/// \brief Return true if this declaration is an original (first) declaration /// \brief Return true if this declaration is an original (first) declaration
/// of the namespace. This is false for non-original (subsequent) namespace /// of the namespace. This is false for non-original (subsequent) namespace
/// declarations and anonymous namespaces. /// declarations and anonymous namespaces.
bool isOriginalNamespace() const { bool isOriginalNamespace() const { return isFirstDecl(); }
return isFirstDeclaration();
}
/// \brief Retrieve the anonymous namespace nested inside this namespace, /// \brief Retrieve the anonymous namespace nested inside this namespace,
/// if any. /// if any.
@ -689,11 +712,21 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// \brief Whether this variable is (C++0x) constexpr. /// \brief Whether this variable is (C++0x) constexpr.
unsigned IsConstexpr : 1; unsigned IsConstexpr : 1;
/// \brief Whether this variable is the implicit variable for a lambda
/// init-capture.
unsigned IsInitCapture : 1;
/// \brief Whether this local extern variable's previous declaration was
/// declared in the same block scope. This controls whether we should merge
/// the type of this declaration with its previous declaration.
unsigned PreviousDeclInSameBlockScope : 1;
}; };
enum { NumVarDeclBits = 12 }; enum { NumVarDeclBits = 14 };
friend class ASTDeclReader; friend class ASTDeclReader;
friend class StmtIteratorBase; friend class StmtIteratorBase;
friend class ASTNodeImporter;
protected: protected:
enum { NumParameterIndexBits = 8 }; enum { NumParameterIndexBits = 8 };
@ -732,15 +765,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
}; };
VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
QualType T, TypeSourceInfo *TInfo, StorageClass SC) TypeSourceInfo *TInfo, StorageClass SC);
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
AllBits = 0;
VarDeclBits.SClass = SC;
// Everything else is implicitly initialized to false.
}
typedef Redeclarable<VarDecl> redeclarable_base; typedef Redeclarable<VarDecl> redeclarable_base;
virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); } virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
@ -757,6 +783,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
static VarDecl *Create(ASTContext &C, DeclContext *DC, static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc, SourceLocation StartLoc, SourceLocation IdLoc,
@ -797,7 +824,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// is a non-static local variable. /// is a non-static local variable.
bool hasLocalStorage() const { bool hasLocalStorage() const {
if (getStorageClass() == SC_None) if (getStorageClass() == SC_None)
return !isFileVarDecl(); // Second check is for C++11 [dcl.stc]p4.
return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
// Return true for: Auto, Register. // Return true for: Auto, Register.
// Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal. // Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.
@ -808,7 +836,10 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// isStaticLocal - Returns true if a variable with function scope is a /// isStaticLocal - Returns true if a variable with function scope is a
/// static local variable. /// static local variable.
bool isStaticLocal() const { bool isStaticLocal() const {
return getStorageClass() == SC_Static && !isFileVarDecl(); return (getStorageClass() == SC_Static ||
// C++11 [dcl.stc]p4
(getStorageClass() == SC_None && getTSCSpec() == TSCS_thread_local))
&& !isFileVarDecl();
} }
/// \brief Returns true if a variable has extern or __private_extern__ /// \brief Returns true if a variable has extern or __private_extern__
@ -818,12 +849,19 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
getStorageClass() == SC_PrivateExtern; getStorageClass() == SC_PrivateExtern;
} }
/// hasGlobalStorage - Returns true for all variables that do not /// \brief Returns true for all variables that do not have local storage.
/// have local storage. This includs all global variables as well ///
/// as static variables declared within a function. /// This includes all global variables as well as static variables declared
/// within a function.
bool hasGlobalStorage() const { return !hasLocalStorage(); } bool hasGlobalStorage() const { return !hasLocalStorage(); }
/// Compute the language linkage. /// \brief Get the storage duration of this variable, per C++ [basic.stc].
StorageDuration getStorageDuration() const {
return hasLocalStorage() ? SD_Automatic :
getTSCSpec() ? SD_Thread : SD_Static;
}
/// \brief Compute the language linkage.
LanguageLinkage getLanguageLinkage() const; LanguageLinkage getLanguageLinkage() const;
/// \brief Determines whether this variable is a variable with /// \brief Determines whether this variable is a variable with
@ -847,7 +885,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
bool isLocalVarDecl() const { bool isLocalVarDecl() const {
if (getKind() != Decl::Var) if (getKind() != Decl::Var)
return false; return false;
if (const DeclContext *DC = getDeclContext()) if (const DeclContext *DC = getLexicalDeclContext())
return DC->getRedeclContext()->isFunctionOrMethod(); return DC->getRedeclContext()->isFunctionOrMethod();
return false; return false;
} }
@ -857,7 +895,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
bool isFunctionOrMethodVarDecl() const { bool isFunctionOrMethodVarDecl() const {
if (getKind() != Decl::Var) if (getKind() != Decl::Var)
return false; return false;
const DeclContext *DC = getDeclContext()->getRedeclContext(); const DeclContext *DC = getLexicalDeclContext()->getRedeclContext();
return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block; return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;
} }
@ -908,10 +946,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
return const_cast<VarDecl*>(this)->getActingDefinition(); return const_cast<VarDecl*>(this)->getActingDefinition();
} }
/// \brief Determine whether this is a tentative definition of a
/// variable in C.
bool isTentativeDefinitionNow() const;
/// \brief Get the real (not just tentative) definition for this declaration. /// \brief Get the real (not just tentative) definition for this declaration.
VarDecl *getDefinition(ASTContext &); VarDecl *getDefinition(ASTContext &);
const VarDecl *getDefinition(ASTContext &C) const { const VarDecl *getDefinition(ASTContext &C) const {
@ -933,10 +967,11 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// isFileVarDecl - Returns true for file scoped variable declaration. /// isFileVarDecl - Returns true for file scoped variable declaration.
bool isFileVarDecl() const { bool isFileVarDecl() const {
if (getKind() != Decl::Var) Kind K = getKind();
if (K == ParmVar || K == ImplicitParam)
return false; return false;
if (getDeclContext()->getRedeclContext()->isFileContext()) if (getLexicalDeclContext()->getRedeclContext()->isFileContext())
return true; return true;
if (isStaticDataMember()) if (isStaticDataMember())
@ -1000,20 +1035,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
void setInit(Expr *I); void setInit(Expr *I);
/// \brief Determine whether this variable is a reference that
/// extends the lifetime of its temporary initializer.
///
/// A reference extends the lifetime of its temporary initializer if
/// it's initializer is an rvalue that would normally go out of scope
/// at the end of the initializer (a full expression). In such cases,
/// the reference itself takes ownership of the temporary, which will
/// be destroyed when the reference goes out of scope. For example:
///
/// \code
/// const int &r = 1.0; // creates a temporary of type 'int'
/// \endcode
bool extendsLifetimeOfTemporary() const;
/// \brief Determine whether this variable's value can be used in a /// \brief Determine whether this variable's value can be used in a
/// constant expression, according to the relevant language standard. /// constant expression, according to the relevant language standard.
/// This only checks properties of the declaration, and does not check /// This only checks properties of the declaration, and does not check
@ -1123,15 +1144,34 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
bool isConstexpr() const { return VarDeclBits.IsConstexpr; } bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; } void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
/// Whether this variable is the implicit variable for a lambda init-capture.
bool isInitCapture() const { return VarDeclBits.IsInitCapture; }
void setInitCapture(bool IC) { VarDeclBits.IsInitCapture = IC; }
/// Whether this local extern variable declaration's previous declaration
/// was declared in the same block scope. Only correct in C++.
bool isPreviousDeclInSameBlockScope() const {
return VarDeclBits.PreviousDeclInSameBlockScope;
}
void setPreviousDeclInSameBlockScope(bool Same) {
VarDeclBits.PreviousDeclInSameBlockScope = Same;
}
/// \brief If this variable is an instantiated static data member of a /// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member /// class template specialization, returns the templated static data member
/// from which it was instantiated. /// from which it was instantiated.
VarDecl *getInstantiatedFromStaticDataMember() const; VarDecl *getInstantiatedFromStaticDataMember() const;
/// \brief If this variable is a static data member, determine what kind of /// \brief If this variable is an instantiation of a variable template or a
/// static data member of a class template, determine what kind of
/// template specialization or instantiation this is. /// template specialization or instantiation this is.
TemplateSpecializationKind getTemplateSpecializationKind() const; TemplateSpecializationKind getTemplateSpecializationKind() const;
/// \brief If this variable is an instantiation of a variable template or a
/// static data member of a class template, determine its point of
/// instantiation.
SourceLocation getPointOfInstantiation() const;
/// \brief If this variable is an instantiation of a static data member of a /// \brief If this variable is an instantiation of a static data member of a
/// class template specialization, retrieves the member specialization /// class template specialization, retrieves the member specialization
/// information. /// information.
@ -1142,6 +1182,26 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
void setTemplateSpecializationKind(TemplateSpecializationKind TSK, void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation = SourceLocation()); SourceLocation PointOfInstantiation = SourceLocation());
/// \brief Specify that this variable is an instantiation of the
/// static data member VD.
void setInstantiationOfStaticDataMember(VarDecl *VD,
TemplateSpecializationKind TSK);
/// \brief Retrieves the variable template that is described by this
/// variable declaration.
///
/// Every variable template is represented as a VarTemplateDecl and a
/// VarDecl. The former contains template properties (such as
/// the template parameter lists) while the latter contains the
/// actual description of the template's
/// contents. VarTemplateDecl::getTemplatedDecl() retrieves the
/// VarDecl that from a VarTemplateDecl, while
/// getDescribedVarTemplate() retrieves the VarTemplateDecl from
/// a VarDecl.
VarTemplateDecl *getDescribedVarTemplate() const;
void setDescribedVarTemplate(VarTemplateDecl *Template);
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
@ -1314,11 +1374,7 @@ class ParmVarDecl : public VarDecl {
ParmVarDeclBits.HasInheritedDefaultArg = I; ParmVarDeclBits.HasInheritedDefaultArg = I;
} }
QualType getOriginalType() const { QualType getOriginalType() const;
if (getTypeSourceInfo())
return getTypeSourceInfo()->getType();
return getType();
}
/// \brief Determine whether this parameter is actually a function /// \brief Determine whether this parameter is actually a function
/// parameter pack. /// parameter pack.
@ -1517,6 +1573,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
static FunctionDecl *Create(ASTContext &C, DeclContext *DC, static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation NLoc, SourceLocation StartLoc, SourceLocation NLoc,
@ -1701,6 +1758,10 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
/// entry point into an executable program. /// entry point into an executable program.
bool isMain() const; bool isMain() const;
/// \brief Determines whether this function is a MSVCRT user defined entry
/// point.
bool isMSVCRTEntryPoint() const;
/// \brief Determines whether this operator new or delete is one /// \brief Determines whether this operator new or delete is one
/// of the reserved global placement operators: /// of the reserved global placement operators:
/// void *operator new(size_t, void *); /// void *operator new(size_t, void *);
@ -1716,6 +1777,28 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
/// This function must be an allocation or deallocation function. /// This function must be an allocation or deallocation function.
bool isReservedGlobalPlacementOperator() const; bool isReservedGlobalPlacementOperator() const;
/// \brief Determines whether this function is one of the replaceable
/// global allocation functions:
/// void *operator new(size_t);
/// void *operator new(size_t, const std::nothrow_t &) noexcept;
/// void *operator new[](size_t);
/// void *operator new[](size_t, const std::nothrow_t &) noexcept;
/// void operator delete(void *) noexcept;
/// void operator delete(void *, std::size_t) noexcept; [C++1y]
/// void operator delete(void *, const std::nothrow_t &) noexcept;
/// void operator delete[](void *) noexcept;
/// void operator delete[](void *, std::size_t) noexcept; [C++1y]
/// void operator delete[](void *, const std::nothrow_t &) noexcept;
/// These functions have special behavior under C++1y [expr.new]:
/// An implementation is allowed to omit a call to a replaceable global
/// allocation function. [...]
bool isReplaceableGlobalAllocationFunction() const;
/// \brief Determine whether this function is a sized global deallocation
/// function in C++1y. If so, find and return the corresponding unsized
/// deallocation function.
FunctionDecl *getCorrespondingUnsizedGlobalDeallocationFunction() const;
/// Compute the language linkage. /// Compute the language linkage.
LanguageLinkage getLanguageLinkage() const; LanguageLinkage getLanguageLinkage() const;
@ -2039,7 +2122,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
/// FieldDecl - An instance of this class is created by Sema::ActOnField to /// FieldDecl - An instance of this class is created by Sema::ActOnField to
/// represent a member of a struct/union/class. /// represent a member of a struct/union/class.
class FieldDecl : public DeclaratorDecl { class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
// FIXME: This can be packed into the bitfields in Decl. // FIXME: This can be packed into the bitfields in Decl.
bool Mutable : 1; bool Mutable : 1;
mutable unsigned CachedFieldIndex : 31; mutable unsigned CachedFieldIndex : 31;
@ -2153,6 +2236,10 @@ class FieldDecl : public DeclaratorDecl {
SourceRange getSourceRange() const LLVM_READONLY; SourceRange getSourceRange() const LLVM_READONLY;
/// Retrieves the canonical declaration of this field.
FieldDecl *getCanonicalDecl() { return getFirstDecl(); }
const FieldDecl *getCanonicalDecl() const { return getFirstDecl(); }
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
@ -2165,7 +2252,7 @@ class FieldDecl : public DeclaratorDecl {
/// that is defined. For example, in "enum X {a,b}", each of a/b are /// that is defined. For example, in "enum X {a,b}", each of a/b are
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a /// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
/// TagType for the X EnumDecl. /// TagType for the X EnumDecl.
class EnumConstantDecl : public ValueDecl { class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> {
Stmt *Init; // an integer constant expression Stmt *Init; // an integer constant expression
llvm::APSInt Val; // The value. llvm::APSInt Val; // The value.
protected: protected:
@ -2191,6 +2278,10 @@ class EnumConstantDecl : public ValueDecl {
SourceRange getSourceRange() const LLVM_READONLY; SourceRange getSourceRange() const LLVM_READONLY;
/// Retrieves the canonical declaration of this enumerator.
EnumConstantDecl *getCanonicalDecl() { return getFirstDecl(); }
const EnumConstantDecl *getCanonicalDecl() const { return getFirstDecl(); }
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == EnumConstant; } static bool classofKind(Kind K) { return K == EnumConstant; }
@ -2289,14 +2380,14 @@ class TypeDecl : public NamedDecl {
/// Base class for declarations which introduce a typedef-name. /// Base class for declarations which introduce a typedef-name.
class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> { class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
virtual void anchor(); virtual void anchor();
/// UnderlyingType - This is the type the typedef is set to. typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
TypeSourceInfo *TInfo; llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
protected: protected:
TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation IdLoc, IdentifierInfo *Id,
TypeSourceInfo *TInfo) TypeSourceInfo *TInfo)
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), TInfo(TInfo) {} : TypeDecl(DK, DC, IdLoc, Id, StartLoc), MaybeModedTInfo(TInfo) {}
typedef Redeclarable<TypedefNameDecl> redeclarable_base; typedef Redeclarable<TypedefNameDecl> redeclarable_base;
virtual TypedefNameDecl *getNextRedeclaration() { virtual TypedefNameDecl *getNextRedeclaration() {
@ -2315,25 +2406,30 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
bool isModed() const { return MaybeModedTInfo.is<ModedTInfo*>(); }
TypeSourceInfo *getTypeSourceInfo() const { TypeSourceInfo *getTypeSourceInfo() const {
return TInfo; return isModed()
? MaybeModedTInfo.get<ModedTInfo*>()->first
: MaybeModedTInfo.get<TypeSourceInfo*>();
}
QualType getUnderlyingType() const {
return isModed()
? MaybeModedTInfo.get<ModedTInfo*>()->second
: MaybeModedTInfo.get<TypeSourceInfo*>()->getType();
}
void setTypeSourceInfo(TypeSourceInfo *newType) {
MaybeModedTInfo = newType;
}
void setModedTypeSourceInfo(TypeSourceInfo *unmodedTSI, QualType modedTy) {
MaybeModedTInfo = new (getASTContext()) ModedTInfo(unmodedTSI, modedTy);
} }
/// Retrieves the canonical declaration of this typedef-name. /// Retrieves the canonical declaration of this typedef-name.
TypedefNameDecl *getCanonicalDecl() { TypedefNameDecl *getCanonicalDecl() { return getFirstDecl(); }
return getFirstDeclaration(); const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); }
}
const TypedefNameDecl *getCanonicalDecl() const {
return getFirstDeclaration();
}
QualType getUnderlyingType() const {
return TInfo->getType();
}
void setTypeSourceInfo(TypeSourceInfo *newType) {
TInfo = newType;
}
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -2436,6 +2532,9 @@ class TagDecl
/// This option is only enabled when modules are enabled. /// This option is only enabled when modules are enabled.
bool MayHaveOutOfDateDef : 1; bool MayHaveOutOfDateDef : 1;
/// Has the full definition of this type been required by a use somewhere in
/// the TU.
bool IsCompleteDefinitionRequired : 1;
private: private:
SourceLocation RBraceLoc; SourceLocation RBraceLoc;
@ -2443,33 +2542,33 @@ class TagDecl
// to be used for the (uncommon) case of out-of-line declarations. // to be used for the (uncommon) case of out-of-line declarations.
typedef QualifierInfo ExtInfo; typedef QualifierInfo ExtInfo;
/// TypedefNameDeclOrQualifier - If the (out-of-line) tag declaration name /// \brief If the (out-of-line) tag declaration name
/// is qualified, it points to the qualifier info (nns and range); /// is qualified, it points to the qualifier info (nns and range);
/// otherwise, if the tag declaration is anonymous and it is part of /// otherwise, if the tag declaration is anonymous and it is part of
/// a typedef or alias, it points to the TypedefNameDecl (used for mangling); /// a typedef or alias, it points to the TypedefNameDecl (used for mangling);
/// otherwise, if the tag declaration is anonymous and it is used as a
/// declaration specifier for variables, it points to the first VarDecl (used
/// for mangling);
/// otherwise, it is a null (TypedefNameDecl) pointer. /// otherwise, it is a null (TypedefNameDecl) pointer.
llvm::PointerUnion<TypedefNameDecl*, ExtInfo*> TypedefNameDeclOrQualifier; llvm::PointerUnion<NamedDecl *, ExtInfo *> NamedDeclOrQualifier;
bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo*>(); } bool hasExtInfo() const { return NamedDeclOrQualifier.is<ExtInfo *>(); }
ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo*>(); } ExtInfo *getExtInfo() { return NamedDeclOrQualifier.get<ExtInfo *>(); }
const ExtInfo *getExtInfo() const { const ExtInfo *getExtInfo() const {
return TypedefNameDeclOrQualifier.get<ExtInfo*>(); return NamedDeclOrQualifier.get<ExtInfo *>();
} }
protected: protected:
TagDecl(Kind DK, TagKind TK, DeclContext *DC, TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
SourceLocation L, IdentifierInfo *Id, IdentifierInfo *Id, TagDecl *PrevDecl, SourceLocation StartL)
TagDecl *PrevDecl, SourceLocation StartL) : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), TagDeclKind(TK),
: TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), IsCompleteDefinition(false), IsBeingDefined(false),
TypedefNameDeclOrQualifier((TypedefNameDecl*) 0) { IsEmbeddedInDeclarator(false), IsFreeStanding(false),
IsCompleteDefinitionRequired(false),
NamedDeclOrQualifier((NamedDecl *)0) {
assert((DK != Enum || TK == TTK_Enum) && assert((DK != Enum || TK == TTK_Enum) &&
"EnumDecl not matched with TTK_Enum"); "EnumDecl not matched with TTK_Enum");
TagDeclKind = TK; setPreviousDecl(PrevDecl);
IsCompleteDefinition = false;
IsBeingDefined = false;
IsEmbeddedInDeclarator = false;
IsFreeStanding = false;
setPreviousDeclaration(PrevDecl);
} }
typedef Redeclarable<TagDecl> redeclarable_base; typedef Redeclarable<TagDecl> redeclarable_base;
@ -2492,6 +2591,7 @@ class TagDecl
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
SourceLocation getRBraceLoc() const { return RBraceLoc; } SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
@ -2522,6 +2622,12 @@ class TagDecl
return IsCompleteDefinition; return IsCompleteDefinition;
} }
/// \brief Return true if this complete decl is
/// required to be complete for some existing use.
bool isCompleteDefinitionRequired() const {
return IsCompleteDefinitionRequired;
}
/// isBeingDefined - Return true if this decl is currently being defined. /// isBeingDefined - Return true if this decl is currently being defined.
bool isBeingDefined() const { bool isBeingDefined() const {
return IsBeingDefined; return IsBeingDefined;
@ -2563,6 +2669,10 @@ class TagDecl
void setCompleteDefinition(bool V) { IsCompleteDefinition = V; } void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
void setCompleteDefinitionRequired(bool V = true) {
IsCompleteDefinitionRequired = V;
}
// FIXME: Return StringRef; // FIXME: Return StringRef;
const char *getKindName() const { const char *getKindName() const {
return TypeWithKeyword::getTagTypeKindName(getTagKind()); return TypeWithKeyword::getTagTypeKindName(getTagKind());
@ -2599,10 +2709,21 @@ class TagDecl
return (getDeclName() || getTypedefNameForAnonDecl()); return (getDeclName() || getTypedefNameForAnonDecl());
} }
TypedefNameDecl *getTypedefNameForAnonDecl() const { bool hasDeclaratorForAnonDecl() const {
return hasExtInfo() ? 0 : return dyn_cast_or_null<DeclaratorDecl>(
TypedefNameDeclOrQualifier.get<TypedefNameDecl*>(); NamedDeclOrQualifier.get<NamedDecl *>());
} }
DeclaratorDecl *getDeclaratorForAnonDecl() const {
return hasExtInfo() ? 0 : dyn_cast_or_null<DeclaratorDecl>(
NamedDeclOrQualifier.get<NamedDecl *>());
}
TypedefNameDecl *getTypedefNameForAnonDecl() const {
return hasExtInfo() ? 0 : dyn_cast_or_null<TypedefNameDecl>(
NamedDeclOrQualifier.get<NamedDecl *>());
}
void setDeclaratorForAnonDecl(DeclaratorDecl *DD) { NamedDeclOrQualifier = DD; }
void setTypedefNameForAnonDecl(TypedefNameDecl *TDD); void setTypedefNameForAnonDecl(TypedefNameDecl *TDD);
@ -2702,21 +2823,22 @@ class EnumDecl : public TagDecl {
return cast<EnumDecl>(TagDecl::getCanonicalDecl()); return cast<EnumDecl>(TagDecl::getCanonicalDecl());
} }
const EnumDecl *getCanonicalDecl() const { const EnumDecl *getCanonicalDecl() const {
return cast<EnumDecl>(TagDecl::getCanonicalDecl()); return const_cast<EnumDecl*>(this)->getCanonicalDecl();
} }
const EnumDecl *getPreviousDecl() const {
return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl());
}
EnumDecl *getPreviousDecl() { EnumDecl *getPreviousDecl() {
return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl()); return cast_or_null<EnumDecl>(
static_cast<TagDecl *>(this)->getPreviousDecl());
}
const EnumDecl *getPreviousDecl() const {
return const_cast<EnumDecl*>(this)->getPreviousDecl();
} }
const EnumDecl *getMostRecentDecl() const {
return cast<EnumDecl>(TagDecl::getMostRecentDecl());
}
EnumDecl *getMostRecentDecl() { EnumDecl *getMostRecentDecl() {
return cast<EnumDecl>(TagDecl::getMostRecentDecl()); return cast<EnumDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl());
}
const EnumDecl *getMostRecentDecl() const {
return const_cast<EnumDecl*>(this)->getMostRecentDecl();
} }
EnumDecl *getDefinition() const { EnumDecl *getDefinition() const {
@ -2912,18 +3034,19 @@ class RecordDecl : public TagDecl {
IdentifierInfo *Id, RecordDecl* PrevDecl = 0); IdentifierInfo *Id, RecordDecl* PrevDecl = 0);
static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
const RecordDecl *getPreviousDecl() const {
return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl());
}
RecordDecl *getPreviousDecl() { RecordDecl *getPreviousDecl() {
return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl()); return cast_or_null<RecordDecl>(
static_cast<TagDecl *>(this)->getPreviousDecl());
}
const RecordDecl *getPreviousDecl() const {
return const_cast<RecordDecl*>(this)->getPreviousDecl();
} }
const RecordDecl *getMostRecentDecl() const {
return cast<RecordDecl>(TagDecl::getMostRecentDecl());
}
RecordDecl *getMostRecentDecl() { RecordDecl *getMostRecentDecl() {
return cast<RecordDecl>(TagDecl::getMostRecentDecl()); return cast<RecordDecl>(static_cast<TagDecl *>(this)->getMostRecentDecl());
}
const RecordDecl *getMostRecentDecl() const {
return const_cast<RecordDecl*>(this)->getMostRecentDecl();
} }
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; } bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
@ -3106,13 +3229,17 @@ class BlockDecl : public Decl, public DeclContext {
Capture *Captures; Capture *Captures;
unsigned NumCaptures; unsigned NumCaptures;
unsigned ManglingNumber;
Decl *ManglingContextDecl;
protected: protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc) BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block), : Decl(Block, DC, CaretLoc), DeclContext(Block),
IsVariadic(false), CapturesCXXThis(false), IsVariadic(false), CapturesCXXThis(false),
BlockMissingReturnType(true), IsConversionFromLambda(false), BlockMissingReturnType(true), IsConversionFromLambda(false),
ParamInfo(0), NumParams(0), Body(0), ParamInfo(0), NumParams(0), Body(0),
SignatureAsWritten(0), Captures(0), NumCaptures(0) {} SignatureAsWritten(0), Captures(0), NumCaptures(0),
ManglingNumber(0), ManglingContextDecl(0) {}
public: public:
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
@ -3182,6 +3309,18 @@ class BlockDecl : public Decl, public DeclContext {
const Capture *end, const Capture *end,
bool capturesCXXThis); bool capturesCXXThis);
unsigned getBlockManglingNumber() const {
return ManglingNumber;
}
Decl *getBlockManglingContextDecl() const {
return ManglingContextDecl;
}
void setBlockMangling(unsigned Number, Decl *Ctx) {
ManglingNumber = Number;
ManglingContextDecl = Ctx;
}
virtual SourceRange getSourceRange() const LLVM_READONLY; virtual SourceRange getSourceRange() const LLVM_READONLY;
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
@ -3354,7 +3493,7 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
} }
template<typename decl_type> template<typename decl_type>
void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) { void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) {
// Note: This routine is implemented here because we need both NamedDecl // Note: This routine is implemented here because we need both NamedDecl
// and Redeclarable to be defined. // and Redeclarable to be defined.
@ -3364,10 +3503,16 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
// Point to previous. Make sure that this is actually the most recent // Point to previous. Make sure that this is actually the most recent
// redeclaration, or we can build invalid chains. If the most recent // redeclaration, or we can build invalid chains. If the most recent
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway. // redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
First = PrevDecl->getFirstDeclaration(); First = PrevDecl->getFirstDecl();
assert(First->RedeclLink.NextIsLatest() && "Expected first"); assert(First->RedeclLink.NextIsLatest() && "Expected first");
decl_type *MostRecent = First->RedeclLink.getNext(); decl_type *MostRecent = First->RedeclLink.getNext();
RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent)); RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent));
// If the declaration was previously visible, a redeclaration of it remains
// visible even if it wouldn't be visible by itself.
static_cast<decl_type*>(this)->IdentifierNamespace |=
MostRecent->getIdentifierNamespace() &
(Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
} else { } else {
// Make this first. // Make this first.
First = static_cast<decl_type*>(this); First = static_cast<decl_type*>(this);

View File

@ -28,7 +28,7 @@ class NamedDecl;
/// A POD class for pairing a NamedDecl* with an access specifier. /// A POD class for pairing a NamedDecl* with an access specifier.
/// Can be put into unions. /// Can be put into unions.
class DeclAccessPair { class DeclAccessPair {
NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
enum { Mask = 0x3 }; enum { Mask = 0x3 };
@ -40,10 +40,10 @@ class DeclAccessPair {
} }
NamedDecl *getDecl() const { NamedDecl *getDecl() const {
return (NamedDecl*) (~Mask & (uintptr_t) Ptr); return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
} }
AccessSpecifier getAccess() const { AccessSpecifier getAccess() const {
return AccessSpecifier(Mask & (uintptr_t) Ptr); return AccessSpecifier(Mask & Ptr);
} }
void setDecl(NamedDecl *D) { void setDecl(NamedDecl *D) {
@ -53,8 +53,7 @@ class DeclAccessPair {
set(getDecl(), AS); set(getDecl(), AS);
} }
void set(NamedDecl *D, AccessSpecifier AS) { void set(NamedDecl *D, AccessSpecifier AS) {
Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) | Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D);
reinterpret_cast<uintptr_t>(D));
} }
operator NamedDecl*() const { return getDecl(); } operator NamedDecl*() const { return getDecl(); }

View File

@ -16,6 +16,7 @@
#include "clang/AST/AttrIterator.h" #include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclarationName.h" #include "clang/AST/DeclarationName.h"
#include "clang/Basic/Linkage.h"
#include "clang/Basic/Specifiers.h" #include "clang/Basic/Specifiers.h"
#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
@ -31,6 +32,7 @@ class DeclarationName;
class DependentDiagnostic; class DependentDiagnostic;
class EnumDecl; class EnumDecl;
class FunctionDecl; class FunctionDecl;
class LinkageComputer;
class LinkageSpecDecl; class LinkageSpecDecl;
class Module; class Module;
class NamedDecl; class NamedDecl;
@ -157,7 +159,12 @@ class Decl {
/// This declaration is a C++ operator declared in a non-class /// This declaration is a C++ operator declared in a non-class
/// context. All such operators are also in IDNS_Ordinary. /// context. All such operators are also in IDNS_Ordinary.
/// C++ lexical operator lookup looks for these. /// C++ lexical operator lookup looks for these.
IDNS_NonMemberOperator = 0x0400 IDNS_NonMemberOperator = 0x0400,
/// This declaration is a function-local extern declaration of a
/// variable or function. This may also be IDNS_Ordinary if it
/// has been declared outside any function.
IDNS_LocalExtern = 0x0800
}; };
/// ObjCDeclQualifier - 'Qualifiers' written next to the return and /// ObjCDeclQualifier - 'Qualifiers' written next to the return and
@ -284,19 +291,16 @@ class Decl {
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 12; unsigned IdentifierNamespace : 12;
/// \brief Whether the \c CachedLinkage field is active. /// \brief If 0, we have not computed the linkage of this declaration.
/// /// Otherwise, it is the linkage + 1.
/// This field is only valid for NamedDecls subclasses. mutable unsigned CacheValidAndLinkage : 3;
mutable unsigned HasCachedLinkage : 1;
/// \brief If \c HasCachedLinkage, the linkage of this declaration.
///
/// This field is only valid for NamedDecls subclasses.
mutable unsigned CachedLinkage : 2;
friend class ASTDeclWriter; friend class ASTDeclWriter;
friend class ASTDeclReader; friend class ASTDeclReader;
friend class ASTReader; friend class ASTReader;
friend class LinkageComputer;
template<typename decl_type> friend class Redeclarable;
private: private:
void CheckAccessDeclContext() const; void CheckAccessDeclContext() const;
@ -309,7 +313,7 @@ class Decl {
HasAttrs(false), Implicit(false), Used(false), Referenced(false), HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), FromASTFile(0), Hidden(0), Access(AS_none), FromASTFile(0), Hidden(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)), IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0) CacheValidAndLinkage(0)
{ {
if (StatisticsEnabled) add(DK); if (StatisticsEnabled) add(DK);
} }
@ -319,7 +323,7 @@ class Decl {
HasAttrs(false), Implicit(false), Used(false), Referenced(false), HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), FromASTFile(0), Hidden(0), Access(AS_none), FromASTFile(0), Hidden(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)), IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0) CacheValidAndLinkage(0)
{ {
if (StatisticsEnabled) add(DK); if (StatisticsEnabled) add(DK);
} }
@ -341,6 +345,18 @@ class Decl {
/// \brief Update a potentially out-of-date declaration. /// \brief Update a potentially out-of-date declaration.
void updateOutOfDate(IdentifierInfo &II) const; void updateOutOfDate(IdentifierInfo &II) const;
Linkage getCachedLinkage() const {
return Linkage(CacheValidAndLinkage - 1);
}
void setCachedLinkage(Linkage L) const {
CacheValidAndLinkage = L + 1;
}
bool hasCachedLinkage() const {
return CacheValidAndLinkage;
}
public: public:
/// \brief Source range that this declaration covers. /// \brief Source range that this declaration covers.
@ -419,7 +435,6 @@ class Decl {
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs()); return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
} }
const AttrVec &getAttrs() const; const AttrVec &getAttrs() const;
void swapAttrs(Decl *D);
void dropAttrs(); void dropAttrs();
void addAttr(Attr *A) { void addAttr(Attr *A) {
@ -490,7 +505,16 @@ class Decl {
/// whether the function is used. /// whether the function is used.
bool isUsed(bool CheckUsedAttr = true) const; bool isUsed(bool CheckUsedAttr = true) const;
void setUsed(bool U = true) { Used = U; } /// \brief Set whether the declaration is used, in the sense of odr-use.
///
/// This should only be used immediately after creating a declaration.
void setIsUsed() { Used = true; }
/// \brief Mark the declaration used, in the sense of odr-use.
///
/// This notifies any mutation listeners in addition to setting a bit
/// indicating the declaration is used.
void markUsed(ASTContext &C);
/// \brief Whether this declaration was referenced. /// \brief Whether this declaration was referenced.
bool isReferenced() const; bool isReferenced() const;
@ -513,13 +537,13 @@ class Decl {
NextInContextAndBits.setInt(Bits); NextInContextAndBits.setInt(Bits);
} }
protected:
/// \brief Whether this declaration was marked as being private to the /// \brief Whether this declaration was marked as being private to the
/// module in which it was defined. /// module in which it was defined.
bool isModulePrivate() const { bool isModulePrivate() const {
return NextInContextAndBits.getInt() & ModulePrivateFlag; return NextInContextAndBits.getInt() & ModulePrivateFlag;
} }
protected:
/// \brief Specify whether this declaration was marked as being private /// \brief Specify whether this declaration was marked as being private
/// to the module in which it was defined. /// to the module in which it was defined.
void setModulePrivate(bool MP = true) { void setModulePrivate(bool MP = true) {
@ -761,7 +785,12 @@ class Decl {
const Decl *getPreviousDecl() const { const Decl *getPreviousDecl() const {
return const_cast<Decl *>(this)->getPreviousDeclImpl(); return const_cast<Decl *>(this)->getPreviousDeclImpl();
} }
/// \brief True if this is the first declaration in its redeclaration chain.
bool isFirstDecl() const {
return getPreviousDecl() == 0;
}
/// \brief Retrieve the most recent declaration that declares the same entity /// \brief Retrieve the most recent declaration that declares the same entity
/// as this declaration (which may be this declaration). /// as this declaration (which may be this declaration).
Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); } Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); }
@ -777,8 +806,10 @@ class Decl {
/// top-level Stmt* of that body. Otherwise this method returns null. /// top-level Stmt* of that body. Otherwise this method returns null.
virtual Stmt* getBody() const { return 0; } virtual Stmt* getBody() const { return 0; }
/// \brief Returns true if this Decl represents a declaration for a body of /// \brief Returns true if this \c Decl represents a declaration for a body of
/// code, such as a function or method definition. /// code, such as a function or method definition.
/// Note that \c hasBody can also return true if any redeclaration of this
/// \c Decl represents a declaration for a body of code.
virtual bool hasBody() const { return getBody() != 0; } virtual bool hasBody() const { return getBody() != 0; }
/// getBodyRBrace - Gets the right brace of the body, if a body exists. /// getBodyRBrace - Gets the right brace of the body, if a body exists.
@ -807,6 +838,32 @@ class Decl {
/// \brief Whether this declaration is a function or function template. /// \brief Whether this declaration is a function or function template.
bool isFunctionOrFunctionTemplate() const; bool isFunctionOrFunctionTemplate() const;
/// \brief Changes the namespace of this declaration to reflect that it's
/// a function-local extern declaration.
///
/// These declarations appear in the lexical context of the extern
/// declaration, but in the semantic context of the enclosing namespace
/// scope.
void setLocalExternDecl() {
assert((IdentifierNamespace == IDNS_Ordinary ||
IdentifierNamespace == IDNS_OrdinaryFriend) &&
"namespace is not ordinary");
Decl *Prev = getPreviousDecl();
IdentifierNamespace &= ~IDNS_Ordinary;
IdentifierNamespace |= IDNS_LocalExtern;
if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)
IdentifierNamespace |= IDNS_Ordinary;
}
/// \brief Determine whether this is a block-scope declaration with linkage.
/// This will either be a local variable declaration declared 'extern', or a
/// local function declaration.
bool isLocalExternDecl() {
return IdentifierNamespace & IDNS_LocalExtern;
}
/// \brief Changes the namespace of this declaration to reflect that it's /// \brief Changes the namespace of this declaration to reflect that it's
/// the object of a friend declaration. /// the object of a friend declaration.
/// ///
@ -814,31 +871,39 @@ class Decl {
/// class, but in the semantic context of the actual entity. This property /// class, but in the semantic context of the actual entity. This property
/// applies only to a specific decl object; other redeclarations of the /// applies only to a specific decl object; other redeclarations of the
/// same entity may not (and probably don't) share this property. /// same entity may not (and probably don't) share this property.
void setObjectOfFriendDecl(bool PreviouslyDeclared) { void setObjectOfFriendDecl(bool PerformFriendInjection = false) {
unsigned OldNS = IdentifierNamespace; unsigned OldNS = IdentifierNamespace;
assert((OldNS & (IDNS_Tag | IDNS_Ordinary | assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
IDNS_TagFriend | IDNS_OrdinaryFriend)) && IDNS_TagFriend | IDNS_OrdinaryFriend |
IDNS_LocalExtern)) &&
"namespace includes neither ordinary nor tag"); "namespace includes neither ordinary nor tag");
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
IDNS_TagFriend | IDNS_OrdinaryFriend)) && IDNS_TagFriend | IDNS_OrdinaryFriend |
IDNS_LocalExtern)) &&
"namespace includes other than ordinary or tag"); "namespace includes other than ordinary or tag");
IdentifierNamespace = 0; Decl *Prev = getPreviousDecl();
IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type);
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend; IdentifierNamespace |= IDNS_TagFriend;
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type; if (PerformFriendInjection ||
(Prev && Prev->getIdentifierNamespace() & IDNS_Tag))
IdentifierNamespace |= IDNS_Tag | IDNS_Type;
} }
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) { if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) {
IdentifierNamespace |= IDNS_OrdinaryFriend; IdentifierNamespace |= IDNS_OrdinaryFriend;
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary; if (PerformFriendInjection ||
(Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
IdentifierNamespace |= IDNS_Ordinary;
} }
} }
enum FriendObjectKind { enum FriendObjectKind {
FOK_None, // not a friend object FOK_None, ///< Not a friend object.
FOK_Declared, // a friend of a previously-declared entity FOK_Declared, ///< A friend of a previously-declared entity.
FOK_Undeclared // a friend of a previously-undeclared entity FOK_Undeclared ///< A friend of a previously-undeclared entity.
}; };
/// \brief Determines whether this declaration is the object of a /// \brief Determines whether this declaration is the object of a
@ -846,11 +911,11 @@ class Decl {
/// ///
/// There is currently no direct way to find the associated FriendDecl. /// There is currently no direct way to find the associated FriendDecl.
FriendObjectKind getFriendObjectKind() const { FriendObjectKind getFriendObjectKind() const {
unsigned mask unsigned mask =
= (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend)); (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
if (!mask) return FOK_None; if (!mask) return FOK_None;
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared
FOK_Declared : FOK_Undeclared); : FOK_Undeclared);
} }
/// Specifies that this declaration is a C++ overloaded non-member. /// Specifies that this declaration is a C++ overloaded non-member.
@ -877,9 +942,6 @@ class Decl {
// Same as dump(), but forces color printing. // Same as dump(), but forces color printing.
LLVM_ATTRIBUTE_USED void dumpColor() const; LLVM_ATTRIBUTE_USED void dumpColor() const;
void dump(raw_ostream &Out) const; void dump(raw_ostream &Out) const;
// Debuggers don't usually respect default arguments.
LLVM_ATTRIBUTE_USED void dumpXML() const;
void dumpXML(raw_ostream &OS) const;
private: private:
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx); void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
@ -974,6 +1036,7 @@ class DeclContext {
mutable Decl *LastDecl; mutable Decl *LastDecl;
friend class ExternalASTSource; friend class ExternalASTSource;
friend class ASTDeclReader;
friend class ASTWriter; friend class ASTWriter;
/// \brief Build up a chain of declarations. /// \brief Build up a chain of declarations.
@ -1096,6 +1159,14 @@ class DeclContext {
/// C++0x scoped enums), and C++ linkage specifications. /// C++0x scoped enums), and C++ linkage specifications.
bool isTransparentContext() const; bool isTransparentContext() const;
/// \brief Determines whether this context or some of its ancestors is a
/// linkage specification context that specifies C linkage.
bool isExternCContext() const;
/// \brief Determines whether this context or some of its ancestors is a
/// linkage specification context that specifies C++ linkage.
bool isExternCXXContext() const;
/// \brief Determine whether this declaration context is equivalent /// \brief Determine whether this declaration context is equivalent
/// to the declaration context DC. /// to the declaration context DC.
bool Equals(const DeclContext *DC) const { bool Equals(const DeclContext *DC) const {
@ -1429,12 +1500,20 @@ class DeclContext {
return const_cast<DeclContext*>(this)->lookup(Name); return const_cast<DeclContext*>(this)->lookup(Name);
} }
/// \brief Find the declarations with the given name that are visible
/// within this context; don't attempt to retrieve anything from an
/// external source.
lookup_result noload_lookup(DeclarationName Name);
/// \brief A simplistic name lookup mechanism that performs name lookup /// \brief A simplistic name lookup mechanism that performs name lookup
/// into this declaration context without consulting the external source. /// into this declaration context without consulting the external source.
/// ///
/// This function should almost never be used, because it subverts the /// This function should almost never be used, because it subverts the
/// usual relationship between a DeclContext and the external source. /// usual relationship between a DeclContext and the external source.
/// See the ASTImporter for the (few, but important) use cases. /// See the ASTImporter for the (few, but important) use cases.
///
/// FIXME: This is very inefficient; replace uses of it with uses of
/// noload_lookup.
void localUncachedLookup(DeclarationName Name, void localUncachedLookup(DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Results); SmallVectorImpl<NamedDecl *> &Results);
@ -1458,10 +1537,16 @@ class DeclContext {
/// of looking up every possible name. /// of looking up every possible name.
class all_lookups_iterator; class all_lookups_iterator;
/// \brief Iterators over all possible lookups within this context.
all_lookups_iterator lookups_begin() const; all_lookups_iterator lookups_begin() const;
all_lookups_iterator lookups_end() const; all_lookups_iterator lookups_end() const;
/// \brief Iterators over all possible lookups within this context that are
/// currently loaded; don't attempt to retrieve anything from an external
/// source.
all_lookups_iterator noload_lookups_begin() const;
all_lookups_iterator noload_lookups_end() const;
/// udir_iterator - Iterates through the using-directives stored /// udir_iterator - Iterates through the using-directives stored
/// within this context. /// within this context.
typedef UsingDirectiveDecl * const * udir_iterator; typedef UsingDirectiveDecl * const * udir_iterator;
@ -1532,6 +1617,8 @@ class DeclContext {
static bool classof(const DeclContext *D) { return true; } static bool classof(const DeclContext *D) { return true; }
LLVM_ATTRIBUTE_USED void dumpDeclContext() const; LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
LLVM_ATTRIBUTE_USED void dumpLookups() const;
LLVM_ATTRIBUTE_USED void dumpLookups(llvm::raw_ostream &OS) const;
private: private:
void reconcileExternalVisibleStorage(); void reconcileExternalVisibleStorage();
@ -1548,6 +1635,8 @@ class DeclContext {
friend class DependentDiagnostic; friend class DependentDiagnostic;
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
template<decl_iterator (DeclContext::*Begin)() const,
decl_iterator (DeclContext::*End)() const>
void buildLookupImpl(DeclContext *DCtx); void buildLookupImpl(DeclContext *DCtx);
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
bool Rediscoverable); bool Rediscoverable);

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h" #include "clang/AST/DeclarationName.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include <algorithm> #include <algorithm>
@ -26,23 +27,29 @@ namespace clang {
class DependentDiagnostic; class DependentDiagnostic;
/// StoredDeclsList - This is an array of decls optimized a common case of only /// \brief An array of decls optimized for the common case of only containing
/// containing one entry. /// one entry.
struct StoredDeclsList { struct StoredDeclsList {
/// DeclsTy - When in vector form, this is what the Data pointer points to. /// \brief When in vector form, this is what the Data pointer points to.
typedef SmallVector<NamedDecl *, 4> DeclsTy; typedef SmallVector<NamedDecl *, 4> DeclsTy;
/// \brief A collection of declarations, with a flag to indicate if we have
/// further external declarations.
typedef llvm::PointerIntPair<DeclsTy *, 1, bool> DeclsAndHasExternalTy;
/// \brief The stored data, which will be either a pointer to a NamedDecl, /// \brief The stored data, which will be either a pointer to a NamedDecl,
/// or a pointer to a vector. /// or a pointer to a vector with a flag to indicate if there are further
llvm::PointerUnion<NamedDecl *, DeclsTy *> Data; /// external declarations.
llvm::PointerUnion<NamedDecl*, DeclsAndHasExternalTy> Data;
public: public:
StoredDeclsList() {} StoredDeclsList() {}
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) { StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
if (DeclsTy *RHSVec = RHS.getAsVector()) if (DeclsTy *RHSVec = RHS.getAsVector())
Data = new DeclsTy(*RHSVec); Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec),
RHS.hasExternalDecls());
} }
~StoredDeclsList() { ~StoredDeclsList() {
@ -56,7 +63,7 @@ struct StoredDeclsList {
delete Vector; delete Vector;
Data = RHS.Data; Data = RHS.Data;
if (DeclsTy *RHSVec = RHS.getAsVector()) if (DeclsTy *RHSVec = RHS.getAsVector())
Data = new DeclsTy(*RHSVec); Data = DeclsAndHasExternalTy(new DeclsTy(*RHSVec), hasExternalDecls());
return *this; return *this;
} }
@ -66,8 +73,27 @@ struct StoredDeclsList {
return Data.dyn_cast<NamedDecl *>(); return Data.dyn_cast<NamedDecl *>();
} }
DeclsAndHasExternalTy getAsVectorAndHasExternal() const {
return Data.dyn_cast<DeclsAndHasExternalTy>();
}
DeclsTy *getAsVector() const { DeclsTy *getAsVector() const {
return Data.dyn_cast<DeclsTy *>(); return getAsVectorAndHasExternal().getPointer();
}
bool hasExternalDecls() const {
return getAsVectorAndHasExternal().getInt();
}
void setHasExternalDecls() {
if (DeclsTy *Vec = getAsVector())
Data = DeclsAndHasExternalTy(Vec, true);
else {
DeclsTy *VT = new DeclsTy();
if (NamedDecl *OldD = getAsDecl())
VT->push_back(OldD);
Data = DeclsAndHasExternalTy(VT, true);
}
} }
void setOnlyValue(NamedDecl *ND) { void setOnlyValue(NamedDecl *ND) {
@ -110,6 +136,8 @@ struct StoredDeclsList {
Vec.erase(std::remove_if(Vec.begin(), Vec.end(), Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
std::mem_fun(&Decl::isFromASTFile)), std::mem_fun(&Decl::isFromASTFile)),
Vec.end()); Vec.end());
// Don't have any external decls any more.
Data = DeclsAndHasExternalTy(&Vec, false);
} }
} }
@ -165,12 +193,14 @@ struct StoredDeclsList {
/// not a redeclaration to merge it into the appropriate place in our list. /// not a redeclaration to merge it into the appropriate place in our list.
/// ///
void AddSubsequentDecl(NamedDecl *D) { void AddSubsequentDecl(NamedDecl *D) {
assert(!isNull() && "don't AddSubsequentDecl when we have no decls");
// If this is the second decl added to the list, convert this to vector // If this is the second decl added to the list, convert this to vector
// form. // form.
if (NamedDecl *OldD = getAsDecl()) { if (NamedDecl *OldD = getAsDecl()) {
DeclsTy *VT = new DeclsTy(); DeclsTy *VT = new DeclsTy();
VT->push_back(OldD); VT->push_back(OldD);
Data = VT; Data = DeclsAndHasExternalTy(VT, false);
} }
DeclsTy &Vec = *getAsVector(); DeclsTy &Vec = *getAsVector();

View File

@ -220,7 +220,7 @@ class CXXRecordDecl::friend_iterator {
}; };
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const { inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
return friend_iterator(data().FirstFriend); return friend_iterator(getFirstFriend());
} }
inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const { inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
@ -228,7 +228,7 @@ inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {
} }
inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
assert(FD->NextFriend == 0 && "friend already has next friend?"); assert(!FD->NextFriend && "friend already has next friend?");
FD->NextFriend = data().FirstFriend; FD->NextFriend = data().FirstFriend;
data().FirstFriend = FD; data().FirstFriend = FD;
} }

View File

@ -37,6 +37,8 @@ class DeclContext::all_lookups_iterator {
StoredDeclsMap::iterator End) StoredDeclsMap::iterator End)
: It(It), End(End) {} : It(It), End(End) {}
DeclarationName getLookupName() const { return It->first; }
reference operator*() const { return It->second.getLookupResult(); } reference operator*() const { return It->second.getLookupResult(); }
pointer operator->() const { return It->second.getLookupResult(); } pointer operator->() const { return It->second.getLookupResult(); }
@ -66,7 +68,7 @@ class DeclContext::all_lookups_iterator {
} }
}; };
DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { inline DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
if (Primary->hasExternalVisibleStorage()) if (Primary->hasExternalVisibleStorage())
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
@ -75,7 +77,7 @@ DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
return all_lookups_iterator(); return all_lookups_iterator();
} }
DeclContext::all_lookups_iterator DeclContext::lookups_end() const { inline DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
if (Primary->hasExternalVisibleStorage()) if (Primary->hasExternalVisibleStorage())
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
@ -84,6 +86,22 @@ DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
return all_lookups_iterator(); return all_lookups_iterator();
} }
inline
DeclContext::all_lookups_iterator DeclContext::noload_lookups_begin() const {
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
if (StoredDeclsMap *Map = Primary->getLookupPtr())
return all_lookups_iterator(Map->begin(), Map->end());
return all_lookups_iterator();
}
inline
DeclContext::all_lookups_iterator DeclContext::noload_lookups_end() const {
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
if (StoredDeclsMap *Map = Primary->getLookupPtr())
return all_lookups_iterator(Map->end(), Map->end());
return all_lookups_iterator();
}
} // end namespace clang } // end namespace clang
#endif #endif

View File

@ -452,7 +452,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
} }
/// \brief Determine whether this method has a body. /// \brief Determine whether this method has a body.
virtual bool hasBody() const { return Body; } virtual bool hasBody() const { return Body.isValid(); }
/// \brief Retrieve the body of this method, if it has one. /// \brief Retrieve the body of this method, if it has one.
virtual Stmt *getBody() const; virtual Stmt *getBody() const;
@ -463,7 +463,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
void setBody(Stmt *B) { Body = B; } void setBody(Stmt *B) { Body = B; }
/// \brief Returns whether this specific method is a definition. /// \brief Returns whether this specific method is a definition.
bool isThisDeclarationADefinition() const { return Body; } bool isThisDeclarationADefinition() const { return hasBody(); }
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -553,6 +553,9 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap; typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
ProtocolPropertyMap;
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder; typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
/// This routine collects list of properties to be implemented in the class. /// This routine collects list of properties to be implemented in the class.
@ -1133,6 +1136,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
return lookupInstanceVariable(IVarName, ClassDeclared); return lookupInstanceVariable(IVarName, ClassDeclared);
} }
ObjCProtocolDecl *lookupNestedProtocol(IdentifierInfo *Name);
// Lookup a method. First, we search locally. If a method isn't // Lookup a method. First, we search locally. If a method isn't
// found, we search referenced protocols and class categories. // found, we search referenced protocols and class categories.
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance, ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
@ -1196,14 +1201,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
/// Retrieves the canonical declaration of this Objective-C class. /// Retrieves the canonical declaration of this Objective-C class.
ObjCInterfaceDecl *getCanonicalDecl() { ObjCInterfaceDecl *getCanonicalDecl() { return getFirstDecl(); }
return getFirstDeclaration(); const ObjCInterfaceDecl *getCanonicalDecl() const { return getFirstDecl(); }
}
const ObjCInterfaceDecl *getCanonicalDecl() const {
return getFirstDeclaration();
}
// Low-level accessor // Low-level accessor
const Type *getTypeForDecl() const { return TypeForDecl; } const Type *getTypeForDecl() const { return TypeForDecl; }
@ -1244,10 +1246,12 @@ class ObjCIvarDecl : public FieldDecl {
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc, ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized) bool synthesized,
bool backingIvarReferencedInAccessor)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit), /*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {} NextIvar(0), DeclAccess(ac), Synthesized(synthesized),
BackingIvarReferencedInAccessor(backingIvarReferencedInAccessor) {}
public: public:
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
@ -1255,7 +1259,8 @@ class ObjCIvarDecl : public FieldDecl {
IdentifierInfo *Id, QualType T, IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW = NULL, AccessControl ac, Expr *BW = NULL,
bool synthesized=false); bool synthesized=false,
bool backingIvarReferencedInAccessor=false);
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID); static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@ -1277,6 +1282,13 @@ class ObjCIvarDecl : public FieldDecl {
return DeclAccess == None ? Protected : AccessControl(DeclAccess); return DeclAccess == None ? Protected : AccessControl(DeclAccess);
} }
void setBackingIvarReferencedInAccessor(bool val) {
BackingIvarReferencedInAccessor = val;
}
bool getBackingIvarReferencedInAccessor() const {
return BackingIvarReferencedInAccessor;
}
void setSynthesize(bool synth) { Synthesized = synth; } void setSynthesize(bool synth) { Synthesized = synth; }
bool getSynthesize() const { return Synthesized; } bool getSynthesize() const { return Synthesized; }
@ -1291,6 +1303,7 @@ class ObjCIvarDecl : public FieldDecl {
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
unsigned DeclAccess : 3; unsigned DeclAccess : 3;
unsigned Synthesized : 1; unsigned Synthesized : 1;
unsigned BackingIvarReferencedInAccessor : 1;
}; };
@ -1502,17 +1515,17 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
/// Retrieves the canonical declaration of this Objective-C protocol. /// Retrieves the canonical declaration of this Objective-C protocol.
ObjCProtocolDecl *getCanonicalDecl() { ObjCProtocolDecl *getCanonicalDecl() { return getFirstDecl(); }
return getFirstDeclaration(); const ObjCProtocolDecl *getCanonicalDecl() const { return getFirstDecl(); }
}
const ObjCProtocolDecl *getCanonicalDecl() const {
return getFirstDeclaration();
}
virtual void collectPropertiesToImplement(PropertyMap &PM, virtual void collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const; PropertyDeclOrder &PO) const;
void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
ProtocolPropertyMap &PM) const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCProtocol; } static bool classofKind(Kind K) { return K == ObjCProtocol; }

View File

@ -1,4 +1,4 @@
//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===// //===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// ///
/// \file /// \file
/// \brief This file defines OpenMP nodes. /// \brief This file defines OpenMP nodes for declarative directives.
/// ///
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -20,8 +20,6 @@
namespace clang { namespace clang {
class DeclRefExpr;
/// \brief This represents '#pragma omp threadprivate ...' directive. /// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate: /// For example, in the following, both 'a' and 'A::b' are threadprivate:
/// ///
@ -43,29 +41,29 @@ class OMPThreadPrivateDecl : public Decl {
OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) : OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
Decl(DK, DC, L), NumVars(0) { } Decl(DK, DC, L), NumVars(0) { }
ArrayRef<const DeclRefExpr *> getVars() const { ArrayRef<const Expr *> getVars() const {
return ArrayRef<const DeclRefExpr *>( return ArrayRef<const Expr *>(
reinterpret_cast<const DeclRefExpr * const *>(this + 1), reinterpret_cast<const Expr * const *>(this + 1),
NumVars); NumVars);
} }
llvm::MutableArrayRef<DeclRefExpr *> getVars() { llvm::MutableArrayRef<Expr *> getVars() {
return llvm::MutableArrayRef<DeclRefExpr *>( return llvm::MutableArrayRef<Expr *>(
reinterpret_cast<DeclRefExpr **>(this + 1), reinterpret_cast<Expr **>(this + 1),
NumVars); NumVars);
} }
void setVars(ArrayRef<DeclRefExpr *> VL); void setVars(ArrayRef<Expr *> VL);
public: public:
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC, static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, SourceLocation L,
ArrayRef<DeclRefExpr *> VL); ArrayRef<Expr *> VL);
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
unsigned ID, unsigned N); unsigned ID, unsigned N);
typedef llvm::MutableArrayRef<DeclRefExpr *>::iterator varlist_iterator; typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator;
typedef ArrayRef<const DeclRefExpr *>::iterator varlist_const_iterator; typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
unsigned varlist_size() const { return NumVars; } unsigned varlist_size() const { return NumVars; }
bool varlist_empty() const { return NumVars == 0; } bool varlist_empty() const { return NumVars == 0; }

View File

@ -34,6 +34,8 @@ class TemplateTypeParmDecl;
class NonTypeTemplateParmDecl; class NonTypeTemplateParmDecl;
class TemplateTemplateParmDecl; class TemplateTemplateParmDecl;
class TypeAliasTemplateDecl; class TypeAliasTemplateDecl;
class VarTemplateDecl;
class VarTemplatePartialSpecializationDecl;
/// \brief Stores a template parameter of any kind. /// \brief Stores a template parameter of any kind.
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*, typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
@ -629,9 +631,9 @@ class RedeclarableTemplateDecl : public TemplateDecl,
template <class decl_type> friend class RedeclarableTemplate; template <class decl_type> friend class RedeclarableTemplate;
/// \brief Retrieves the canonical declaration of this template. /// \brief Retrieves the canonical declaration of this template.
RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDeclaration(); } RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDecl(); }
const RedeclarableTemplateDecl *getCanonicalDecl() const { const RedeclarableTemplateDecl *getCanonicalDecl() const {
return getFirstDeclaration(); return getFirstDecl();
} }
/// \brief Determines whether this template was a specialization of a /// \brief Determines whether this template was a specialization of a
@ -713,6 +715,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
using redeclarable_base::redecls_end; using redeclarable_base::redecls_end;
using redeclarable_base::getPreviousDecl; using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl; using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -743,7 +746,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
/// \brief Data that is common to all of the declarations of a given /// \brief Data that is common to all of the declarations of a given
/// function template. /// function template.
struct Common : CommonBase { struct Common : CommonBase {
Common() : InjectedArgs(0) { } Common() : InjectedArgs(), LazySpecializations() { }
/// \brief The function template specializations for this function /// \brief The function template specializations for this function
/// template, including explicit specializations and instantiations. /// template, including explicit specializations and instantiations.
@ -757,6 +760,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
/// template, and is allocated lazily, since most function templates do not /// template, and is allocated lazily, since most function templates do not
/// require the use of this information. /// require the use of this information.
TemplateArgument *InjectedArgs; TemplateArgument *InjectedArgs;
/// \brief If non-null, points to an array of specializations known only
/// by their external declaration IDs.
///
/// The first value in the array is the number of of specializations
/// that follow.
uint32_t *LazySpecializations;
}; };
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
@ -771,12 +781,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
friend class FunctionDecl; friend class FunctionDecl;
/// \brief Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
/// \brief Retrieve the set of function template specializations of this /// \brief Retrieve the set of function template specializations of this
/// function template. /// function template.
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> & llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
getSpecializations() const { getSpecializations() const;
return getCommonPtr()->Specializations;
}
/// \brief Add a specialization of this function template. /// \brief Add a specialization of this function template.
/// ///
@ -815,14 +826,14 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
/// NULL if no such declaration exists. /// NULL if no such declaration exists.
FunctionTemplateDecl *getPreviousDecl() { FunctionTemplateDecl *getPreviousDecl() {
return cast_or_null<FunctionTemplateDecl>( return cast_or_null<FunctionTemplateDecl>(
RedeclarableTemplateDecl::getPreviousDecl()); static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
} }
/// \brief Retrieve the previous declaration of this function template, or /// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists. /// NULL if no such declaration exists.
const FunctionTemplateDecl *getPreviousDecl() const { const FunctionTemplateDecl *getPreviousDecl() const {
return cast_or_null<FunctionTemplateDecl>( return cast_or_null<FunctionTemplateDecl>(
RedeclarableTemplateDecl::getPreviousDecl()); static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl());
} }
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() { FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
@ -847,7 +858,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
/// arguments for a function template, the notion is convenient when /// arguments for a function template, the notion is convenient when
/// we need to perform substitutions inside the definition of a function /// we need to perform substitutions inside the definition of a function
/// template. /// template.
std::pair<const TemplateArgument *, unsigned> getInjectedTemplateArgs(); ArrayRef<TemplateArgument> getInjectedTemplateArgs();
/// \brief Create a function template node. /// \brief Create a function template node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
@ -1377,7 +1388,7 @@ class ClassTemplateSpecializationDecl
/// \brief The template argument list deduced for the class template /// \brief The template argument list deduced for the class template
/// partial specialization itself. /// partial specialization itself.
TemplateArgumentList *TemplateArgs; const TemplateArgumentList *TemplateArgs;
}; };
/// \brief The template that this specialization specializes /// \brief The template that this specialization specializes
@ -1402,7 +1413,7 @@ class ClassTemplateSpecializationDecl
ExplicitSpecializationInfo *ExplicitInfo; ExplicitSpecializationInfo *ExplicitInfo;
/// \brief The template arguments used to describe this specialization. /// \brief The template arguments used to describe this specialization.
TemplateArgumentList *TemplateArgs; const TemplateArgumentList *TemplateArgs;
/// \brief The point where this template was instantiated (if any) /// \brief The point where this template was instantiated (if any)
SourceLocation PointOfInstantiation; SourceLocation PointOfInstantiation;
@ -1438,9 +1449,9 @@ class ClassTemplateSpecializationDecl
bool Qualified) const; bool Qualified) const;
ClassTemplateSpecializationDecl *getMostRecentDecl() { ClassTemplateSpecializationDecl *getMostRecentDecl() {
CXXRecordDecl *Recent CXXRecordDecl *Recent = static_cast<CXXRecordDecl *>(
= cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDecl()); this)->getMostRecentDecl();
if (!isa<ClassTemplateSpecializationDecl>(Recent)) { while (!isa<ClassTemplateSpecializationDecl>(Recent)) {
// FIXME: Does injected class name need to be in the redeclarations chain? // FIXME: Does injected class name need to be in the redeclarations chain?
assert(Recent->isInjectedClassName() && Recent->getPreviousDecl()); assert(Recent->isInjectedClassName() && Recent->getPreviousDecl());
Recent = Recent->getPreviousDecl(); Recent = Recent->getPreviousDecl();
@ -1553,7 +1564,7 @@ class ClassTemplateSpecializationDecl
/// instantiation of the given class template partial specialization whose /// instantiation of the given class template partial specialization whose
/// template arguments have been deduced. /// template arguments have been deduced.
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
TemplateArgumentList *TemplateArgs) { const TemplateArgumentList *TemplateArgs) {
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() && assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
"Already set to a class template partial specialization!"); "Already set to a class template partial specialization!");
SpecializedPartialSpecialization *PS SpecializedPartialSpecialization *PS
@ -1639,13 +1650,7 @@ class ClassTemplatePartialSpecializationDecl
/// \brief The source info for the template arguments as written. /// \brief The source info for the template arguments as written.
/// FIXME: redundant with TypeAsWritten? /// FIXME: redundant with TypeAsWritten?
TemplateArgumentLoc *ArgsAsWritten; const ASTTemplateArgumentListInfo *ArgsAsWritten;
unsigned NumArgsAsWritten;
/// \brief Sequence number indicating when this class template partial
/// specialization was added to the set of partial specializations for
/// its owning class template.
unsigned SequenceNumber;
/// \brief The class template partial specialization from which this /// \brief The class template partial specialization from which this
/// class template partial specialization was instantiated. /// class template partial specialization was instantiated.
@ -1663,16 +1668,12 @@ class ClassTemplatePartialSpecializationDecl
ClassTemplateDecl *SpecializedTemplate, ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args, const TemplateArgument *Args,
unsigned NumArgs, unsigned NumArgs,
TemplateArgumentLoc *ArgInfos, const ASTTemplateArgumentListInfo *ArgsAsWritten,
unsigned NumArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl);
ClassTemplatePartialSpecializationDecl *PrevDecl,
unsigned SequenceNumber);
ClassTemplatePartialSpecializationDecl() ClassTemplatePartialSpecializationDecl()
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization), : ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
TemplateParams(0), ArgsAsWritten(0), TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) { }
NumArgsAsWritten(0), SequenceNumber(0),
InstantiatedFromMember(0, false) { }
public: public:
static ClassTemplatePartialSpecializationDecl * static ClassTemplatePartialSpecializationDecl *
@ -1684,15 +1685,15 @@ class ClassTemplatePartialSpecializationDecl
unsigned NumArgs, unsigned NumArgs,
const TemplateArgumentListInfo &ArgInfos, const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType, QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl, ClassTemplatePartialSpecializationDecl *PrevDecl);
unsigned SequenceNumber);
static ClassTemplatePartialSpecializationDecl * static ClassTemplatePartialSpecializationDecl *
CreateDeserialized(ASTContext &C, unsigned ID); CreateDeserialized(ASTContext &C, unsigned ID);
ClassTemplatePartialSpecializationDecl *getMostRecentDecl() { ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
return cast<ClassTemplatePartialSpecializationDecl>( return cast<ClassTemplatePartialSpecializationDecl>(
ClassTemplateSpecializationDecl::getMostRecentDecl()); static_cast<ClassTemplateSpecializationDecl *>(
this)->getMostRecentDecl());
} }
/// Get the list of template parameters /// Get the list of template parameters
@ -1701,19 +1702,10 @@ class ClassTemplatePartialSpecializationDecl
} }
/// Get the template arguments as written. /// Get the template arguments as written.
TemplateArgumentLoc *getTemplateArgsAsWritten() const { const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten; return ArgsAsWritten;
} }
/// Get the number of template arguments as written.
unsigned getNumTemplateArgsAsWritten() const {
return NumArgsAsWritten;
}
/// \brief Get the sequence number for this class template partial
/// specialization.
unsigned getSequenceNumber() const { return SequenceNumber; }
/// \brief Retrieve the member class template partial specialization from /// \brief Retrieve the member class template partial specialization from
/// which this particular class template partial specialization was /// which this particular class template partial specialization was
/// instantiated. /// instantiated.
@ -1735,15 +1727,15 @@ class ClassTemplatePartialSpecializationDecl
/// \c Outer<float>::Inner<U*>, this function would return /// \c Outer<float>::Inner<U*>, this function would return
/// \c Outer<T>::Inner<U*>. /// \c Outer<T>::Inner<U*>.
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() { ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
ClassTemplatePartialSpecializationDecl *First ClassTemplatePartialSpecializationDecl *First =
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getPointer(); return First->InstantiatedFromMember.getPointer();
} }
void setInstantiatedFromMember( void setInstantiatedFromMember(
ClassTemplatePartialSpecializationDecl *PartialSpec) { ClassTemplatePartialSpecializationDecl *PartialSpec) {
ClassTemplatePartialSpecializationDecl *First ClassTemplatePartialSpecializationDecl *First =
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
First->InstantiatedFromMember.setPointer(PartialSpec); First->InstantiatedFromMember.setPointer(PartialSpec);
} }
@ -1764,15 +1756,15 @@ class ClassTemplatePartialSpecializationDecl
/// struct X<int>::Inner<T*> { /* ... */ }; /// struct X<int>::Inner<T*> { /* ... */ };
/// \endcode /// \endcode
bool isMemberSpecialization() { bool isMemberSpecialization() {
ClassTemplatePartialSpecializationDecl *First ClassTemplatePartialSpecializationDecl *First =
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt(); return First->InstantiatedFromMember.getInt();
} }
/// \brief Note that this member template is a specialization. /// \brief Note that this member template is a specialization.
void setMemberSpecialization() { void setMemberSpecialization() {
ClassTemplatePartialSpecializationDecl *First ClassTemplatePartialSpecializationDecl *First =
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
assert(First->InstantiatedFromMember.getPointer() && assert(First->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations"); "Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true); return First->InstantiatedFromMember.setInt(true);
@ -1821,7 +1813,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
QualType InjectedClassNameType; QualType InjectedClassNameType;
/// \brief If non-null, points to an array of specializations (including /// \brief If non-null, points to an array of specializations (including
/// partial specializations) known ownly by their external declaration IDs. /// partial specializations) known only by their external declaration IDs.
/// ///
/// The first value in the array is the number of of specializations/ /// The first value in the array is the number of of specializations/
/// partial specializations that follow. /// partial specializations that follow.
@ -1900,14 +1892,23 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
/// NULL if no such declaration exists. /// NULL if no such declaration exists.
ClassTemplateDecl *getPreviousDecl() { ClassTemplateDecl *getPreviousDecl() {
return cast_or_null<ClassTemplateDecl>( return cast_or_null<ClassTemplateDecl>(
RedeclarableTemplateDecl::getPreviousDecl()); static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
} }
/// \brief Retrieve the previous declaration of this class template, or /// \brief Retrieve the previous declaration of this class template, or
/// NULL if no such declaration exists. /// NULL if no such declaration exists.
const ClassTemplateDecl *getPreviousDecl() const { const ClassTemplateDecl *getPreviousDecl() const {
return cast_or_null<ClassTemplateDecl>( return cast_or_null<ClassTemplateDecl>(
RedeclarableTemplateDecl::getPreviousDecl()); static_cast<const RedeclarableTemplateDecl *>(
this)->getPreviousDecl());
}
ClassTemplateDecl *getMostRecentDecl() {
return cast<ClassTemplateDecl>(
static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl());
}
const ClassTemplateDecl *getMostRecentDecl() const {
return const_cast<ClassTemplateDecl*>(this)->getMostRecentDecl();
} }
ClassTemplateDecl *getInstantiatedFromMemberTemplate() { ClassTemplateDecl *getInstantiatedFromMemberTemplate() {
@ -1926,11 +1927,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D, void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D,
void *InsertPos); void *InsertPos);
/// \brief Return the next partial specialization sequence number.
unsigned getNextPartialSpecSequenceNumber() {
return getPartialSpecializations().size();
}
/// \brief Retrieve the partial specializations as an ordered list. /// \brief Retrieve the partial specializations as an ordered list.
void getPartialSpecializations( void getPartialSpecializations(
SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS); SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
@ -2139,14 +2135,15 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
/// NULL if no such declaration exists. /// NULL if no such declaration exists.
TypeAliasTemplateDecl *getPreviousDecl() { TypeAliasTemplateDecl *getPreviousDecl() {
return cast_or_null<TypeAliasTemplateDecl>( return cast_or_null<TypeAliasTemplateDecl>(
RedeclarableTemplateDecl::getPreviousDecl()); static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
} }
/// \brief Retrieve the previous declaration of this function template, or /// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists. /// NULL if no such declaration exists.
const TypeAliasTemplateDecl *getPreviousDecl() const { const TypeAliasTemplateDecl *getPreviousDecl() const {
return cast_or_null<TypeAliasTemplateDecl>( return cast_or_null<TypeAliasTemplateDecl>(
RedeclarableTemplateDecl::getPreviousDecl()); static_cast<const RedeclarableTemplateDecl *>(
this)->getPreviousDecl());
} }
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() { TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
@ -2239,6 +2236,578 @@ class ClassScopeFunctionSpecializationDecl : public Decl {
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
: Function(FTD) { } : Function(FTD) { }
/// \brief Represents a variable template specialization, which refers to
/// a variable template with a given set of template arguments.
///
/// Variable template specializations represent both explicit
/// specializations of variable templates, as in the example below, and
/// implicit instantiations of variable templates.
///
/// \code
/// template<typename T> constexpr T pi = T(3.1415926535897932385);
///
/// template<>
/// constexpr float pi<float>; // variable template specialization pi<float>
/// \endcode
class VarTemplateSpecializationDecl : public VarDecl,
public llvm::FoldingSetNode {
/// \brief Structure that stores information about a variable template
/// specialization that was instantiated from a variable template partial
/// specialization.
struct SpecializedPartialSpecialization {
/// \brief The variable template partial specialization from which this
/// variable template specialization was instantiated.
VarTemplatePartialSpecializationDecl *PartialSpecialization;
/// \brief The template argument list deduced for the variable template
/// partial specialization itself.
const TemplateArgumentList *TemplateArgs;
};
/// \brief The template that this specialization specializes.
llvm::PointerUnion<VarTemplateDecl *, SpecializedPartialSpecialization *>
SpecializedTemplate;
/// \brief Further info for explicit template specialization/instantiation.
struct ExplicitSpecializationInfo {
/// \brief The type-as-written.
TypeSourceInfo *TypeAsWritten;
/// \brief The location of the extern keyword.
SourceLocation ExternLoc;
/// \brief The location of the template keyword.
SourceLocation TemplateKeywordLoc;
ExplicitSpecializationInfo()
: TypeAsWritten(0), ExternLoc(), TemplateKeywordLoc() {}
};
/// \brief Further info for explicit template specialization/instantiation.
/// Does not apply to implicit specializations.
ExplicitSpecializationInfo *ExplicitInfo;
/// \brief The template arguments used to describe this specialization.
const TemplateArgumentList *TemplateArgs;
TemplateArgumentListInfo TemplateArgsInfo;
/// \brief The point where this template was instantiated (if any).
SourceLocation PointOfInstantiation;
/// \brief The kind of specialization this declaration refers to.
/// Really a value of type TemplateSpecializationKind.
unsigned SpecializationKind : 3;
protected:
VarTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
VarTemplateDecl *SpecializedTemplate,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, const TemplateArgument *Args,
unsigned NumArgs);
explicit VarTemplateSpecializationDecl(Kind DK);
public:
static VarTemplateSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
unsigned NumArgs);
static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
virtual void getNameForDiagnostic(raw_ostream &OS,
const PrintingPolicy &Policy,
bool Qualified) const;
VarTemplateSpecializationDecl *getMostRecentDecl() {
VarDecl *Recent = static_cast<VarDecl *>(this)->getMostRecentDecl();
return cast<VarTemplateSpecializationDecl>(Recent);
}
/// \brief Retrieve the template that this specialization specializes.
VarTemplateDecl *getSpecializedTemplate() const;
/// \brief Retrieve the template arguments of the variable template
/// specialization.
const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; }
// TODO: Always set this when creating the new specialization?
void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo);
const TemplateArgumentListInfo &getTemplateArgsInfo() const {
return TemplateArgsInfo;
}
/// \brief Determine the kind of specialization that this
/// declaration represents.
TemplateSpecializationKind getSpecializationKind() const {
return static_cast<TemplateSpecializationKind>(SpecializationKind);
}
bool isExplicitSpecialization() const {
return getSpecializationKind() == TSK_ExplicitSpecialization;
}
/// \brief True if this declaration is an explicit specialization,
/// explicit instantiation declaration, or explicit instantiation
/// definition.
bool isExplicitInstantiationOrSpecialization() const {
switch (getTemplateSpecializationKind()) {
case TSK_ExplicitSpecialization:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
return true;
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
return false;
}
llvm_unreachable("bad template specialization kind");
}
void setSpecializationKind(TemplateSpecializationKind TSK) {
SpecializationKind = TSK;
}
/// \brief Get the point of instantiation (if any), or null if none.
SourceLocation getPointOfInstantiation() const {
return PointOfInstantiation;
}
void setPointOfInstantiation(SourceLocation Loc) {
assert(Loc.isValid() && "point of instantiation must be valid!");
PointOfInstantiation = Loc;
}
/// \brief If this variable template specialization is an instantiation of
/// a template (rather than an explicit specialization), return the
/// variable template or variable template partial specialization from which
/// it was instantiated.
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
getInstantiatedFrom() const {
if (getSpecializationKind() != TSK_ImplicitInstantiation &&
getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
return llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *>();
if (SpecializedPartialSpecialization *PartialSpec =
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
return PartialSpec->PartialSpecialization;
return SpecializedTemplate.get<VarTemplateDecl *>();
}
/// \brief Retrieve the variable template or variable template partial
/// specialization which was specialized by this.
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
getSpecializedTemplateOrPartial() const {
if (SpecializedPartialSpecialization *PartialSpec =
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
return PartialSpec->PartialSpecialization;
return SpecializedTemplate.get<VarTemplateDecl *>();
}
/// \brief Retrieve the set of template arguments that should be used
/// to instantiate the initializer of the variable template or variable
/// template partial specialization from which this variable template
/// specialization was instantiated.
///
/// \returns For a variable template specialization instantiated from the
/// primary template, this function will return the same template arguments
/// as getTemplateArgs(). For a variable template specialization instantiated
/// from a variable template partial specialization, this function will the
/// return deduced template arguments for the variable template partial
/// specialization itself.
const TemplateArgumentList &getTemplateInstantiationArgs() const {
if (SpecializedPartialSpecialization *PartialSpec =
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
return *PartialSpec->TemplateArgs;
return getTemplateArgs();
}
/// \brief Note that this variable template specialization is actually an
/// instantiation of the given variable template partial specialization whose
/// template arguments have been deduced.
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgumentList *TemplateArgs) {
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Already set to a variable template partial specialization!");
SpecializedPartialSpecialization *PS =
new (getASTContext()) SpecializedPartialSpecialization();
PS->PartialSpecialization = PartialSpec;
PS->TemplateArgs = TemplateArgs;
SpecializedTemplate = PS;
}
/// \brief Note that this variable template specialization is an instantiation
/// of the given variable template.
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
"Previously set to a variable template partial specialization!");
SpecializedTemplate = TemplDecl;
}
/// \brief Sets the type of this specialization as it was written by
/// the user.
void setTypeAsWritten(TypeSourceInfo *T) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = T;
}
/// \brief Gets the type of this specialization as it was written by
/// the user, if it was so written.
TypeSourceInfo *getTypeAsWritten() const {
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : 0;
}
/// \brief Gets the location of the extern keyword, if present.
SourceLocation getExternLoc() const {
return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
}
/// \brief Sets the location of the extern keyword.
void setExternLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->ExternLoc = Loc;
}
/// \brief Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TemplateKeywordLoc = Loc;
}
/// \brief Gets the location of the template keyword, if present.
SourceLocation getTemplateKeywordLoc() const {
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
}
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
}
static void Profile(llvm::FoldingSetNodeID &ID,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs, ASTContext &Context) {
ID.AddInteger(NumTemplateArgs);
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
TemplateArgs[Arg].Profile(ID, Context);
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstVarTemplateSpecialization &&
K <= lastVarTemplateSpecialization;
}
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
class VarTemplatePartialSpecializationDecl
: public VarTemplateSpecializationDecl {
virtual void anchor();
/// \brief The list of template parameters
TemplateParameterList *TemplateParams;
/// \brief The source info for the template arguments as written.
/// FIXME: redundant with TypeAsWritten?
const ASTTemplateArgumentListInfo *ArgsAsWritten;
/// \brief The variable template partial specialization from which this
/// variable template partial specialization was instantiated.
///
/// The boolean value will be true to indicate that this variable template
/// partial specialization was specialized at this level.
llvm::PointerIntPair<VarTemplatePartialSpecializationDecl *, 1, bool>
InstantiatedFromMember;
VarTemplatePartialSpecializationDecl(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
const ASTTemplateArgumentListInfo *ArgInfos);
VarTemplatePartialSpecializationDecl()
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization),
TemplateParams(0), ArgsAsWritten(0), InstantiatedFromMember(0, false) {}
public:
static VarTemplatePartialSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos);
static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
VarTemplatePartialSpecializationDecl *getMostRecentDecl() {
return cast<VarTemplatePartialSpecializationDecl>(
static_cast<VarTemplateSpecializationDecl *>(
this)->getMostRecentDecl());
}
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
return TemplateParams;
}
/// Get the template arguments as written.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
}
/// \brief Retrieve the member variable template partial specialization from
/// which this particular variable template partial specialization was
/// instantiated.
///
/// \code
/// template<typename T>
/// struct Outer {
/// template<typename U> U Inner;
/// template<typename U> U* Inner<U*> = (U*)(0); // #1
/// };
///
/// template int* Outer<float>::Inner<int*>;
/// \endcode
///
/// In this example, the instantiation of \c Outer<float>::Inner<int*> will
/// end up instantiating the partial specialization
/// \c Outer<float>::Inner<U*>, which itself was instantiated from the
/// variable template partial specialization \c Outer<T>::Inner<U*>. Given
/// \c Outer<float>::Inner<U*>, this function would return
/// \c Outer<T>::Inner<U*>.
VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
VarTemplatePartialSpecializationDecl *First =
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getPointer();
}
void
setInstantiatedFromMember(VarTemplatePartialSpecializationDecl *PartialSpec) {
VarTemplatePartialSpecializationDecl *First =
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
First->InstantiatedFromMember.setPointer(PartialSpec);
}
/// \brief Determines whether this variable template partial specialization
/// was a specialization of a member partial specialization.
///
/// In the following example, the member template partial specialization
/// \c X<int>::Inner<T*> is a member specialization.
///
/// \code
/// template<typename T>
/// struct X {
/// template<typename U> U Inner;
/// template<typename U> U* Inner<U*> = (U*)(0);
/// };
///
/// template<> template<typename T>
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
/// \endcode
bool isMemberSpecialization() {
VarTemplatePartialSpecializationDecl *First =
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
}
/// \brief Note that this member template is a specialization.
void setMemberSpecialization() {
VarTemplatePartialSpecializationDecl *First =
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
assert(First->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true);
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K == VarTemplatePartialSpecialization;
}
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
/// Declaration of a variable template.
class VarTemplateDecl : public RedeclarableTemplateDecl {
static void DeallocateCommon(void *Ptr);
protected:
/// \brief Data that is common to all of the declarations of a given
/// variable template.
struct Common : CommonBase {
Common() : LazySpecializations() {}
/// \brief The variable template specializations for this variable
/// template, including explicit specializations and instantiations.
llvm::FoldingSetVector<VarTemplateSpecializationDecl> Specializations;
/// \brief The variable template partial specializations for this variable
/// template.
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>
PartialSpecializations;
/// \brief If non-null, points to an array of specializations (including
/// partial specializations) known ownly by their external declaration IDs.
///
/// The first value in the array is the number of of specializations/
/// partial specializations that follow.
uint32_t *LazySpecializations;
};
/// \brief Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
/// \brief Retrieve the set of specializations of this variable template.
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
getSpecializations() const;
/// \brief Retrieve the set of partial specializations of this class
/// template.
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
getPartialSpecializations();
VarTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: RedeclarableTemplateDecl(VarTemplate, DC, L, Name, Params, Decl) {}
VarTemplateDecl(EmptyShell Empty)
: RedeclarableTemplateDecl(VarTemplate, 0, SourceLocation(),
DeclarationName(), 0, 0) {}
CommonBase *newCommon(ASTContext &C) const;
Common *getCommonPtr() const {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}
public:
/// \brief Get the underlying variable declarations of the template.
VarDecl *getTemplatedDecl() const {
return static_cast<VarDecl *>(TemplatedDecl);
}
/// \brief Returns whether this template declaration defines the primary
/// variable pattern.
bool isThisDeclarationADefinition() const {
return getTemplatedDecl()->isThisDeclarationADefinition();
}
VarTemplateDecl *getDefinition();
/// \brief Create a variable template node.
static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl,
VarTemplateDecl *PrevDecl);
/// \brief Create an empty variable template node.
static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// \brief Return the specialization with the provided arguments if it exists,
/// otherwise return the insertion point.
VarTemplateSpecializationDecl *
findSpecialization(const TemplateArgument *Args, unsigned NumArgs,
void *&InsertPos);
/// \brief Insert the specified specialization knowing that it is not already
/// in. InsertPos must be obtained from findSpecialization.
void AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos);
VarTemplateDecl *getCanonicalDecl() {
return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
}
const VarTemplateDecl *getCanonicalDecl() const {
return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
}
/// \brief Retrieve the previous declaration of this variable template, or
/// NULL if no such declaration exists.
VarTemplateDecl *getPreviousDecl() {
return cast_or_null<VarTemplateDecl>(
static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
}
/// \brief Retrieve the previous declaration of this variable template, or
/// NULL if no such declaration exists.
const VarTemplateDecl *getPreviousDecl() const {
return cast_or_null<VarTemplateDecl>(
static_cast<const RedeclarableTemplateDecl *>(
this)->getPreviousDecl());
}
VarTemplateDecl *getInstantiatedFromMemberTemplate() {
return cast_or_null<VarTemplateDecl>(
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
}
/// \brief Return the partial specialization with the provided arguments if it
/// exists, otherwise return the insertion point.
VarTemplatePartialSpecializationDecl *
findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs,
void *&InsertPos);
/// \brief Insert the specified partial specialization knowing that it is not
/// already in. InsertPos must be obtained from findPartialSpecialization.
void AddPartialSpecialization(VarTemplatePartialSpecializationDecl *D,
void *InsertPos);
/// \brief Retrieve the partial specializations as an ordered list.
void getPartialSpecializations(
SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS);
/// \brief Find a variable template partial specialization which was
/// instantiated
/// from the given member partial specialization.
///
/// \param D a member variable template partial specialization.
///
/// \returns the variable template partial specialization which was
/// instantiated
/// from the given member partial specialization, or NULL if no such partial
/// specialization exists.
VarTemplatePartialSpecializationDecl *findPartialSpecInstantiatedFromMember(
VarTemplatePartialSpecializationDecl *D);
typedef SpecIterator<VarTemplateSpecializationDecl> spec_iterator;
spec_iterator spec_begin() const {
return makeSpecIterator(getSpecializations(), false);
}
spec_iterator spec_end() const {
return makeSpecIterator(getSpecializations(), true);
}
typedef SpecIterator<VarTemplatePartialSpecializationDecl>
partial_spec_iterator;
partial_spec_iterator partial_spec_begin() {
return makeSpecIterator(getPartialSpecializations(), false);
}
partial_spec_iterator partial_spec_end() {
return makeSpecIterator(getPartialSpecializations(), true);
}
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == VarTemplate; }
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
} /* end of namespace clang */ } /* end of namespace clang */
#endif #endif

View File

@ -182,11 +182,16 @@ class DeclarationName {
// operator bool() - Evaluates true when this declaration name is // operator bool() - Evaluates true when this declaration name is
// non-empty. // non-empty.
operator bool() const { LLVM_EXPLICIT operator bool() const {
return ((Ptr & PtrMask) != 0) || return ((Ptr & PtrMask) != 0) ||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask)); (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
} }
/// \brief Evaluates true when this declaration name is empty.
bool isEmpty() const {
return !*this;
}
/// Predicate functions for querying what type of name this is. /// Predicate functions for querying what type of name this is.
bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; } bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
bool isObjCZeroArgSelector() const { bool isObjCZeroArgSelector() const {
@ -210,9 +215,6 @@ class DeclarationName {
/// getNameAsString - Retrieve the human-readable string for this name. /// getNameAsString - Retrieve the human-readable string for this name.
std::string getAsString() const; std::string getAsString() const;
/// printName - Print the human-readable name to a stream.
void printName(raw_ostream &OS) const;
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
/// this declaration name, or NULL if this declaration name isn't a /// this declaration name, or NULL if this declaration name isn't a
/// simple identifier. /// simple identifier.
@ -302,6 +304,8 @@ class DeclarationName {
void dump() const; void dump() const;
}; };
raw_ostream &operator<<(raw_ostream &OS, DeclarationName N);
/// Ordering on two declaration names. If both names are identifiers, /// Ordering on two declaration names. If both names are identifiers,
/// this provides a lexicographical ordering. /// this provides a lexicographical ordering.
inline bool operator<(DeclarationName LHS, DeclarationName RHS) { inline bool operator<(DeclarationName LHS, DeclarationName RHS) {

View File

@ -53,7 +53,7 @@ class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
if (E->getCond()->isValueDependent()) if (E->getCond()->isValueDependent())
return; return;
// Only the selected subexpression matters; the other one is not evaluated. // Only the selected subexpression matters; the other one is not evaluated.
return this->Visit(E->getChosenSubExpr(Context)); return this->Visit(E->getChosenSubExpr());
} }
void VisitDesignatedInitExpr(DesignatedInitExpr *E) { void VisitDesignatedInitExpr(DesignatedInitExpr *E) {

View File

@ -277,7 +277,6 @@ class Expr : public Stmt {
MLV_IncompleteType, MLV_IncompleteType,
MLV_ConstQualified, MLV_ConstQualified,
MLV_ArrayType, MLV_ArrayType,
MLV_ReadonlyProperty,
MLV_NoSetterProperty, MLV_NoSetterProperty,
MLV_MemberFunction, MLV_MemberFunction,
MLV_SubObjCPropertySetting, MLV_SubObjCPropertySetting,
@ -483,21 +482,22 @@ class Expr : public Stmt {
/// ///
/// Note: This does not perform the implicit conversions required by C++11 /// Note: This does not perform the implicit conversions required by C++11
/// [expr.const]p5. /// [expr.const]p5.
bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, bool isIntegerConstantExpr(llvm::APSInt &Result, const ASTContext &Ctx,
SourceLocation *Loc = 0, SourceLocation *Loc = 0,
bool isEvaluated = true) const; bool isEvaluated = true) const;
bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const; bool isIntegerConstantExpr(const ASTContext &Ctx,
SourceLocation *Loc = 0) const;
/// isCXX98IntegralConstantExpr - Return true if this expression is an /// isCXX98IntegralConstantExpr - Return true if this expression is an
/// integral constant expression in C++98. Can only be used in C++. /// integral constant expression in C++98. Can only be used in C++.
bool isCXX98IntegralConstantExpr(ASTContext &Ctx) const; bool isCXX98IntegralConstantExpr(const ASTContext &Ctx) const;
/// isCXX11ConstantExpr - Return true if this expression is a constant /// isCXX11ConstantExpr - Return true if this expression is a constant
/// expression in C++11. Can only be used in C++. /// expression in C++11. Can only be used in C++.
/// ///
/// Note: This does not perform the implicit conversions required by C++11 /// Note: This does not perform the implicit conversions required by C++11
/// [expr.const]p5. /// [expr.const]p5.
bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0, bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = 0,
SourceLocation *Loc = 0) const; SourceLocation *Loc = 0) const;
/// isPotentialConstantExpr - Return true if this function's definition /// isPotentialConstantExpr - Return true if this function's definition
@ -579,15 +579,14 @@ class Expr : public Stmt {
/// \brief Determine whether this expression involves a call to any function /// \brief Determine whether this expression involves a call to any function
/// that is not trivial. /// that is not trivial.
bool hasNonTrivialCall(ASTContext &Ctx); bool hasNonTrivialCall(ASTContext &Ctx);
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
/// integer. This must be called on an expression that constant folds to an /// integer. This must be called on an expression that constant folds to an
/// integer. /// integer.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const; SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
void EvaluateForOverflow(const ASTContext &Ctx, void EvaluateForOverflow(const ASTContext &Ctx) const;
SmallVectorImpl<PartialDiagnosticAt> *Diag) const;
/// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
/// lvalue with link time known address, with no side-effects. /// lvalue with link time known address, with no side-effects.
@ -760,10 +759,10 @@ class Expr : public Stmt {
/// Walk outwards from an expression we want to bind a reference to and /// Walk outwards from an expression we want to bind a reference to and
/// find the expression whose lifetime needs to be extended. Record /// find the expression whose lifetime needs to be extended. Record
/// the adjustments needed along the path. /// the LHSs of comma expressions and adjustments needed along the path.
const Expr * const Expr *skipRValueSubobjectAdjustments(
skipRValueSubobjectAdjustments( SmallVectorImpl<const Expr *> &CommaLHS,
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const; SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
/// Skip irrelevant expressions to find what should be materialize for /// Skip irrelevant expressions to find what should be materialize for
/// binding with a reference. /// binding with a reference.
@ -893,7 +892,7 @@ class DeclRefExpr : public Expr {
bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; } bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
/// \brief Helper to retrieve the optional NamedDecl through which this /// \brief Helper to retrieve the optional NamedDecl through which this
/// reference occured. /// reference occurred.
NamedDecl *&getInternalFoundDecl() { NamedDecl *&getInternalFoundDecl() {
assert(hasFoundDecl()); assert(hasFoundDecl());
if (hasQualifier()) if (hasQualifier())
@ -902,12 +901,12 @@ class DeclRefExpr : public Expr {
} }
/// \brief Helper to retrieve the optional NamedDecl through which this /// \brief Helper to retrieve the optional NamedDecl through which this
/// reference occured. /// reference occurred.
NamedDecl *getInternalFoundDecl() const { NamedDecl *getInternalFoundDecl() const {
return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl(); return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
} }
DeclRefExpr(ASTContext &Ctx, DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, SourceLocation TemplateKWLoc,
ValueDecl *D, bool refersToEnclosingLocal, ValueDecl *D, bool refersToEnclosingLocal,
@ -922,7 +921,7 @@ class DeclRefExpr : public Expr {
/// \brief Computes the type- and value-dependence flags for this /// \brief Computes the type- and value-dependence flags for this
/// declaration reference expression. /// declaration reference expression.
void computeDependence(ASTContext &C); void computeDependence(const ASTContext &C);
public: public:
DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T, DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T,
@ -938,7 +937,7 @@ class DeclRefExpr : public Expr {
computeDependence(D->getASTContext()); computeDependence(D->getASTContext());
} }
static DeclRefExpr *Create(ASTContext &Context, static DeclRefExpr *Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, SourceLocation TemplateKWLoc,
ValueDecl *D, ValueDecl *D,
@ -948,7 +947,7 @@ class DeclRefExpr : public Expr {
NamedDecl *FoundD = 0, NamedDecl *FoundD = 0,
const TemplateArgumentListInfo *TemplateArgs = 0); const TemplateArgumentListInfo *TemplateArgs = 0);
static DeclRefExpr *Create(ASTContext &Context, static DeclRefExpr *Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, SourceLocation TemplateKWLoc,
ValueDecl *D, ValueDecl *D,
@ -959,7 +958,7 @@ class DeclRefExpr : public Expr {
const TemplateArgumentListInfo *TemplateArgs = 0); const TemplateArgumentListInfo *TemplateArgs = 0);
/// \brief Construct an empty declaration reference expression. /// \brief Construct an empty declaration reference expression.
static DeclRefExpr *CreateEmpty(ASTContext &Context, static DeclRefExpr *CreateEmpty(const ASTContext &Context,
bool HasQualifier, bool HasQualifier,
bool HasFoundDecl, bool HasFoundDecl,
bool HasTemplateKWAndArgsInfo, bool HasTemplateKWAndArgsInfo,
@ -1000,7 +999,7 @@ class DeclRefExpr : public Expr {
return getInternalQualifierLoc(); return getInternalQualifierLoc();
} }
/// \brief Get the NamedDecl through which this reference occured. /// \brief Get the NamedDecl through which this reference occurred.
/// ///
/// This Decl may be different from the ValueDecl actually referred to in the /// This Decl may be different from the ValueDecl actually referred to in the
/// presence of using declarations, etc. It always returns non-NULL, and may /// presence of using declarations, etc. It always returns non-NULL, and may
@ -1151,6 +1150,7 @@ class PredefinedExpr : public Expr {
Func, Func,
Function, Function,
LFunction, // Same as Function, but as wide string. LFunction, // Same as Function, but as wide string.
FuncDName,
PrettyFunction, PrettyFunction,
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the /// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions. /// 'virtual' keyword is omitted for virtual member functions.
@ -1221,13 +1221,15 @@ class APNumericStorage {
else else
return llvm::APInt(BitWidth, VAL); return llvm::APInt(BitWidth, VAL);
} }
void setIntValue(ASTContext &C, const llvm::APInt &Val); void setIntValue(const ASTContext &C, const llvm::APInt &Val);
}; };
class APIntStorage : private APNumericStorage { class APIntStorage : private APNumericStorage {
public: public:
llvm::APInt getValue() const { return getIntValue(); } llvm::APInt getValue() const { return getIntValue(); }
void setValue(ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); } void setValue(const ASTContext &C, const llvm::APInt &Val) {
setIntValue(C, Val);
}
}; };
class APFloatStorage : private APNumericStorage { class APFloatStorage : private APNumericStorage {
@ -1235,7 +1237,7 @@ class APFloatStorage : private APNumericStorage {
llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const { llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const {
return llvm::APFloat(Semantics, getIntValue()); return llvm::APFloat(Semantics, getIntValue());
} }
void setValue(ASTContext &C, const llvm::APFloat &Val) { void setValue(const ASTContext &C, const llvm::APFloat &Val) {
setIntValue(C, Val.bitcastToAPInt()); setIntValue(C, Val.bitcastToAPInt());
} }
}; };
@ -1250,17 +1252,17 @@ class IntegerLiteral : public Expr, public APIntStorage {
public: public:
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
// or UnsignedLongLongTy // or UnsignedLongLongTy
IntegerLiteral(ASTContext &C, const llvm::APInt &V, QualType type, IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type,
SourceLocation l); SourceLocation l);
/// \brief Returns a new integer literal with value 'V' and type 'type'. /// \brief Returns a new integer literal with value 'V' and type 'type'.
/// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy, /// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy,
/// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V /// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V
/// \param V - the value that the returned integer literal contains. /// \param V - the value that the returned integer literal contains.
static IntegerLiteral *Create(ASTContext &C, const llvm::APInt &V, static IntegerLiteral *Create(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l); QualType type, SourceLocation l);
/// \brief Returns a new empty integer literal. /// \brief Returns a new empty integer literal.
static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty); static IntegerLiteral *Create(const ASTContext &C, EmptyShell Empty);
SourceLocation getLocStart() const LLVM_READONLY { return Loc; } SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
@ -1328,21 +1330,21 @@ class CharacterLiteral : public Expr {
class FloatingLiteral : public Expr, private APFloatStorage { class FloatingLiteral : public Expr, private APFloatStorage {
SourceLocation Loc; SourceLocation Loc;
FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact, FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact,
QualType Type, SourceLocation L); QualType Type, SourceLocation L);
/// \brief Construct an empty floating-point literal. /// \brief Construct an empty floating-point literal.
explicit FloatingLiteral(ASTContext &C, EmptyShell Empty); explicit FloatingLiteral(const ASTContext &C, EmptyShell Empty);
public: public:
static FloatingLiteral *Create(ASTContext &C, const llvm::APFloat &V, static FloatingLiteral *Create(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L); bool isexact, QualType Type, SourceLocation L);
static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty); static FloatingLiteral *Create(const ASTContext &C, EmptyShell Empty);
llvm::APFloat getValue() const { llvm::APFloat getValue() const {
return APFloatStorage::getValue(getSemantics()); return APFloatStorage::getValue(getSemantics());
} }
void setValue(ASTContext &C, const llvm::APFloat &Val) { void setValue(const ASTContext &C, const llvm::APFloat &Val) {
assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics"); assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics");
APFloatStorage::setValue(C, Val); APFloatStorage::setValue(C, Val);
} }
@ -1420,7 +1422,7 @@ class ImaginaryLiteral : public Expr {
}; };
/// StringLiteral - This represents a string literal expression, e.g. "foo" /// StringLiteral - This represents a string literal expression, e.g. "foo"
/// or L"bar" (wide strings). The actual string is returned by getStrData() /// or L"bar" (wide strings). The actual string is returned by getBytes()
/// is NOT null-terminated, and the length of the string is determined by /// is NOT null-terminated, and the length of the string is determined by
/// calling getByteLength(). The C type for a string is always a /// calling getByteLength(). The C type for a string is always a
/// ConstantArrayType. In C++, the char type is const qualified, in C it is /// ConstantArrayType. In C++, the char type is const qualified, in C it is
@ -1469,19 +1471,19 @@ class StringLiteral : public Expr {
public: public:
/// This is the "fully general" constructor that allows representation of /// This is the "fully general" constructor that allows representation of
/// strings formed from multiple concatenated tokens. /// strings formed from multiple concatenated tokens.
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind, static StringLiteral *Create(const ASTContext &C, StringRef Str,
bool Pascal, QualType Ty, StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc, unsigned NumStrs); const SourceLocation *Loc, unsigned NumStrs);
/// Simple constructor for string literals made from one token. /// Simple constructor for string literals made from one token.
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind, static StringLiteral *Create(const ASTContext &C, StringRef Str,
bool Pascal, QualType Ty, StringKind Kind, bool Pascal, QualType Ty,
SourceLocation Loc) { SourceLocation Loc) {
return Create(C, Str, Kind, Pascal, Ty, &Loc, 1); return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
} }
/// \brief Construct an empty string literal. /// \brief Construct an empty string literal.
static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs); static StringLiteral *CreateEmpty(const ASTContext &C, unsigned NumStrs);
StringRef getString() const { StringRef getString() const {
assert(CharByteWidth==1 assert(CharByteWidth==1
@ -1520,7 +1522,7 @@ class StringLiteral : public Expr {
unsigned getCharByteWidth() const { return CharByteWidth; } unsigned getCharByteWidth() const { return CharByteWidth; }
/// \brief Sets the string data to the given string data. /// \brief Sets the string data to the given string data.
void setString(ASTContext &C, StringRef Str, void setString(const ASTContext &C, StringRef Str,
StringKind Kind, bool IsPascal); StringKind Kind, bool IsPascal);
StringKind getKind() const { return static_cast<StringKind>(Kind); } StringKind getKind() const { return static_cast<StringKind>(Kind); }
@ -1853,7 +1855,7 @@ class OffsetOfExpr : public Expr {
// Number of sub-expressions (i.e. array subscript expressions). // Number of sub-expressions (i.e. array subscript expressions).
unsigned NumExprs; unsigned NumExprs;
OffsetOfExpr(ASTContext &C, QualType type, OffsetOfExpr(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi, SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs, ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc); SourceLocation RParenLoc);
@ -1864,12 +1866,12 @@ class OffsetOfExpr : public Expr {
public: public:
static OffsetOfExpr *Create(ASTContext &C, QualType type, static OffsetOfExpr *Create(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi, SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<OffsetOfNode> comps,
ArrayRef<Expr*> exprs, SourceLocation RParenLoc); ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
static OffsetOfExpr *CreateEmpty(ASTContext &C, static OffsetOfExpr *CreateEmpty(const ASTContext &C,
unsigned NumComps, unsigned NumExprs); unsigned NumComps, unsigned NumExprs);
/// getOperatorLoc - Return the location of the operator. /// getOperatorLoc - Return the location of the operator.
@ -2133,10 +2135,11 @@ class CallExpr : public Expr {
protected: protected:
// These versions of the constructor are for derived classes. // These versions of the constructor are for derived classes.
CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK, ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc); SourceLocation rparenloc);
CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty); CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty);
Stmt *getPreArg(unsigned i) { Stmt *getPreArg(unsigned i) {
assert(i < getNumPreArgs() && "Prearg access out of range!"); assert(i < getNumPreArgs() && "Prearg access out of range!");
@ -2154,11 +2157,11 @@ class CallExpr : public Expr {
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
public: public:
CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
ExprValueKind VK, SourceLocation rparenloc); ExprValueKind VK, SourceLocation rparenloc);
/// \brief Build an empty call expression. /// \brief Build an empty call expression.
CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty); CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty);
const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); } const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); }
Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } Expr *getCallee() { return cast<Expr>(SubExprs[FN]); }
@ -2206,7 +2209,7 @@ class CallExpr : public Expr {
/// setNumArgs - This changes the number of arguments present in this call. /// setNumArgs - This changes the number of arguments present in this call.
/// Any orphaned expressions are deleted by this, and any new operands are set /// Any orphaned expressions are deleted by this, and any new operands are set
/// to null. /// to null.
void setNumArgs(ASTContext& C, unsigned NumArgs); void setNumArgs(const ASTContext& C, unsigned NumArgs);
typedef ExprIterator arg_iterator; typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator; typedef ConstExprIterator const_arg_iterator;
@ -2360,7 +2363,7 @@ class MemberExpr : public Expr {
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false), HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
HadMultipleCandidates(false) {} HadMultipleCandidates(false) {}
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, SourceLocation TemplateKWLoc,
ValueDecl *memberdecl, DeclAccessPair founddecl, ValueDecl *memberdecl, DeclAccessPair founddecl,
@ -2747,12 +2750,13 @@ class ImplicitCastExpr : public CastExpr {
: CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) { : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) {
} }
static ImplicitCastExpr *Create(ASTContext &Context, QualType T, static ImplicitCastExpr *Create(const ASTContext &Context, QualType T,
CastKind Kind, Expr *Operand, CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath, const CXXCastPath *BasePath,
ExprValueKind Cat); ExprValueKind Cat);
static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize); static ImplicitCastExpr *CreateEmpty(const ASTContext &Context,
unsigned PathSize);
SourceLocation getLocStart() const LLVM_READONLY { SourceLocation getLocStart() const LLVM_READONLY {
return getSubExpr()->getLocStart(); return getSubExpr()->getLocStart();
@ -2838,13 +2842,14 @@ class CStyleCastExpr : public ExplicitCastExpr {
: ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { } : ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { }
public: public:
static CStyleCastExpr *Create(ASTContext &Context, QualType T, static CStyleCastExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, CastKind K, ExprValueKind VK, CastKind K,
Expr *Op, const CXXCastPath *BasePath, Expr *Op, const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L, TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation R); SourceLocation R);
static CStyleCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize); static CStyleCastExpr *CreateEmpty(const ASTContext &Context,
unsigned PathSize);
SourceLocation getLParenLoc() const { return LPLoc; } SourceLocation getLParenLoc() const { return LPLoc; }
void setLParenLoc(SourceLocation L) { LPLoc = L; } void setLParenLoc(SourceLocation L) { LPLoc = L; }
@ -3412,7 +3417,7 @@ class ShuffleVectorExpr : public Expr {
unsigned NumExprs; unsigned NumExprs;
public: public:
ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type, ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type,
SourceLocation BLoc, SourceLocation RP); SourceLocation BLoc, SourceLocation RP);
/// \brief Build an empty vector-shuffle expression. /// \brief Build an empty vector-shuffle expression.
@ -3450,11 +3455,11 @@ class ShuffleVectorExpr : public Expr {
return cast<Expr>(SubExprs[Index]); return cast<Expr>(SubExprs[Index]);
} }
void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs); void setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs);
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) const { llvm::APSInt getShuffleMaskIdx(const ASTContext &Ctx, unsigned N) const {
assert((N < NumExprs - 2) && "Shuffle idx out of range!"); assert((N < NumExprs - 2) && "Shuffle idx out of range!");
return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue(); return getExpr(N+2)->EvaluateKnownConstInt(Ctx);
} }
// Iterators // Iterators
@ -3463,6 +3468,60 @@ class ShuffleVectorExpr : public Expr {
} }
}; };
/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
/// This AST node provides support for converting a vector type to another
/// vector type of the same arity.
class ConvertVectorExpr : public Expr {
private:
Stmt *SrcExpr;
TypeSourceInfo *TInfo;
SourceLocation BuiltinLoc, RParenLoc;
friend class ASTReader;
friend class ASTStmtReader;
explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {}
public:
ConvertVectorExpr(Expr* SrcExpr, TypeSourceInfo *TI, QualType DstType,
ExprValueKind VK, ExprObjectKind OK,
SourceLocation BuiltinLoc, SourceLocation RParenLoc)
: Expr(ConvertVectorExprClass, DstType, VK, OK,
DstType->isDependentType(),
DstType->isDependentType() || SrcExpr->isValueDependent(),
(DstType->isInstantiationDependentType() ||
SrcExpr->isInstantiationDependent()),
(DstType->containsUnexpandedParameterPack() ||
SrcExpr->containsUnexpandedParameterPack())),
SrcExpr(SrcExpr), TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {}
/// getSrcExpr - Return the Expr to be converted.
Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); }
/// getTypeSourceInfo - Return the destination type.
TypeSourceInfo *getTypeSourceInfo() const {
return TInfo;
}
void setTypeSourceInfo(TypeSourceInfo *ti) {
TInfo = ti;
}
/// getBuiltinLoc - Return the location of the __builtin_convertvector token.
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
/// getRParenLoc - Return the location of final right parenthesis.
SourceLocation getRParenLoc() const { return RParenLoc; }
SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ConvertVectorExprClass;
}
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
};
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr. /// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
/// This AST node is similar to the conditional operator (?:) in C, with /// This AST node is similar to the conditional operator (?:) in C, with
/// the following exceptions: /// the following exceptions:
@ -3476,10 +3535,12 @@ class ChooseExpr : public Expr {
enum { COND, LHS, RHS, END_EXPR }; enum { COND, LHS, RHS, END_EXPR };
Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
SourceLocation BuiltinLoc, RParenLoc; SourceLocation BuiltinLoc, RParenLoc;
bool CondIsTrue;
public: public:
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs,
QualType t, ExprValueKind VK, ExprObjectKind OK, QualType t, ExprValueKind VK, ExprObjectKind OK,
SourceLocation RP, bool TypeDependent, bool ValueDependent) SourceLocation RP, bool condIsTrue,
bool TypeDependent, bool ValueDependent)
: Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent, : Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent,
(cond->isInstantiationDependent() || (cond->isInstantiationDependent() ||
lhs->isInstantiationDependent() || lhs->isInstantiationDependent() ||
@ -3487,7 +3548,7 @@ class ChooseExpr : public Expr {
(cond->containsUnexpandedParameterPack() || (cond->containsUnexpandedParameterPack() ||
lhs->containsUnexpandedParameterPack() || lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())), rhs->containsUnexpandedParameterPack())),
BuiltinLoc(BLoc), RParenLoc(RP) { BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) {
SubExprs[COND] = cond; SubExprs[COND] = cond;
SubExprs[LHS] = lhs; SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs; SubExprs[RHS] = rhs;
@ -3498,12 +3559,21 @@ class ChooseExpr : public Expr {
/// isConditionTrue - Return whether the condition is true (i.e. not /// isConditionTrue - Return whether the condition is true (i.e. not
/// equal to zero). /// equal to zero).
bool isConditionTrue(const ASTContext &C) const; bool isConditionTrue() const {
assert(!isConditionDependent() &&
"Dependent condition isn't true or false");
return CondIsTrue;
}
void setIsConditionTrue(bool isTrue) { CondIsTrue = isTrue; }
bool isConditionDependent() const {
return getCond()->isTypeDependent() || getCond()->isValueDependent();
}
/// getChosenSubExpr - Return the subexpression chosen according to the /// getChosenSubExpr - Return the subexpression chosen according to the
/// condition. /// condition.
Expr *getChosenSubExpr(const ASTContext &C) const { Expr *getChosenSubExpr() const {
return isConditionTrue(C) ? getLHS() : getRHS(); return isConditionTrue() ? getLHS() : getRHS();
} }
Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
@ -3663,7 +3733,7 @@ class InitListExpr : public Expr {
SourceLocation LBraceLoc, RBraceLoc; SourceLocation LBraceLoc, RBraceLoc;
/// The alternative form of the initializer list (if it exists). /// The alternative form of the initializer list (if it exists).
/// The int part of the pair stores whether this initalizer list is /// The int part of the pair stores whether this initializer list is
/// in semantic form. If not null, the pointer points to: /// in semantic form. If not null, the pointer points to:
/// - the syntactic form, if this is in semantic form; /// - the syntactic form, if this is in semantic form;
/// - the semantic form, if this is in syntactic form. /// - the semantic form, if this is in syntactic form.
@ -3679,7 +3749,7 @@ class InitListExpr : public Expr {
llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit; llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
public: public:
InitListExpr(ASTContext &C, SourceLocation lbraceloc, InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc); ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
/// \brief Build an empty initializer list. /// \brief Build an empty initializer list.
@ -3707,7 +3777,7 @@ class InitListExpr : public Expr {
} }
/// \brief Reserve space for some number of initializers. /// \brief Reserve space for some number of initializers.
void reserveInits(ASTContext &C, unsigned NumInits); void reserveInits(const ASTContext &C, unsigned NumInits);
/// @brief Specify the number of initializers /// @brief Specify the number of initializers
/// ///
@ -3715,7 +3785,7 @@ class InitListExpr : public Expr {
/// initializers will be destroyed. If there are fewer than @p /// initializers will be destroyed. If there are fewer than @p
/// NumInits initializers, NULL expressions will be added for the /// NumInits initializers, NULL expressions will be added for the
/// unknown initializers. /// unknown initializers.
void resizeInits(ASTContext &Context, unsigned NumInits); void resizeInits(const ASTContext &Context, unsigned NumInits);
/// @brief Updates the initializer at index @p Init with the new /// @brief Updates the initializer at index @p Init with the new
/// expression @p expr, and returns the old expression at that /// expression @p expr, and returns the old expression at that
@ -3724,7 +3794,7 @@ class InitListExpr : public Expr {
/// When @p Init is out of range for this initializer list, the /// When @p Init is out of range for this initializer list, the
/// initializer list will be extended with NULL expressions to /// initializer list will be extended with NULL expressions to
/// accommodate the new entry. /// accommodate the new entry.
Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr); Expr *updateInit(const ASTContext &C, unsigned Init, Expr *expr);
/// \brief If this initializer list initializes an array with more elements /// \brief If this initializer list initializes an array with more elements
/// than there are initializers in the list, specifies an expression to be /// than there are initializers in the list, specifies an expression to be
@ -3754,6 +3824,10 @@ class InitListExpr : public Expr {
return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion(); return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
} }
void setInitializedFieldInUnion(FieldDecl *FD) { void setInitializedFieldInUnion(FieldDecl *FD) {
assert((FD == 0
|| getInitializedFieldInUnion() == 0
|| getInitializedFieldInUnion() == FD)
&& "Only one field of a union may be initialized at a time!");
ArrayFillerOrUnionFieldInit = FD; ArrayFillerOrUnionFieldInit = FD;
} }
@ -3794,13 +3868,6 @@ class InitListExpr : public Expr {
InitListExprBits.HadArrayRangeDesignator = ARD; InitListExprBits.HadArrayRangeDesignator = ARD;
} }
bool initializesStdInitializerList() const {
return InitListExprBits.InitializesStdInitializerList != 0;
}
void setInitializesStdInitializerList(bool ISIL = true) {
InitListExprBits.InitializesStdInitializerList = ISIL;
}
SourceLocation getLocStart() const LLVM_READONLY; SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY; SourceLocation getLocEnd() const LLVM_READONLY;
@ -3851,7 +3918,7 @@ class InitListExpr : public Expr {
/// The InitListExpr contains three DesignatedInitExprs, the first of /// The InitListExpr contains three DesignatedInitExprs, the first of
/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two /// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
/// designators, one array designator for @c [2] followed by one field /// designators, one array designator for @c [2] followed by one field
/// designator for @c .y. The initalization expression will be 1.0. /// designator for @c .y. The initialization expression will be 1.0.
class DesignatedInitExpr : public Expr { class DesignatedInitExpr : public Expr {
public: public:
/// \brief Forward declaration of the Designator class. /// \brief Forward declaration of the Designator class.
@ -3879,7 +3946,7 @@ class DesignatedInitExpr : public Expr {
Designator *Designators; Designator *Designators;
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators, DesignatedInitExpr(const ASTContext &C, QualType Ty, unsigned NumDesignators,
const Designator *Designators, const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax, SourceLocation EqualOrColonLoc, bool GNUSyntax,
ArrayRef<Expr*> IndexExprs, Expr *Init); ArrayRef<Expr*> IndexExprs, Expr *Init);
@ -4041,13 +4108,15 @@ class DesignatedInitExpr : public Expr {
} }
}; };
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, static DesignatedInitExpr *Create(const ASTContext &C,
Designator *Designators,
unsigned NumDesignators, unsigned NumDesignators,
ArrayRef<Expr*> IndexExprs, ArrayRef<Expr*> IndexExprs,
SourceLocation EqualOrColonLoc, SourceLocation EqualOrColonLoc,
bool GNUSyntax, Expr *Init); bool GNUSyntax, Expr *Init);
static DesignatedInitExpr *CreateEmpty(ASTContext &C, unsigned NumIndexExprs); static DesignatedInitExpr *CreateEmpty(const ASTContext &C,
unsigned NumIndexExprs);
/// @brief Returns the number of designators in this initializer. /// @brief Returns the number of designators in this initializer.
unsigned size() const { return NumDesignators; } unsigned size() const { return NumDesignators; }
@ -4085,7 +4154,7 @@ class DesignatedInitExpr : public Expr {
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; } Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
void setDesignators(ASTContext &C, const Designator *Desigs, void setDesignators(const ASTContext &C, const Designator *Desigs,
unsigned NumDesigs); unsigned NumDesigs);
Expr *getArrayIndex(const Designator &D) const; Expr *getArrayIndex(const Designator &D) const;
@ -4133,8 +4202,8 @@ class DesignatedInitExpr : public Expr {
/// \brief Replaces the designator at index @p Idx with the series /// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last). /// of designators in [First, Last).
void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First, void ExpandDesignator(const ASTContext &C, unsigned Idx,
const Designator *Last); const Designator *First, const Designator *Last);
SourceRange getDesignatorsSourceRange() const; SourceRange getDesignatorsSourceRange() const;
@ -4188,8 +4257,8 @@ class ParenListExpr : public Expr {
SourceLocation LParenLoc, RParenLoc; SourceLocation LParenLoc, RParenLoc;
public: public:
ParenListExpr(ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs, ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
SourceLocation rparenloc); ArrayRef<Expr*> exprs, SourceLocation rparenloc);
/// \brief Build an empty paren list. /// \brief Build an empty paren list.
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { } explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
@ -4262,7 +4331,7 @@ class GenericSelectionExpr : public Expr {
SourceLocation GenericLoc, DefaultLoc, RParenLoc; SourceLocation GenericLoc, DefaultLoc, RParenLoc;
public: public:
GenericSelectionExpr(ASTContext &Context, GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr, SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes, ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs, ArrayRef<Expr*> AssocExprs,
@ -4271,7 +4340,7 @@ class GenericSelectionExpr : public Expr {
unsigned ResultIndex); unsigned ResultIndex);
/// This constructor is used in the result-dependent case. /// This constructor is used in the result-dependent case.
GenericSelectionExpr(ASTContext &Context, GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr, SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes, ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs, ArrayRef<Expr*> AssocExprs,
@ -4450,7 +4519,7 @@ class BlockExpr : public Expr {
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] /// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
/// This AST node provides support for reinterpreting a type to another /// This AST node provides support for reinterpreting a type to another
/// type of the same size. /// type of the same size.
class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr? class AsTypeExpr : public Expr {
private: private:
Stmt *SrcExpr; Stmt *SrcExpr;
SourceLocation BuiltinLoc, RParenLoc; SourceLocation BuiltinLoc, RParenLoc;
@ -4552,13 +4621,13 @@ class PseudoObjectExpr : public Expr {
public: public:
/// NoResult - A value for the result index indicating that there is /// NoResult - A value for the result index indicating that there is
/// no semantic result. /// no semantic result.
enum { NoResult = ~0U }; enum LLVM_ENUM_INT_TYPE(unsigned) { NoResult = ~0U };
static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic, static PseudoObjectExpr *Create(const ASTContext &Context, Expr *syntactic,
ArrayRef<Expr*> semantic, ArrayRef<Expr*> semantic,
unsigned resultIndex); unsigned resultIndex);
static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell, static PseudoObjectExpr *Create(const ASTContext &Context, EmptyShell shell,
unsigned numSemanticExprs); unsigned numSemanticExprs);
/// Return the syntactic form of this expression, i.e. the /// Return the syntactic form of this expression, i.e. the

File diff suppressed because it is too large Load Diff

View File

@ -143,12 +143,13 @@ class ObjCArrayLiteral : public Expr {
: Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {} : Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {}
public: public:
static ObjCArrayLiteral *Create(ASTContext &C, static ObjCArrayLiteral *Create(const ASTContext &C,
ArrayRef<Expr *> Elements, ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method, QualType T, ObjCMethodDecl * Method,
SourceRange SR); SourceRange SR);
static ObjCArrayLiteral *CreateEmpty(ASTContext &C, unsigned NumElements); static ObjCArrayLiteral *CreateEmpty(const ASTContext &C,
unsigned NumElements);
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
@ -289,13 +290,13 @@ class ObjCDictionaryLiteral : public Expr {
} }
public: public:
static ObjCDictionaryLiteral *Create(ASTContext &C, static ObjCDictionaryLiteral *Create(const ASTContext &C,
ArrayRef<ObjCDictionaryElement> VK, ArrayRef<ObjCDictionaryElement> VK,
bool HasPackExpansions, bool HasPackExpansions,
QualType T, ObjCMethodDecl *method, QualType T, ObjCMethodDecl *method,
SourceRange SR); SourceRange SR);
static ObjCDictionaryLiteral *CreateEmpty(ASTContext &C, static ObjCDictionaryLiteral *CreateEmpty(const ASTContext &C,
unsigned NumElements, unsigned NumElements,
bool HasPackExpansions); bool HasPackExpansions);
@ -807,7 +808,7 @@ class ObjCSubscriptRefExpr : public Expr {
explicit ObjCSubscriptRefExpr(EmptyShell Empty) explicit ObjCSubscriptRefExpr(EmptyShell Empty)
: Expr(ObjCSubscriptRefExprClass, Empty) {} : Expr(ObjCSubscriptRefExprClass, Empty) {}
static ObjCSubscriptRefExpr *Create(ASTContext &C, static ObjCSubscriptRefExpr *Create(const ASTContext &C,
Expr *base, Expr *base,
Expr *key, QualType T, Expr *key, QualType T,
ObjCMethodDecl *getMethod, ObjCMethodDecl *getMethod,
@ -1003,13 +1004,13 @@ class ObjCMessageExpr : public Expr {
return getNumSelectorLocs(); return getNumSelectorLocs();
} }
static ObjCMessageExpr *alloc(ASTContext &C, static ObjCMessageExpr *alloc(const ASTContext &C,
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
SourceLocation RBraceLoc, SourceLocation RBraceLoc,
ArrayRef<SourceLocation> SelLocs, ArrayRef<SourceLocation> SelLocs,
Selector Sel, Selector Sel,
SelectorLocationsKind &SelLocsK); SelectorLocationsKind &SelLocsK);
static ObjCMessageExpr *alloc(ASTContext &C, static ObjCMessageExpr *alloc(const ASTContext &C,
unsigned NumArgs, unsigned NumArgs,
unsigned NumStoredSelLocs); unsigned NumStoredSelLocs);
@ -1051,7 +1052,7 @@ class ObjCMessageExpr : public Expr {
/// \param Args The message send arguments. /// \param Args The message send arguments.
/// ///
/// \param RBracLoc The location of the closing square bracket ']'. /// \param RBracLoc The location of the closing square bracket ']'.
static ObjCMessageExpr *Create(ASTContext &Context, QualType T, static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, ExprValueKind VK,
SourceLocation LBracLoc, SourceLocation LBracLoc,
SourceLocation SuperLoc, SourceLocation SuperLoc,
@ -1087,7 +1088,7 @@ class ObjCMessageExpr : public Expr {
/// \param Args The message send arguments. /// \param Args The message send arguments.
/// ///
/// \param RBracLoc The location of the closing square bracket ']'. /// \param RBracLoc The location of the closing square bracket ']'.
static ObjCMessageExpr *Create(ASTContext &Context, QualType T, static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, ExprValueKind VK,
SourceLocation LBracLoc, SourceLocation LBracLoc,
TypeSourceInfo *Receiver, TypeSourceInfo *Receiver,
@ -1121,7 +1122,7 @@ class ObjCMessageExpr : public Expr {
/// \param Args The message send arguments. /// \param Args The message send arguments.
/// ///
/// \param RBracLoc The location of the closing square bracket ']'. /// \param RBracLoc The location of the closing square bracket ']'.
static ObjCMessageExpr *Create(ASTContext &Context, QualType T, static ObjCMessageExpr *Create(const ASTContext &Context, QualType T,
ExprValueKind VK, ExprValueKind VK,
SourceLocation LBracLoc, SourceLocation LBracLoc,
Expr *Receiver, Expr *Receiver,
@ -1139,7 +1140,7 @@ class ObjCMessageExpr : public Expr {
/// ///
/// \param NumArgs The number of message arguments, not including /// \param NumArgs The number of message arguments, not including
/// the receiver. /// the receiver.
static ObjCMessageExpr *CreateEmpty(ASTContext &Context, static ObjCMessageExpr *CreateEmpty(const ASTContext &Context,
unsigned NumArgs, unsigned NumArgs,
unsigned NumStoredSelLocs); unsigned NumStoredSelLocs);

View File

@ -329,7 +329,12 @@ struct LazyOffsetPtr {
/// \brief Whether this pointer is non-NULL. /// \brief Whether this pointer is non-NULL.
/// ///
/// This operation does not require the AST node to be deserialized. /// This operation does not require the AST node to be deserialized.
operator bool() const { return Ptr != 0; } LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
/// \brief Whether this pointer is non-NULL.
///
/// This operation does not require the AST node to be deserialized.
bool isValid() const { return Ptr != 0; }
/// \brief Whether this pointer is currently stored as an offset. /// \brief Whether this pointer is currently stored as an offset.
bool isOffset() const { return Ptr & 0x01; } bool isOffset() const { return Ptr & 0x01; }

View File

@ -41,6 +41,7 @@ class GlobalDecl {
GlobalDecl(const VarDecl *D) { Init(D);} GlobalDecl(const VarDecl *D) { Init(D);}
GlobalDecl(const FunctionDecl *D) { Init(D); } GlobalDecl(const FunctionDecl *D) { Init(D); }
GlobalDecl(const BlockDecl *D) { Init(D); } GlobalDecl(const BlockDecl *D) { Init(D); }
GlobalDecl(const CapturedDecl *D) { Init(D); }
GlobalDecl(const ObjCMethodDecl *D) { Init(D); } GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)

View File

@ -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

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
namespace clang { namespace clang {
@ -64,18 +65,29 @@ class MangleBuffer {
/// MangleContext - Context for tracking state which persists across multiple /// MangleContext - Context for tracking state which persists across multiple
/// calls to the C++ name mangler. /// calls to the C++ name mangler.
class MangleContext { class MangleContext {
public:
enum ManglerKind {
MK_Itanium,
MK_Microsoft
};
private:
virtual void anchor(); virtual void anchor();
ASTContext &Context; ASTContext &Context;
DiagnosticsEngine &Diags; DiagnosticsEngine &Diags;
const ManglerKind Kind;
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds; llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds; llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
public: public:
ManglerKind getKind() const { return Kind; }
explicit MangleContext(ASTContext &Context, explicit MangleContext(ASTContext &Context,
DiagnosticsEngine &Diags) DiagnosticsEngine &Diags,
: Context(Context), Diags(Diags) { } ManglerKind Kind)
: Context(Context), Diags(Diags), Kind(Kind) {}
virtual ~MangleContext() { } virtual ~MangleContext() { }
@ -96,8 +108,12 @@ class MangleContext {
/// @name Mangler Entry Points /// @name Mangler Entry Points
/// @{ /// @{
virtual bool shouldMangleDeclName(const NamedDecl *D) = 0; bool shouldMangleDeclName(const NamedDecl *D);
virtual void mangleName(const NamedDecl *D, raw_ostream &)=0; virtual bool shouldMangleCXXName(const NamedDecl *D) = 0;
// FIXME: consider replacing raw_ostream & with something like SmallString &.
void mangleName(const NamedDecl *D, raw_ostream &);
virtual void mangleCXXName(const NamedDecl *D, raw_ostream &) = 0;
virtual void mangleThunk(const CXXMethodDecl *MD, virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk, const ThunkInfo &Thunk,
raw_ostream &) = 0; raw_ostream &) = 0;
@ -106,13 +122,6 @@ class MangleContext {
raw_ostream &) = 0; raw_ostream &) = 0;
virtual void mangleReferenceTemporary(const VarDecl *D, virtual void mangleReferenceTemporary(const VarDecl *D,
raw_ostream &) = 0; raw_ostream &) = 0;
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
raw_ostream &) = 0;
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
raw_ostream &) = 0;
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
raw_ostream &) = 0;
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0; virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0; virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
@ -129,36 +138,78 @@ class MangleContext {
const BlockDecl *BD, raw_ostream &Out); const BlockDecl *BD, raw_ostream &Out);
void mangleBlock(const DeclContext *DC, const BlockDecl *BD, void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
raw_ostream &Out); raw_ostream &Out);
// Do the right thing.
void mangleBlock(const BlockDecl *BD, raw_ostream &Out,
const NamedDecl *ID=0);
void mangleObjCMethodName(const ObjCMethodDecl *MD, void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &);
raw_ostream &);
// This is pretty lame. virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) = 0;
virtual void mangleItaniumGuardVariable(const VarDecl *D,
raw_ostream &) { virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &) = 0;
llvm_unreachable("Target does not support mangling guard variables");
} virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
// FIXME: Revisit this once we know what we need to do for MSVC compatibility. raw_ostream &) = 0;
virtual void mangleItaniumThreadLocalInit(const VarDecl *D,
raw_ostream &) { /// Generates a unique string for an externally visible type for use with TBAA
llvm_unreachable("Target does not support mangling thread_local variables"); /// or type uniquing.
} /// TODO: Extend this to internal types by generating names that are unique
virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D, /// across translation units so it can be used with LTO.
raw_ostream &) { virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
llvm_unreachable("Target does not support mangling thread_local variables");
}
/// @} /// @}
}; };
MangleContext *createItaniumMangleContext(ASTContext &Context, class ItaniumMangleContext : public MangleContext {
DiagnosticsEngine &Diags); public:
MangleContext *createMicrosoftMangleContext(ASTContext &Context, explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
DiagnosticsEngine &Diags); : MangleContext(C, D, MK_Itanium) {}
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
raw_ostream &) = 0;
virtual void mangleItaniumThreadLocalInit(const VarDecl *D,
raw_ostream &) = 0;
virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D,
raw_ostream &) = 0;
static bool classof(const MangleContext *C) {
return C->getKind() == MK_Itanium;
}
static ItaniumMangleContext *create(ASTContext &Context,
DiagnosticsEngine &Diags);
};
class MicrosoftMangleContext : public MangleContext {
public:
explicit MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D)
: MangleContext(C, D, MK_Microsoft) {}
/// \brief Mangle vftable symbols. Only a subset of the bases along the path
/// to the vftable are included in the name. It's up to the caller to pick
/// them correctly.
virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) = 0;
/// \brief Mangle vbtable symbols. Only a subset of the bases along the path
/// to the vbtable are included in the name. It's up to the caller to pick
/// them correctly.
virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) = 0;
virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
uint64_t OffsetInVFTable,
raw_ostream &) = 0;
static bool classof(const MangleContext *C) {
return C->getKind() == MK_Microsoft;
}
static MicrosoftMangleContext *create(ASTContext &Context,
DiagnosticsEngine &Diags);
};
} }
#endif #endif

View 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

View File

@ -231,7 +231,11 @@ class NestedNameSpecifierLoc {
/// \brief Evalutes true when this nested-name-specifier location is /// \brief Evalutes true when this nested-name-specifier location is
/// non-empty. /// non-empty.
operator bool() const { return Qualifier; } LLVM_EXPLICIT operator bool() const { return Qualifier; }
/// \brief Evalutes true when this nested-name-specifier location is
/// empty.
bool hasQualifier() const { return Qualifier; }
/// \brief Retrieve the nested-name-specifier to which this instance /// \brief Retrieve the nested-name-specifier to which this instance
/// refers. /// refers.

View File

@ -29,6 +29,11 @@ class ParentMap {
/// visited and updated or inserted but not the parents of S. /// visited and updated or inserted but not the parents of S.
void addStmt(Stmt* S); void addStmt(Stmt* S);
/// Manually sets the parent of \p S to \p Parent.
///
/// If \p S is already in the map, this method will update the mapping.
void setParent(const Stmt *S, const Stmt *Parent);
Stmt *getParent(Stmt*) const; Stmt *getParent(Stmt*) const;
Stmt *getParentIgnoreParens(Stmt *) const; Stmt *getParentIgnoreParens(Stmt *) const;
Stmt *getParentIgnoreParenCasts(Stmt *) const; Stmt *getParentIgnoreParenCasts(Stmt *) const;

View File

@ -39,8 +39,9 @@ struct PrintingPolicy {
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false), SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
SuppressUnwrittenScope(false), SuppressInitializers(false), SuppressUnwrittenScope(false), SuppressInitializers(false),
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
SuppressStrongLifetime(false), Bool(LO.Bool), SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
TerseOutput(false), PolishForDeclaration(false) { } Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false),
MSWChar(LO.MicrosoftExt && !LO.WChar) { }
/// \brief What language we're printing. /// \brief What language we're printing.
LangOptions LangOpts; LangOptions LangOpts;
@ -131,6 +132,10 @@ struct PrintingPolicy {
/// ARC. /// ARC.
unsigned SuppressStrongLifetime : 1; unsigned SuppressStrongLifetime : 1;
/// \brief When true, suppress printing of lifetime qualifier in
/// ARC.
unsigned SuppressLifetimeQualifiers : 1;
/// \brief Whether we can use 'bool' rather than '_Bool', even if the language /// \brief Whether we can use 'bool' rather than '_Bool', even if the language
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro). /// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
unsigned Bool : 1; unsigned Bool : 1;
@ -146,6 +151,10 @@ struct PrintingPolicy {
/// declaration tag; such as, do not print attributes attached to the declaration. /// declaration tag; such as, do not print attributes attached to the declaration.
/// ///
unsigned PolishForDeclaration : 1; unsigned PolishForDeclaration : 1;
/// \brief When true, print the built-in wchar_t type as __wchar_t. For use in
/// Microsoft mode when wchar_t is not available.
unsigned MSWChar : 1;
}; };
} // end namespace clang } // end namespace clang

View File

@ -107,12 +107,9 @@ class RawComment {
return RawText; return RawText;
} }
SourceRange getSourceRange() const LLVM_READONLY { SourceRange getSourceRange() const LLVM_READONLY { return Range; }
return Range; SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
} SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
unsigned getBeginLine(const SourceManager &SM) const;
unsigned getEndLine(const SourceManager &SM) const;
const char *getBriefText(const ASTContext &Context) const { const char *getBriefText(const ASTContext &Context) const {
if (BriefTextValid) if (BriefTextValid)
@ -146,11 +143,6 @@ class RawComment {
/// considered as documentation comments. /// considered as documentation comments.
bool ParseAllComments : 1; bool ParseAllComments : 1;
mutable bool BeginLineValid : 1; ///< True if BeginLine is valid
mutable bool EndLineValid : 1; ///< True if EndLine is valid
mutable unsigned BeginLine; ///< Cached line number
mutable unsigned EndLine; ///< Cached line number
/// \brief Constructor for AST deserialization. /// \brief Constructor for AST deserialization.
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment, RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
bool IsAlmostTrailingComment, bool IsAlmostTrailingComment,
@ -158,8 +150,7 @@ class RawComment {
Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K), Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
IsAttached(false), IsTrailingComment(IsTrailingComment), IsAttached(false), IsTrailingComment(IsTrailingComment),
IsAlmostTrailingComment(IsAlmostTrailingComment), IsAlmostTrailingComment(IsAlmostTrailingComment),
ParseAllComments(ParseAllComments), ParseAllComments(ParseAllComments)
BeginLineValid(false), EndLineValid(false)
{ } { }
StringRef getRawTextSlow(const SourceManager &SourceMgr) const; StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
@ -178,8 +169,7 @@ class BeforeThanCompare<RawComment> {
explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { } explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
bool operator()(const RawComment &LHS, const RawComment &RHS) { bool operator()(const RawComment &LHS, const RawComment &RHS) {
return SM.isBeforeInTranslationUnit(LHS.getSourceRange().getBegin(), return SM.isBeforeInTranslationUnit(LHS.getLocStart(), RHS.getLocStart());
RHS.getSourceRange().getBegin());
} }
bool operator()(const RawComment *LHS, const RawComment *RHS) { bool operator()(const RawComment *LHS, const RawComment *RHS) {
@ -191,8 +181,7 @@ class BeforeThanCompare<RawComment> {
/// sorted in order of appearance in the translation unit. /// sorted in order of appearance in the translation unit.
class RawCommentList { class RawCommentList {
public: public:
RawCommentList(SourceManager &SourceMgr) : RawCommentList(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
SourceMgr(SourceMgr), OnlyWhitespaceSeen(true) { }
void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator); void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator);
@ -203,15 +192,9 @@ class RawCommentList {
private: private:
SourceManager &SourceMgr; SourceManager &SourceMgr;
std::vector<RawComment *> Comments; std::vector<RawComment *> Comments;
SourceLocation PrevCommentEndLoc;
bool OnlyWhitespaceSeen;
void addCommentsToFront(const std::vector<RawComment *> &C) { void addCommentsToFront(const std::vector<RawComment *> &C) {
size_t OldSize = Comments.size(); Comments.insert(Comments.begin(), C.begin(), C.end());
Comments.resize(C.size() + OldSize);
std::copy_backward(Comments.begin(), Comments.begin() + OldSize,
Comments.end());
std::copy(C.begin(), C.end(), Comments.begin());
} }
friend class ASTReader; friend class ASTReader;

View File

@ -93,10 +93,22 @@ class ASTRecordLayout {
/// HasOwnVFPtr - Does this class provide a virtual function table /// HasOwnVFPtr - Does this class provide a virtual function table
/// (vtable in Itanium, vftbl in Microsoft) that is independent from /// (vtable in Itanium, vftbl in Microsoft) that is independent from
/// its base classes? /// its base classes?
bool HasOwnVFPtr; // TODO: stash this somewhere more efficient bool HasOwnVFPtr : 1;
/// HasVFPtr - Does this class have a vftable that could be extended by
/// a derived class. The class may have inherited this pointer from
/// a primary base class.
bool HasExtendableVFPtr : 1;
/// AlignAfterVBases - Force appropriate alignment after virtual bases are
/// laid out in MS-C++-ABI.
bool AlignAfterVBases : 1;
/// PrimaryBase - The primary base info for this record. /// PrimaryBase - The primary base info for this record.
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase; llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
/// BaseSharingVBPtr - The base we share vbptr with.
const CXXRecordDecl *BaseSharingVBPtr;
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
@ -122,13 +134,16 @@ class ASTRecordLayout {
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
ASTRecordLayout(const ASTContext &Ctx, ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment, CharUnits size, CharUnits alignment,
bool hasOwnVFPtr, CharUnits vbptroffset, bool hasOwnVFPtr, bool hasExtendableVFPtr,
CharUnits vbptroffset,
CharUnits datasize, CharUnits datasize,
const uint64_t *fieldoffsets, unsigned fieldcount, const uint64_t *fieldoffsets, unsigned fieldcount,
CharUnits nonvirtualsize, CharUnits nonvirtualalign, CharUnits nonvirtualsize, CharUnits nonvirtualalign,
CharUnits SizeOfLargestEmptySubobject, CharUnits SizeOfLargestEmptySubobject,
const CXXRecordDecl *PrimaryBase, const CXXRecordDecl *PrimaryBase,
bool IsPrimaryBaseVirtual, bool IsPrimaryBaseVirtual,
const CXXRecordDecl *BaseSharingVBPtr,
bool ForceAlign,
const BaseOffsetsMapTy& BaseOffsets, const BaseOffsetsMapTy& BaseOffsets,
const VBaseOffsetsMapTy& VBaseOffsets); const VBaseOffsetsMapTy& VBaseOffsets);
@ -226,6 +241,37 @@ class ASTRecordLayout {
return CXXInfo->HasOwnVFPtr; return CXXInfo->HasOwnVFPtr;
} }
/// hasVFPtr - Does this class have a virtual function table pointer
/// that can be extended by a derived class? This is synonymous with
/// this class having a VFPtr at offset zero.
bool hasExtendableVFPtr() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->HasExtendableVFPtr;
}
/// hasOwnVBPtr - Does this class provide its own virtual-base
/// table pointer, rather than inheriting one from a primary base
/// class?
///
/// This implies that the ABI has no primary base class, meaning
/// that it has no base classes that are suitable under the conditions
/// of the ABI.
bool hasOwnVBPtr() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return hasVBPtr() && !CXXInfo->BaseSharingVBPtr;
}
/// hasVBPtr - Does this class have a virtual function table pointer.
bool hasVBPtr() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return !CXXInfo->VBPtrOffset.isNegative();
}
bool getAlignAfterVBases() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->AlignAfterVBases;
}
/// getVBPtrOffset - Get the offset for virtual base table pointer. /// getVBPtrOffset - Get the offset for virtual base table pointer.
/// This is only meaningful with the Microsoft ABI. /// This is only meaningful with the Microsoft ABI.
CharUnits getVBPtrOffset() const { CharUnits getVBPtrOffset() const {
@ -233,6 +279,11 @@ class ASTRecordLayout {
return CXXInfo->VBPtrOffset; return CXXInfo->VBPtrOffset;
} }
const CXXRecordDecl *getBaseSharingVBPtr() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->BaseSharingVBPtr;
}
const VBaseOffsetsMapTy &getVBaseOffsetsMap() const { const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
assert(CXXInfo && "Record layout does not have C++ specific info!"); assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->VBaseOffsets; return CXXInfo->VBaseOffsets;

View File

@ -27,6 +27,7 @@
#include "clang/AST/Stmt.h" #include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h" #include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h" #include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
@ -108,7 +109,7 @@ namespace clang {
/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar /// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar
/// is Foo's super class) before calling VisitFoo(), the result is /// is Foo's super class) before calling VisitFoo(), the result is
/// that the Visit*() methods for a given node are called in the /// that the Visit*() methods for a given node are called in the
/// top-down order (e.g. for a node of type NamedDecl, the order will /// top-down order (e.g. for a node of type NamespaceDecl, the order will
/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()). /// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()).
/// ///
/// This scheme guarantees that all Visit*() calls for the same AST /// This scheme guarantees that all Visit*() calls for the same AST
@ -243,8 +244,16 @@ class RecursiveASTVisitor {
/// \brief Recursively visit a lambda capture. /// \brief Recursively visit a lambda capture.
/// ///
/// \returns false if the visitation was terminated early, true otherwise. /// \returns false if the visitation was terminated early, true otherwise.
bool TraverseLambdaCapture(LambdaExpr::Capture C); bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaExpr::Capture *C);
/// \brief Recursively visit the body of a lambda expression.
///
/// This provides a hook for visitors that need more context when visiting
/// \c LE->getBody().
///
/// \returns false if the visitation was terminated early, true otherwise.
bool TraverseLambdaBody(LambdaExpr *LE);
// ---- Methods on Stmts ---- // ---- Methods on Stmts ----
// Declare Traverse*() for all concrete Stmt classes. // Declare Traverse*() for all concrete Stmt classes.
@ -342,7 +351,7 @@ class RecursiveASTVisitor {
// ---- Methods on TypeLocs ---- // ---- Methods on TypeLocs ----
// FIXME: this currently just calls the matching Type methods // FIXME: this currently just calls the matching Type methods
// Declare Traverse*() for all concrete Type classes. // Declare Traverse*() for all concrete TypeLoc classes.
#define ABSTRACT_TYPELOC(CLASS, BASE) #define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \ #define TYPELOC(CLASS, BASE) \
bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
@ -398,8 +407,12 @@ class RecursiveASTVisitor {
private: private:
// These are helper methods used by more than one Traverse* method. // These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
bool TraverseClassInstantiations(ClassTemplateDecl *D); #define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ; bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D);
DEF_TRAVERSE_TMPL_INST(Class)
DEF_TRAVERSE_TMPL_INST(Var)
DEF_TRAVERSE_TMPL_INST(Function)
#undef DEF_TRAVERSE_TMPL_INST
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
unsigned Count); unsigned Count);
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL); bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
@ -409,6 +422,13 @@ class RecursiveASTVisitor {
bool TraverseDeclContextHelper(DeclContext *DC); bool TraverseDeclContextHelper(DeclContext *DC);
bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseFunctionHelper(FunctionDecl *D);
bool TraverseVarHelper(VarDecl *D); bool TraverseVarHelper(VarDecl *D);
bool TraverseOMPClause(OMPClause *C);
#define OPENMP_CLAUSE(Name, Class) \
bool Visit##Class(Class *C);
#include "clang/Basic/OpenMPKinds.def"
/// \brief Process clauses with list of variables.
template <typename T>
void VisitOMPClauseList(T *Node);
struct EnqueueJob { struct EnqueueJob {
Stmt *S; Stmt *S;
@ -802,10 +822,20 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
} }
template<typename Derived> template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){ bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(
LambdaExpr *LE, const LambdaExpr::Capture *C) {
if (C->isInitCapture())
TRY_TO(TraverseDecl(C->getCapturedVar()));
return true; return true;
} }
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
TRY_TO(TraverseStmt(LE->getBody()));
return true;
}
// ----------------- Type traversal ----------------- // ----------------- Type traversal -----------------
// This macro makes available a variable T, the passed-in type. // This macro makes available a variable T, the passed-in type.
@ -844,6 +874,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, {
TRY_TO(TraverseType(T->getPointeeType())); TRY_TO(TraverseType(T->getPointeeType()));
}) })
DEF_TRAVERSE_TYPE(DecayedType, {
TRY_TO(TraverseType(T->getOriginalType()));
})
DEF_TRAVERSE_TYPE(ConstantArrayType, { DEF_TRAVERSE_TYPE(ConstantArrayType, {
TRY_TO(TraverseType(T->getElementType())); TRY_TO(TraverseType(T->getElementType()));
}) })
@ -1050,6 +1084,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, {
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
}) })
DEF_TRAVERSE_TYPELOC(DecayedType, {
TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
})
template<typename Derived> template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
// This isn't available for ArrayType, but is for the ArrayTypeLoc. // This isn't available for ArrayType, but is for the ArrayTypeLoc.
@ -1420,59 +1458,44 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
return true; return true;
} }
// A helper method for traversing the implicit instantiations of a #define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
// class template. /* A helper method for traversing the implicit instantiations of a
template<typename Derived> class or variable template. */ \
bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations( template<typename Derived> \
ClassTemplateDecl *D) { bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations( \
ClassTemplateDecl::spec_iterator end = D->spec_end(); TMPLDECLKIND##TemplateDecl *D) { \
for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) { TMPLDECLKIND##TemplateDecl::spec_iterator end = D->spec_end(); \
ClassTemplateSpecializationDecl* SD = *it; for (TMPLDECLKIND##TemplateDecl::spec_iterator it = D->spec_begin(); \
it != end; ++it) { \
switch (SD->getSpecializationKind()) { TMPLDECLKIND##TemplateSpecializationDecl* SD = *it; \
// Visit the implicit instantiations with the requested pattern. \
case TSK_Undeclared: switch (SD->getSpecializationKind()) { \
case TSK_ImplicitInstantiation: /* Visit the implicit instantiations with the requested pattern. */ \
TRY_TO(TraverseDecl(SD)); case TSK_Undeclared: \
break; case TSK_ImplicitInstantiation: \
TRY_TO(TraverseDecl(SD)); \
// We don't need to do anything on an explicit instantiation break; \
// or explicit specialization because there will be an explicit \
// node for it elsewhere. /* We don't need to do anything on an explicit instantiation
case TSK_ExplicitInstantiationDeclaration: or explicit specialization because there will be an explicit
case TSK_ExplicitInstantiationDefinition: node for it elsewhere. */ \
case TSK_ExplicitSpecialization: case TSK_ExplicitInstantiationDeclaration: \
break; case TSK_ExplicitInstantiationDefinition: \
} case TSK_ExplicitSpecialization: \
} break; \
} \
return true; } \
\
return true; \
} }
DEF_TRAVERSE_DECL(ClassTemplateDecl, { DEF_TRAVERSE_TMPL_INST(Class)
CXXRecordDecl* TempDecl = D->getTemplatedDecl(); DEF_TRAVERSE_TMPL_INST(Var)
TRY_TO(TraverseDecl(TempDecl));
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
// By default, we do not traverse the instantiations of
// class templates since they do not appear in the user code. The
// following code optionally traverses them.
//
// We only traverse the class instantiations when we see the canonical
// declaration of the template, to ensure we only visit them once.
if (getDerived().shouldVisitTemplateInstantiations() &&
D == D->getCanonicalDecl())
TRY_TO(TraverseClassInstantiations(D));
// Note that getInstantiatedFromMemberTemplate() is just a link
// from a template instantiation back to the template from which
// it was instantiated, and thus should not be traversed.
})
// A helper method for traversing the instantiations of a // A helper method for traversing the instantiations of a
// function while skipping its specializations. // function while skipping its specializations.
template<typename Derived> template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations( bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
FunctionTemplateDecl *D) { FunctionTemplateDecl *D) {
FunctionTemplateDecl::spec_iterator end = D->spec_end(); FunctionTemplateDecl::spec_iterator end = D->spec_end();
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end; for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
@ -1500,21 +1523,32 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
return true; return true;
} }
DEF_TRAVERSE_DECL(FunctionTemplateDecl, { // This macro unifies the traversal of class, variable and function
TRY_TO(TraverseDecl(D->getTemplatedDecl())); // template declarations.
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); #define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \
// By default, we do not traverse the instantiations of TRY_TO(TraverseDecl(D->getTemplatedDecl())); \
// function templates since they do not appear in the user code. The TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
// following code optionally traverses them. \
// /* By default, we do not traverse the instantiations of
// We only traverse the function instantiations when we see the canonical class templates since they do not appear in the user code. The
// declaration of the template, to ensure we only visit them once. following code optionally traverses them.
if (getDerived().shouldVisitTemplateInstantiations() &&
D == D->getCanonicalDecl()) We only traverse the class instantiations when we see the canonical
TRY_TO(TraverseFunctionInstantiations(D)); declaration of the template, to ensure we only visit them once. */ \
if (getDerived().shouldVisitTemplateInstantiations() && \
D == D->getCanonicalDecl()) \
TRY_TO(TraverseTemplateInstantiations(D)); \
\
/* Note that getInstantiatedFromMemberTemplate() is just a link
from a template instantiation back to the template from which
it was instantiated, and thus should not be traversed. */ \
}) })
DEF_TRAVERSE_TMPL_DECL(Class)
DEF_TRAVERSE_TMPL_DECL(Var)
DEF_TRAVERSE_TMPL_DECL(Function)
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, { DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
// D is the "T" in something like // D is the "T" in something like
// template <template <typename> class T> class container { }; // template <template <typename> class T> class container { };
@ -1607,27 +1641,31 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, {
TRY_TO(TraverseCXXRecordHelper(D)); TRY_TO(TraverseCXXRecordHelper(D));
}) })
DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, { #define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND) \
// For implicit instantiations ("set<int> x;"), we don't want to DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
// recurse at all, since the instatiated class isn't written in /* For implicit instantiations ("set<int> x;"), we don't want to
// the source code anywhere. (Note the instatiated *type* -- recurse at all, since the instatiated template isn't written in
// set<int> -- is written, and will still get a callback of the source code anywhere. (Note the instatiated *type* --
// TemplateSpecializationType). For explicit instantiations set<int> -- is written, and will still get a callback of
// ("template set<int>;"), we do need a callback, since this TemplateSpecializationType). For explicit instantiations
// is the only callback that's made for this instantiation. ("template set<int>;"), we do need a callback, since this
// We use getTypeAsWritten() to distinguish. is the only callback that's made for this instantiation.
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) We use getTypeAsWritten() to distinguish. */ \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
if (!getDerived().shouldVisitTemplateInstantiations() && \
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) if (!getDerived().shouldVisitTemplateInstantiations() && \
// Returning from here skips traversing the D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \
// declaration context of the ClassTemplateSpecializationDecl /* Returning from here skips traversing the
// (embedded in the DEF_TRAVERSE_DECL() macro) declaration context of the *TemplateSpecializationDecl
// which contains the instantiated members of the class. (embedded in the DEF_TRAVERSE_DECL() macro)
return true; which contains the instantiated members of the template. */ \
return true; \
}) })
DEF_TRAVERSE_TMPL_SPEC_DECL(Class)
DEF_TRAVERSE_TMPL_SPEC_DECL(Var)
template <typename Derived> template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper( bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
const TemplateArgumentLoc *TAL, unsigned Count) { const TemplateArgumentLoc *TAL, unsigned Count) {
@ -1637,26 +1675,31 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
return true; return true;
} }
DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, { #define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
// The partial specialization. DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
if (TemplateParameterList *TPL = D->getTemplateParameters()) { /* The partial specialization. */ \
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); if (TemplateParameterList *TPL = D->getTemplateParameters()) { \
I != E; ++I) { for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \
TRY_TO(TraverseDecl(*I)); I != E; ++I) { \
} TRY_TO(TraverseDecl(*I)); \
} } \
// The args that remains unspecialized. } \
TRY_TO(TraverseTemplateArgumentLocsHelper( /* The args that remains unspecialized. */ \
D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten())); TRY_TO(TraverseTemplateArgumentLocsHelper( \
D->getTemplateArgsAsWritten()->getTemplateArgs(), \
// Don't need the ClassTemplatePartialSpecializationHelper, even D->getTemplateArgsAsWritten()->NumTemplateArgs)); \
// though that's our parent class -- we already visit all the \
// template args here. /* Don't need the *TemplatePartialSpecializationHelper, even
TRY_TO(TraverseCXXRecordHelper(D)); though that's our parent class -- we already visit all the
template args here. */ \
// Instantiations will have been visited with the primary template. TRY_TO(Traverse##DECLKIND##Helper(D)); \
\
/* Instantiations will have been visited with the primary template. */ \
}) })
DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Class, CXXRecord)
DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Var, Var)
DEF_TRAVERSE_DECL(EnumConstantDecl, { DEF_TRAVERSE_DECL(EnumConstantDecl, {
TRY_TO(TraverseStmt(D->getInitExpr())); TRY_TO(TraverseStmt(D->getInitExpr()));
}) })
@ -1736,6 +1779,14 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
// including exception specifications. // including exception specifications.
if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) { if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
} else if (getDerived().shouldVisitImplicitCode()) {
// Visit parameter variable declarations of the implicit function
// if the traverser is visiting implicit code. Parameter variable
// declarations do not have valid TypeSourceInfo, so to visit them
// we need to traverse the declarations explicitly.
for (FunctionDecl::param_const_iterator I = D->param_begin(),
E = D->param_end(); I != E; ++I)
TRY_TO(TraverseDecl(*I));
} }
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
@ -2117,10 +2168,12 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
// Walk only the visible parts of lambda expressions. // Walk only the visible parts of lambda expressions.
template<typename Derived> template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
TRY_TO(WalkUpFromLambdaExpr(S));
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
CEnd = S->explicit_capture_end(); CEnd = S->explicit_capture_end();
C != CEnd; ++C) { C != CEnd; ++C) {
TRY_TO(TraverseLambdaCapture(*C)); TRY_TO(TraverseLambdaCapture(S, C));
} }
if (S->hasExplicitParameters() || S->hasExplicitResultType()) { if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
@ -2140,7 +2193,7 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
} }
} }
TRY_TO(TraverseStmt(S->getBody())); TRY_TO(TraverseLambdaBody(S));
return true; return true;
} }
@ -2174,6 +2227,7 @@ DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { }) DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { }) DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { }) DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, { })
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo()) if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
@ -2211,6 +2265,7 @@ DEF_TRAVERSE_STMT(ParenExpr, { })
DEF_TRAVERSE_STMT(ParenListExpr, { }) DEF_TRAVERSE_STMT(ParenListExpr, { })
DEF_TRAVERSE_STMT(PredefinedExpr, { }) DEF_TRAVERSE_STMT(PredefinedExpr, { })
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { }) DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
DEF_TRAVERSE_STMT(ConvertVectorExpr, { })
DEF_TRAVERSE_STMT(StmtExpr, { }) DEF_TRAVERSE_STMT(StmtExpr, { })
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
@ -2269,6 +2324,61 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
// Traverse OpenCL: AsType, Convert. // Traverse OpenCL: AsType, Convert.
DEF_TRAVERSE_STMT(AsTypeExpr, { }) DEF_TRAVERSE_STMT(AsTypeExpr, { })
// OpenMP directives.
DEF_TRAVERSE_STMT(OMPParallelDirective, {
ArrayRef<OMPClause *> Clauses = S->clauses();
for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
I != E; ++I)
if (!TraverseOMPClause(*I)) return false;
})
// OpenMP clauses.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
if (!C) return true;
switch (C->getClauseKind()) {
#define OPENMP_CLAUSE(Name, Class) \
case OMPC_##Name: \
return getDerived().Visit##Class(static_cast<Class*>(C));
#include "clang/Basic/OpenMPKinds.def"
default: break;
}
return true;
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPDefaultClause(OMPDefaultClause *C) {
return true;
}
template<typename Derived>
template<typename T>
void RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {
for (typename T::varlist_iterator I = Node->varlist_begin(),
E = Node->varlist_end();
I != E; ++I)
TraverseStmt(*I);
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
VisitOMPClauseList(C);
return true;
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
return true;
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
VisitOMPClauseList(C);
return true;
}
// FIXME: look at the following tricky-seeming exprs to see if we // FIXME: look at the following tricky-seeming exprs to see if we
// need to recurse on anything. These are ones that have methods // need to recurse on anything. These are ones that have methods
// returning decls or qualtypes or nestednamespecifier -- though I'm // returning decls or qualtypes or nestednamespecifier -- though I'm

View File

@ -75,7 +75,7 @@ class Redeclarable {
/// \brief Return the first declaration of this declaration or itself if this /// \brief Return the first declaration of this declaration or itself if this
/// is the only declaration. /// is the only declaration.
decl_type *getFirstDeclaration() { decl_type *getFirstDecl() {
decl_type *D = static_cast<decl_type*>(this); decl_type *D = static_cast<decl_type*>(this);
while (D->getPreviousDecl()) while (D->getPreviousDecl())
D = D->getPreviousDecl(); D = D->getPreviousDecl();
@ -84,31 +84,29 @@ class Redeclarable {
/// \brief Return the first declaration of this declaration or itself if this /// \brief Return the first declaration of this declaration or itself if this
/// is the only declaration. /// is the only declaration.
const decl_type *getFirstDeclaration() const { const decl_type *getFirstDecl() const {
const decl_type *D = static_cast<const decl_type*>(this); const decl_type *D = static_cast<const decl_type*>(this);
while (D->getPreviousDecl()) while (D->getPreviousDecl())
D = D->getPreviousDecl(); D = D->getPreviousDecl();
return D; return D;
} }
/// \brief Returns true if this is the first declaration. /// \brief True if this is the first declaration in its redeclaration chain.
bool isFirstDeclaration() const { bool isFirstDecl() const { return RedeclLink.NextIsLatest(); }
return RedeclLink.NextIsLatest();
}
/// \brief Returns the most recent (re)declaration of this declaration. /// \brief Returns the most recent (re)declaration of this declaration.
decl_type *getMostRecentDecl() { decl_type *getMostRecentDecl() {
return getFirstDeclaration()->RedeclLink.getNext(); return getFirstDecl()->RedeclLink.getNext();
} }
/// \brief Returns the most recent (re)declaration of this declaration. /// \brief Returns the most recent (re)declaration of this declaration.
const decl_type *getMostRecentDecl() const { const decl_type *getMostRecentDecl() const {
return getFirstDeclaration()->RedeclLink.getNext(); return getFirstDecl()->RedeclLink.getNext();
} }
/// \brief Set the previous declaration. If PrevDecl is NULL, set this as the /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
/// first and only declaration. /// first and only declaration.
void setPreviousDeclaration(decl_type *PrevDecl); void setPreviousDecl(decl_type *PrevDecl);
/// \brief Iterates through all the redeclarations of the same decl. /// \brief Iterates through all the redeclarations of the same decl.
class redecl_iterator { class redecl_iterator {
@ -134,7 +132,7 @@ class Redeclarable {
redecl_iterator& operator++() { redecl_iterator& operator++() {
assert(Current && "Advancing while iterator has reached end"); assert(Current && "Advancing while iterator has reached end");
// Sanity check to avoid infinite loop on invalid redecl chain. // Sanity check to avoid infinite loop on invalid redecl chain.
if (Current->isFirstDeclaration()) { if (Current->isFirstDecl()) {
if (PassedFirst) { if (PassedFirst) {
assert(0 && "Passed first decl twice, invalid redecl chain!"); assert(0 && "Passed first decl twice, invalid redecl chain!");
Current = 0; Current = 0;
@ -175,6 +173,40 @@ class Redeclarable {
friend class ASTDeclWriter; friend class ASTDeclWriter;
}; };
/// \brief Get the primary declaration for a declaration from an AST file. That
/// will be the first-loaded declaration.
Decl *getPrimaryMergedDecl(Decl *D);
/// \brief Provides common interface for the Decls that cannot be redeclared,
/// but can be merged if the same declaration is brought in from multiple
/// modules.
template<typename decl_type>
class Mergeable {
public:
Mergeable() {}
/// \brief Return the first declaration of this declaration or itself if this
/// is the only declaration.
decl_type *getFirstDecl() {
decl_type *D = static_cast<decl_type*>(this);
if (!D->isFromASTFile())
return D;
return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D)));
}
/// \brief Return the first declaration of this declaration or itself if this
/// is the only declaration.
const decl_type *getFirstDecl() const {
const decl_type *D = static_cast<const decl_type*>(this);
if (!D->isFromASTFile())
return D;
return cast<decl_type>(getPrimaryMergedDecl(const_cast<decl_type*>(D)));
}
/// \brief Returns true if this is the first declaration.
bool isFirstDecl() const { return getFirstDecl() == this; }
};
} }
#endif #endif

View File

@ -266,10 +266,6 @@ class Stmt {
/// Whether this initializer list originally had a GNU array-range /// Whether this initializer list originally had a GNU array-range
/// designator in it. This is a temporary marker used by CodeGen. /// designator in it. This is a temporary marker used by CodeGen.
unsigned HadArrayRangeDesignator : 1; unsigned HadArrayRangeDesignator : 1;
/// Whether this initializer list initializes a std::initializer_list
/// object.
unsigned InitializesStdInitializerList : 1;
}; };
class TypeTraitExprBitfields { class TypeTraitExprBitfields {
@ -289,7 +285,7 @@ class Stmt {
/// \brief The number of arguments to this type trait. /// \brief The number of arguments to this type trait.
unsigned NumArgs : 32 - 8 - 1 - NumExprBits; unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
}; };
union { union {
// FIXME: this is wasteful on 64-bit platforms. // FIXME: this is wasteful on 64-bit platforms.
void *Aligner; void *Aligner;
@ -316,19 +312,21 @@ class Stmt {
public: public:
// Only allow allocation of Stmts using the allocator in ASTContext // Only allow allocation of Stmts using the allocator in ASTContext
// or by doing a placement new. // or by doing a placement new.
void* operator new(size_t bytes, ASTContext& C, void* operator new(size_t bytes, const ASTContext& C,
unsigned alignment = 8) throw(); unsigned alignment = 8);
void* operator new(size_t bytes, ASTContext* C, void* operator new(size_t bytes, const ASTContext* C,
unsigned alignment = 8) throw(); unsigned alignment = 8) {
return operator new(bytes, *C, alignment);
}
void* operator new(size_t bytes, void* mem) throw() { void* operator new(size_t bytes, void* mem) throw() {
return mem; return mem;
} }
void operator delete(void*, ASTContext&, unsigned) throw() { } void operator delete(void*, const ASTContext&, unsigned) throw() { }
void operator delete(void*, ASTContext*, unsigned) throw() { } void operator delete(void*, const ASTContext*, unsigned) throw() { }
void operator delete(void*, std::size_t) throw() { } void operator delete(void*, size_t) throw() { }
void operator delete(void*, void*) throw() { } void operator delete(void*, void*) throw() { }
public: public:
@ -382,7 +380,7 @@ class Stmt {
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
/// back to its original source language syntax. /// back to its original source language syntax.
void dumpPretty(ASTContext &Context) const; void dumpPretty(const ASTContext &Context) const;
void printPretty(raw_ostream &OS, PrinterHelper *Helper, void printPretty(raw_ostream &OS, PrinterHelper *Helper,
const PrintingPolicy &Policy, const PrintingPolicy &Policy,
unsigned Indentation = 0) const; unsigned Indentation = 0) const;
@ -401,13 +399,6 @@ class Stmt {
const_cast<const Stmt*>(this)->stripLabelLikeStatements()); const_cast<const Stmt*>(this)->stripLabelLikeStatements());
} }
/// hasImplicitControlFlow - Some statements (e.g. short circuited operations)
/// contain implicit control-flow in the order their subexpressions
/// are evaluated. This predicate returns true if this statement has
/// such implicit control-flow. Such statements are also specially handled
/// within CFGs.
bool hasImplicitControlFlow() const;
/// Child Iterators: All subclasses must implement 'children' /// Child Iterators: All subclasses must implement 'children'
/// to permit easy iteration over the substatements/subexpessions of an /// to permit easy iteration over the substatements/subexpessions of an
/// AST node. This permits easy iteration over all nodes in the AST. /// AST node. This permits easy iteration over all nodes in the AST.
@ -553,10 +544,10 @@ class CompoundStmt : public Stmt {
Stmt** Body; Stmt** Body;
SourceLocation LBracLoc, RBracLoc; SourceLocation LBracLoc, RBracLoc;
public: public:
CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts, CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB); SourceLocation LB, SourceLocation RB);
// \brief Build an empty compound statment with a location. // \brief Build an empty compound statement with a location.
explicit CompoundStmt(SourceLocation Loc) explicit CompoundStmt(SourceLocation Loc)
: Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) { : Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) {
CompoundStmtBits.NumStmts = 0; CompoundStmtBits.NumStmts = 0;
@ -568,7 +559,7 @@ class CompoundStmt : public Stmt {
CompoundStmtBits.NumStmts = 0; CompoundStmtBits.NumStmts = 0;
} }
void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts); void setStmts(const ASTContext &C, Stmt **Stmts, unsigned NumStmts);
bool body_empty() const { return CompoundStmtBits.NumStmts == 0; } bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
unsigned size() const { return CompoundStmtBits.NumStmts; } unsigned size() const { return CompoundStmtBits.NumStmts; }
@ -827,10 +818,10 @@ class AttributedStmt : public Stmt {
} }
public: public:
static AttributedStmt *Create(ASTContext &C, SourceLocation Loc, static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc,
ArrayRef<const Attr*> Attrs, Stmt *SubStmt); ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
// \brief Build an empty attributed statement. // \brief Build an empty attributed statement.
static AttributedStmt *CreateEmpty(ASTContext &C, unsigned NumAttrs); static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs);
SourceLocation getAttrLoc() const { return AttrLoc; } SourceLocation getAttrLoc() const { return AttrLoc; }
ArrayRef<const Attr*> getAttrs() const { ArrayRef<const Attr*> getAttrs() const {
@ -860,7 +851,7 @@ class IfStmt : public Stmt {
SourceLocation ElseLoc; SourceLocation ElseLoc;
public: public:
IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0); Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
/// \brief Build an empty if/then/else statement /// \brief Build an empty if/then/else statement
@ -875,7 +866,7 @@ class IfStmt : public Stmt {
/// } /// }
/// \endcode /// \endcode
VarDecl *getConditionVariable() const; VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V); void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this IfStmt has a condition variable, return the faux DeclStmt /// If this IfStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable. /// associated with the creation of that condition variable.
@ -933,7 +924,7 @@ class SwitchStmt : public Stmt {
unsigned AllEnumCasesCovered : 1; unsigned AllEnumCasesCovered : 1;
public: public:
SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond); SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
/// \brief Build a empty switch statement. /// \brief Build a empty switch statement.
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
@ -948,7 +939,7 @@ class SwitchStmt : public Stmt {
/// } /// }
/// \endcode /// \endcode
VarDecl *getConditionVariable() const; VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V); void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this SwitchStmt has a condition variable, return the faux DeclStmt /// If this SwitchStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable. /// associated with the creation of that condition variable.
@ -967,9 +958,6 @@ class SwitchStmt : public Stmt {
SwitchCase *getSwitchCaseList() { return FirstCase; } SwitchCase *getSwitchCaseList() { return FirstCase; }
/// \brief Set the case list for this switch statement. /// \brief Set the case list for this switch statement.
///
/// The caller is responsible for incrementing the retain counts on
/// all of the SwitchCase statements in this list.
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
SourceLocation getSwitchLoc() const { return SwitchLoc; } SourceLocation getSwitchLoc() const { return SwitchLoc; }
@ -1021,7 +1009,7 @@ class WhileStmt : public Stmt {
Stmt* SubExprs[END_EXPR]; Stmt* SubExprs[END_EXPR];
SourceLocation WhileLoc; SourceLocation WhileLoc;
public: public:
WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL); SourceLocation WL);
/// \brief Build an empty while statement. /// \brief Build an empty while statement.
@ -1036,7 +1024,7 @@ class WhileStmt : public Stmt {
/// } /// }
/// \endcode /// \endcode
VarDecl *getConditionVariable() const; VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V); void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this WhileStmt has a condition variable, return the faux DeclStmt /// If this WhileStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable. /// associated with the creation of that condition variable.
@ -1129,8 +1117,9 @@ class ForStmt : public Stmt {
SourceLocation LParenLoc, RParenLoc; SourceLocation LParenLoc, RParenLoc;
public: public:
ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP); Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
SourceLocation RP);
/// \brief Build an empty for statement. /// \brief Build an empty for statement.
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
@ -1146,7 +1135,7 @@ class ForStmt : public Stmt {
/// } /// }
/// \endcode /// \endcode
VarDecl *getConditionVariable() const; VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V); void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this ForStmt has a condition variable, return the faux DeclStmt /// If this ForStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable. /// associated with the creation of that condition variable.
@ -1417,7 +1406,7 @@ class AsmStmt : public Stmt {
//===--- Asm String Analysis ---===// //===--- Asm String Analysis ---===//
/// Assemble final IR asm string. /// Assemble final IR asm string.
std::string generateAsmString(ASTContext &C) const; std::string generateAsmString(const ASTContext &C) const;
//===--- Output operands ---===// //===--- Output operands ---===//
@ -1520,7 +1509,7 @@ class GCCAsmStmt : public AsmStmt {
friend class ASTStmtReader; friend class ASTStmtReader;
public: public:
GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
bool isvolatile, unsigned numoutputs, unsigned numinputs, bool isvolatile, unsigned numoutputs, unsigned numinputs,
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
StringLiteral *asmstr, unsigned numclobbers, StringLiteral *asmstr, unsigned numclobbers,
@ -1586,10 +1575,10 @@ class GCCAsmStmt : public AsmStmt {
/// translation of strings from GCC syntax to LLVM IR syntax, and handles /// translation of strings from GCC syntax to LLVM IR syntax, and handles
//// flattening of named references like %[foo] to Operand AsmStringPiece's. //// flattening of named references like %[foo] to Operand AsmStringPiece's.
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces, unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
ASTContext &C, unsigned &DiagOffs) const; const ASTContext &C, unsigned &DiagOffs) const;
/// Assemble final IR asm string. /// Assemble final IR asm string.
std::string generateAsmString(ASTContext &C) const; std::string generateAsmString(const ASTContext &C) const;
//===--- Output operands ---===// //===--- Output operands ---===//
@ -1649,7 +1638,7 @@ class GCCAsmStmt : public AsmStmt {
} }
private: private:
void setOutputsAndInputsAndClobbers(ASTContext &C, void setOutputsAndInputsAndClobbers(const ASTContext &C,
IdentifierInfo **Names, IdentifierInfo **Names,
StringLiteral **Constraints, StringLiteral **Constraints,
Stmt **Exprs, Stmt **Exprs,
@ -1695,9 +1684,9 @@ class MSAsmStmt : public AsmStmt {
friend class ASTStmtReader; friend class ASTStmtReader;
public: public:
MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
bool issimple, bool isvolatile, ArrayRef<Token> asmtoks, SourceLocation lbraceloc, bool issimple, bool isvolatile,
unsigned numoutputs, unsigned numinputs, ArrayRef<Token> asmtoks, unsigned numoutputs, unsigned numinputs,
ArrayRef<StringRef> constraints, ArrayRef<StringRef> constraints,
ArrayRef<Expr*> exprs, StringRef asmstr, ArrayRef<Expr*> exprs, StringRef asmstr,
ArrayRef<StringRef> clobbers, SourceLocation endloc); ArrayRef<StringRef> clobbers, SourceLocation endloc);
@ -1720,7 +1709,7 @@ class MSAsmStmt : public AsmStmt {
StringRef getAsmString() const { return AsmStr; } StringRef getAsmString() const { return AsmStr; }
/// Assemble final IR asm string. /// Assemble final IR asm string.
std::string generateAsmString(ASTContext &C) const; std::string generateAsmString(const ASTContext &C) const;
//===--- Output operands ---===// //===--- Output operands ---===//
@ -1765,12 +1754,9 @@ class MSAsmStmt : public AsmStmt {
StringRef getClobber(unsigned i) const { return getClobbers()[i]; } StringRef getClobber(unsigned i) const { return getClobbers()[i]; }
private: private:
void initialize(ASTContext &C, void initialize(const ASTContext &C, StringRef AsmString,
StringRef AsmString, ArrayRef<Token> AsmToks, ArrayRef<StringRef> Constraints,
ArrayRef<Token> AsmToks, ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers);
ArrayRef<StringRef> Constraints,
ArrayRef<Expr*> Exprs,
ArrayRef<StringRef> Clobbers);
public: public:
SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; } SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
@ -1800,7 +1786,7 @@ class SEHExceptStmt : public Stmt {
explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { } explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { }
public: public:
static SEHExceptStmt* Create(ASTContext &C, static SEHExceptStmt* Create(const ASTContext &C,
SourceLocation ExceptLoc, SourceLocation ExceptLoc,
Expr *FilterExpr, Expr *FilterExpr,
Stmt *Block); Stmt *Block);
@ -1841,7 +1827,7 @@ class SEHFinallyStmt : public Stmt {
explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { } explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { }
public: public:
static SEHFinallyStmt* Create(ASTContext &C, static SEHFinallyStmt* Create(const ASTContext &C,
SourceLocation FinallyLoc, SourceLocation FinallyLoc,
Stmt *Block); Stmt *Block);
@ -1880,10 +1866,8 @@ class SEHTryStmt : public Stmt {
explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { } explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { }
public: public:
static SEHTryStmt* Create(ASTContext &C, static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry,
bool isCXXTry, SourceLocation TryLoc, Stmt *TryBlock,
SourceLocation TryLoc,
Stmt *TryBlock,
Stmt *Handler); Stmt *Handler);
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); } SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
@ -2006,13 +1990,13 @@ class CapturedStmt : public Stmt {
void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; } void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; }
public: public:
static CapturedStmt *Create(ASTContext &Context, Stmt *S, static CapturedStmt *Create(const ASTContext &Context, Stmt *S,
CapturedRegionKind Kind, CapturedRegionKind Kind,
ArrayRef<Capture> Captures, ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits, ArrayRef<Expr *> CaptureInits,
CapturedDecl *CD, RecordDecl *RD); CapturedDecl *CD, RecordDecl *RD);
static CapturedStmt *CreateDeserialized(ASTContext &Context, static CapturedStmt *CreateDeserialized(const ASTContext &Context,
unsigned NumCaptures); unsigned NumCaptures);
/// \brief Retrieve the statement being captured. /// \brief Retrieve the statement being captured.

View File

@ -79,10 +79,10 @@ class CXXTryStmt : public Stmt {
} }
public: public:
static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc, static CXXTryStmt *Create(const ASTContext &C, SourceLocation tryLoc,
Stmt *tryBlock, ArrayRef<Stmt*> handlers); Stmt *tryBlock, ArrayRef<Stmt*> handlers);
static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty, static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty,
unsigned numHandlers); unsigned numHandlers);
SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); } SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }

View File

@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_STMT_ITR_H #define LLVM_CLANG_AST_STMT_ITR_H
#include "llvm/Support/DataTypes.h" #include "llvm/Support/DataTypes.h"
#include "llvm/Support/Compiler.h"
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iterator> #include <iterator>
@ -28,18 +29,14 @@ class VariableArrayType;
class StmtIteratorBase { class StmtIteratorBase {
protected: protected:
enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3, enum { StmtMode = 0x0, SizeOfTypeVAMode = 0x1, DeclGroupMode = 0x2,
Flags = 0x3 }; Flags = 0x3 };
Stmt **stmt; Stmt **stmt;
union { Decl *decl; Decl **DGI; }; Decl **DGI;
uintptr_t RawVAPtr; uintptr_t RawVAPtr;
Decl **DGE; Decl **DGE;
bool inDecl() const {
return (RawVAPtr & Flags) == DeclMode;
}
bool inDeclGroup() const { bool inDeclGroup() const {
return (RawVAPtr & Flags) == DeclGroupMode; return (RawVAPtr & Flags) == DeclGroupMode;
} }
@ -49,7 +46,7 @@ class StmtIteratorBase {
} }
bool inStmt() const { bool inStmt() const {
return (RawVAPtr & Flags) == 0; return (RawVAPtr & Flags) == StmtMode;
} }
const VariableArrayType *getVAPtr() const { const VariableArrayType *getVAPtr() const {
@ -57,7 +54,7 @@ class StmtIteratorBase {
} }
void setVAPtr(const VariableArrayType *P) { void setVAPtr(const VariableArrayType *P) {
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); assert (inDeclGroup() || inSizeOfTypeVA());
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags); RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
} }
@ -67,11 +64,10 @@ class StmtIteratorBase {
Stmt*& GetDeclExpr() const; Stmt*& GetDeclExpr() const;
StmtIteratorBase(Stmt **s) : stmt(s), decl(0), RawVAPtr(0) {} StmtIteratorBase(Stmt **s) : stmt(s), DGI(0), RawVAPtr(0) {}
StmtIteratorBase(Decl *d, Stmt **s);
StmtIteratorBase(const VariableArrayType *t); StmtIteratorBase(const VariableArrayType *t);
StmtIteratorBase(Decl **dgi, Decl **dge); StmtIteratorBase(Decl **dgi, Decl **dge);
StmtIteratorBase() : stmt(0), decl(0), RawVAPtr(0) {} StmtIteratorBase() : stmt(0), DGI(0), RawVAPtr(0) {}
}; };
@ -86,7 +82,6 @@ class StmtIteratorImpl : public StmtIteratorBase,
StmtIteratorImpl() {} StmtIteratorImpl() {}
StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {} StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {}
StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {} StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {}
StmtIteratorImpl(Decl *d, Stmt **s) : StmtIteratorBase(d, s) {}
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {} StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
DERIVED& operator++() { DERIVED& operator++() {
@ -107,15 +102,15 @@ class StmtIteratorImpl : public StmtIteratorBase,
} }
bool operator==(const DERIVED& RHS) const { bool operator==(const DERIVED& RHS) const {
return stmt == RHS.stmt && decl == RHS.decl && RawVAPtr == RHS.RawVAPtr; return stmt == RHS.stmt && DGI == RHS.DGI && RawVAPtr == RHS.RawVAPtr;
} }
bool operator!=(const DERIVED& RHS) const { bool operator!=(const DERIVED& RHS) const {
return stmt != RHS.stmt || decl != RHS.decl || RawVAPtr != RHS.RawVAPtr; return stmt != RHS.stmt || DGI != RHS.DGI || RawVAPtr != RHS.RawVAPtr;
} }
REFERENCE operator*() const { REFERENCE operator*() const {
return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr()); return inStmt() ? *stmt : GetDeclExpr();
} }
REFERENCE operator->() const { return operator*(); } REFERENCE operator->() const { return operator*(); }
@ -131,9 +126,6 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
StmtIterator(const VariableArrayType *t) StmtIterator(const VariableArrayType *t)
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} : StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
StmtIterator(Decl* D, Stmt **s = 0)
: StmtIteratorImpl<StmtIterator,Stmt*&>(D, s) {}
}; };
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
@ -156,7 +148,7 @@ struct StmtRange : std::pair<StmtIterator,StmtIterator> {
: std::pair<StmtIterator,StmtIterator>(begin, end) {} : std::pair<StmtIterator,StmtIterator>(begin, end) {}
bool empty() const { return first == second; } bool empty() const { return first == second; }
operator bool() const { return !empty(); } LLVM_EXPLICIT operator bool() const { return !empty(); }
Stmt *operator->() const { return first.operator->(); } Stmt *operator->() const { return first.operator->(); }
Stmt *&operator*() const { return first.operator*(); } Stmt *&operator*() const { return first.operator*(); }
@ -199,7 +191,7 @@ struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {} : std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
bool empty() const { return first == second; } bool empty() const { return first == second; }
operator bool() const { return !empty(); } LLVM_EXPLICIT operator bool() const { return !empty(); }
const Stmt *operator->() const { return first.operator->(); } const Stmt *operator->() const { return first.operator->(); }
const Stmt *operator*() const { return first.operator*(); } const Stmt *operator*() const { return first.operator*(); }

View File

@ -181,13 +181,12 @@ class ObjCAtTryStmt : public Stmt {
HasFinally(HasFinally) { } HasFinally(HasFinally) { }
public: public:
static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc, static ObjCAtTryStmt *Create(const ASTContext &Context,
Stmt *atTryStmt, SourceLocation atTryLoc, Stmt *atTryStmt,
Stmt **CatchStmts, unsigned NumCatchStmts, Stmt **CatchStmts, unsigned NumCatchStmts,
Stmt *atFinallyStmt); Stmt *atFinallyStmt);
static ObjCAtTryStmt *CreateEmpty(ASTContext &Context, static ObjCAtTryStmt *CreateEmpty(const ASTContext &Context,
unsigned NumCatchStmts, unsigned NumCatchStmts, bool HasFinally);
bool HasFinally);
/// \brief Retrieve the location of the @ in the \@try. /// \brief Retrieve the location of the @ in the \@try.
SourceLocation getAtTryLoc() const { return AtTryLoc; } SourceLocation getAtTryLoc() const { return AtTryLoc; }

Some files were not shown because too many files have changed in this diff Show More