Import clang r309604 from branches/release_50
This commit is contained in:
parent
51efcbbd66
commit
db05eb1cc8
|
@ -42,7 +42,7 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
|||
list(GET CONFIG_OUTPUT 3 INCLUDE_DIR)
|
||||
list(GET CONFIG_OUTPUT 4 LLVM_OBJ_ROOT)
|
||||
list(GET CONFIG_OUTPUT 5 MAIN_SRC_DIR)
|
||||
list(GET CONFIG_OUTPUT 6 LLVM_CMAKE_PATH)
|
||||
list(GET CONFIG_OUTPUT 6 LLVM_CONFIG_CMAKE_PATH)
|
||||
|
||||
if(NOT MSVC_IDE)
|
||||
set(LLVM_ENABLE_ASSERTIONS ${ENABLE_ASSERTIONS}
|
||||
|
@ -57,6 +57,10 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
|||
set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree")
|
||||
set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
|
||||
|
||||
# Normalize LLVM_CMAKE_PATH. --cmakedir might contain backslashes.
|
||||
# CMake assumes slashes as PATH.
|
||||
file(TO_CMAKE_PATH ${LLVM_CONFIG_CMAKE_PATH} LLVM_CMAKE_PATH)
|
||||
|
||||
find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR}
|
||||
NO_DEFAULT_PATH)
|
||||
|
||||
|
@ -78,6 +82,7 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
|||
set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
|
||||
endif()
|
||||
|
||||
option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON)
|
||||
option(LLVM_INSTALL_TOOLCHAIN_ONLY
|
||||
"Only include toolchain files in the 'install' target." OFF)
|
||||
|
||||
|
@ -181,6 +186,8 @@ if (LIBXML2_FOUND)
|
|||
set(CLANG_HAVE_LIBXML 1)
|
||||
endif()
|
||||
|
||||
find_package(Z3 4.5)
|
||||
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(sys/resource.h CLANG_HAVE_RLIMITS)
|
||||
|
||||
|
@ -325,10 +332,6 @@ if (APPLE)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
|
||||
${CLANG_BINARY_DIR}/include/clang/Config/config.h)
|
||||
|
||||
include(CMakeParseArguments)
|
||||
include(AddClang)
|
||||
|
||||
|
@ -356,6 +359,10 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
|||
PATTERN "*.inc"
|
||||
PATTERN "*.h"
|
||||
)
|
||||
|
||||
install(PROGRAMS utils/bash-autocomplete.sh
|
||||
DESTINATION share/clang
|
||||
)
|
||||
endif()
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
@ -364,29 +371,25 @@ option(CLANG_BUILD_TOOLS
|
|||
"Build the Clang tools. If OFF, just generate build targets." ON)
|
||||
|
||||
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
|
||||
if (CLANG_ENABLE_ARCMT)
|
||||
set(ENABLE_CLANG_ARCMT "1")
|
||||
else()
|
||||
set(ENABLE_CLANG_ARCMT "0")
|
||||
endif()
|
||||
|
||||
option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
|
||||
if (CLANG_ENABLE_STATIC_ANALYZER)
|
||||
set(ENABLE_CLANG_STATIC_ANALYZER "1")
|
||||
else()
|
||||
set(ENABLE_CLANG_STATIC_ANALYZER "0")
|
||||
|
||||
option(CLANG_ANALYZER_BUILD_Z3
|
||||
"Build the static analyzer with the Z3 constraint manager." OFF)
|
||||
|
||||
if(NOT CLANG_ENABLE_STATIC_ANALYZER AND (CLANG_ENABLE_ARCMT OR CLANG_ANALYZER_BUILD_Z3))
|
||||
message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT or Z3")
|
||||
endif()
|
||||
|
||||
if (NOT CLANG_ENABLE_STATIC_ANALYZER AND CLANG_ENABLE_ARCMT)
|
||||
message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT")
|
||||
if(CLANG_ANALYZER_BUILD_Z3)
|
||||
if(Z3_FOUND)
|
||||
set(CLANG_ANALYZER_WITH_Z3 1)
|
||||
else()
|
||||
message(FATAL_ERROR "Cannot find Z3 header file or shared library")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CLANG_ENABLE_ARCMT)
|
||||
add_definitions(-DCLANG_ENABLE_ARCMT)
|
||||
add_definitions(-DCLANG_ENABLE_OBJC_REWRITER)
|
||||
endif()
|
||||
if(CLANG_ENABLE_STATIC_ANALYZER)
|
||||
add_definitions(-DCLANG_ENABLE_STATIC_ANALYZER)
|
||||
set(CLANG_ENABLE_OBJC_REWRITER ON)
|
||||
endif()
|
||||
|
||||
# Clang version information
|
||||
|
@ -415,11 +418,6 @@ add_subdirectory(tools)
|
|||
add_subdirectory(runtime)
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
|
||||
if (CLANG_BUILD_EXAMPLES)
|
||||
set(ENABLE_CLANG_EXAMPLES "1")
|
||||
else()
|
||||
set(ENABLE_CLANG_EXAMPLES "0")
|
||||
endif()
|
||||
add_subdirectory(examples)
|
||||
|
||||
if(APPLE)
|
||||
|
@ -515,6 +513,10 @@ if (CLANG_ENABLE_BOOTSTRAP)
|
|||
set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-stamps/)
|
||||
set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-bins/)
|
||||
|
||||
if(BOOTSTRAP_LLVM_ENABLE_LLD)
|
||||
add_dependencies(clang-bootstrap-deps lld)
|
||||
endif()
|
||||
|
||||
# If the next stage is LTO we need to depend on LTO and possibly lld or LLVMgold
|
||||
if(BOOTSTRAP_LLVM_ENABLE_LTO OR LLVM_ENABLE_LTO AND NOT LLVM_BUILD_INSTRUMENTED)
|
||||
if(APPLE)
|
||||
|
@ -531,9 +533,7 @@ if (CLANG_ENABLE_BOOTSTRAP)
|
|||
-DDYLD_LIBRARY_PATH=${LLVM_LIBRARY_OUTPUT_INTDIR})
|
||||
elseif(NOT WIN32)
|
||||
add_dependencies(clang-bootstrap-deps llvm-ar llvm-ranlib)
|
||||
if(BOOTSTRAP_LLVM_ENABLE_LLD)
|
||||
add_dependencies(clang-bootstrap-deps lld)
|
||||
elseif(LLVM_BINUTILS_INCDIR)
|
||||
if(NOT BOOTSTRAP_LLVM_ENABLE_LLD AND LLVM_BINUTILS_INCDIR)
|
||||
add_dependencies(clang-bootstrap-deps LLVMgold)
|
||||
endif()
|
||||
set(LTO_AR -DCMAKE_AR=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ar)
|
||||
|
@ -579,10 +579,17 @@ if (CLANG_ENABLE_BOOTSTRAP)
|
|||
add_dependencies(clang-bootstrap-deps compiler-rt)
|
||||
endif()
|
||||
|
||||
set(C_COMPILER "clang")
|
||||
set(CXX_COMPILER "clang++")
|
||||
if(WIN32)
|
||||
set(C_COMPILER "clang-cl.exe")
|
||||
set(CXX_COMPILER "clang-cl.exe")
|
||||
endif()
|
||||
|
||||
set(COMPILER_OPTIONS
|
||||
-DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++
|
||||
-DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
|
||||
-DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
|
||||
-DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${CXX_COMPILER}
|
||||
-DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${C_COMPILER}
|
||||
-DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${C_COMPILER})
|
||||
|
||||
if(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED)
|
||||
add_dependencies(clang-bootstrap-deps llvm-profdata)
|
||||
|
@ -696,3 +703,7 @@ endif()
|
|||
if (LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION)
|
||||
add_subdirectory(utils/ClangVisualizers)
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
|
||||
${CLANG_BINARY_DIR}/include/clang/Config/config.h)
|
||||
|
|
|
@ -20,13 +20,5 @@ The available modules are:
|
|||
Bindings for the Clang indexing library.
|
||||
"""
|
||||
|
||||
|
||||
# Python 3 uses unicode for strings. The bindings, in particular the interaction
|
||||
# with ctypes, need modifying to handle conversions between unicode and
|
||||
# c-strings.
|
||||
import sys
|
||||
if sys.version_info[0] != 2:
|
||||
raise Exception("Only Python 2 is supported.")
|
||||
|
||||
__all__ = ['cindex']
|
||||
|
||||
|
|
|
@ -67,6 +67,60 @@ import collections
|
|||
|
||||
import clang.enumerations
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] == 3:
|
||||
# Python 3 strings are unicode, translate them to/from utf8 for C-interop.
|
||||
class c_interop_string(c_char_p):
|
||||
|
||||
def __init__(self, p=None):
|
||||
if p is None:
|
||||
p = ""
|
||||
if isinstance(p, str):
|
||||
p = p.encode("utf8")
|
||||
super(c_char_p, self).__init__(p)
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
if super(c_char_p, self).value is None:
|
||||
return None
|
||||
return super(c_char_p, self).value.decode("utf8")
|
||||
|
||||
@classmethod
|
||||
def from_param(cls, param):
|
||||
if isinstance(param, str):
|
||||
return cls(param)
|
||||
if isinstance(param, bytes):
|
||||
return cls(param)
|
||||
raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__))
|
||||
|
||||
@staticmethod
|
||||
def to_python_string(x, *args):
|
||||
return x.value
|
||||
|
||||
def b(x):
|
||||
if isinstance(x, bytes):
|
||||
return x
|
||||
return x.encode('utf8')
|
||||
|
||||
xrange = range
|
||||
|
||||
elif sys.version_info[0] == 2:
|
||||
# Python 2 strings are utf8 byte strings, no translation is needed for
|
||||
# C-interop.
|
||||
c_interop_string = c_char_p
|
||||
|
||||
def _to_python_string(x, *args):
|
||||
return x
|
||||
|
||||
c_interop_string.to_python_string = staticmethod(_to_python_string)
|
||||
|
||||
def b(x):
|
||||
return x
|
||||
|
||||
|
||||
# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
|
||||
# object. This is a problem, because it means that from_parameter will see an
|
||||
# integer and pass the wrong value on platforms where int != void*. Work around
|
||||
|
@ -157,6 +211,7 @@ class _CXString(Structure):
|
|||
assert isinstance(res, _CXString)
|
||||
return conf.lib.clang_getCString(res)
|
||||
|
||||
|
||||
class SourceLocation(Structure):
|
||||
"""
|
||||
A SourceLocation represents a particular location within a source file.
|
||||
|
@ -596,7 +651,7 @@ class CursorKind(BaseEnumeration):
|
|||
@staticmethod
|
||||
def get_all_kinds():
|
||||
"""Return all CursorKind enumeration instances."""
|
||||
return filter(None, CursorKind._kinds)
|
||||
return [x for x in CursorKind._kinds if not x is None]
|
||||
|
||||
def is_declaration(self):
|
||||
"""Test if this is a declaration kind."""
|
||||
|
@ -727,7 +782,7 @@ CursorKind.CONVERSION_FUNCTION = CursorKind(26)
|
|||
# A C++ template type parameter
|
||||
CursorKind.TEMPLATE_TYPE_PARAMETER = CursorKind(27)
|
||||
|
||||
# A C++ non-type template paramater.
|
||||
# A C++ non-type template parameter.
|
||||
CursorKind.TEMPLATE_NON_TYPE_PARAMETER = CursorKind(28)
|
||||
|
||||
# A C++ template template parameter.
|
||||
|
@ -1312,6 +1367,30 @@ TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2)
|
|||
TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3)
|
||||
TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4)
|
||||
|
||||
### Exception Specification Kinds ###
|
||||
class ExceptionSpecificationKind(BaseEnumeration):
|
||||
"""
|
||||
An ExceptionSpecificationKind describes the kind of exception specification
|
||||
that a function has.
|
||||
"""
|
||||
|
||||
# The required BaseEnumeration declarations.
|
||||
_kinds = []
|
||||
_name_map = None
|
||||
|
||||
def __repr__(self):
|
||||
return 'ExceptionSpecificationKind.{}'.format(self.name)
|
||||
|
||||
ExceptionSpecificationKind.NONE = ExceptionSpecificationKind(0)
|
||||
ExceptionSpecificationKind.DYNAMIC_NONE = ExceptionSpecificationKind(1)
|
||||
ExceptionSpecificationKind.DYNAMIC = ExceptionSpecificationKind(2)
|
||||
ExceptionSpecificationKind.MS_ANY = ExceptionSpecificationKind(3)
|
||||
ExceptionSpecificationKind.BASIC_NOEXCEPT = ExceptionSpecificationKind(4)
|
||||
ExceptionSpecificationKind.COMPUTED_NOEXCEPT = ExceptionSpecificationKind(5)
|
||||
ExceptionSpecificationKind.UNEVALUATED = ExceptionSpecificationKind(6)
|
||||
ExceptionSpecificationKind.UNINSTANTIATED = ExceptionSpecificationKind(7)
|
||||
ExceptionSpecificationKind.UNPARSED = ExceptionSpecificationKind(8)
|
||||
|
||||
### Cursors ###
|
||||
|
||||
class Cursor(Structure):
|
||||
|
@ -1399,6 +1478,11 @@ class Cursor(Structure):
|
|||
"""
|
||||
return conf.lib.clang_CXXMethod_isVirtual(self)
|
||||
|
||||
def is_scoped_enum(self):
|
||||
"""Returns True if the cursor refers to a scoped enum declaration.
|
||||
"""
|
||||
return conf.lib.clang_EnumDecl_isScoped(self)
|
||||
|
||||
def get_definition(self):
|
||||
"""
|
||||
If the cursor is a reference to a declaration or a declaration of
|
||||
|
@ -1531,6 +1615,18 @@ class Cursor(Structure):
|
|||
|
||||
return self._result_type
|
||||
|
||||
@property
|
||||
def exception_specification_kind(self):
|
||||
'''
|
||||
Retrieve the exception specification kind, which is one of the values
|
||||
from the ExceptionSpecificationKind enumeration.
|
||||
'''
|
||||
if not hasattr(self, '_exception_specification_kind'):
|
||||
exc_kind = conf.lib.clang_getCursorExceptionSpecificationType(self)
|
||||
self._exception_specification_kind = ExceptionSpecificationKind.from_id(exc_kind)
|
||||
|
||||
return self._exception_specification_kind
|
||||
|
||||
@property
|
||||
def underlying_typedef_type(self):
|
||||
"""Return the underlying type of a typedef declaration.
|
||||
|
@ -1887,6 +1983,7 @@ TypeKind.OBJCID = TypeKind(27)
|
|||
TypeKind.OBJCCLASS = TypeKind(28)
|
||||
TypeKind.OBJCSEL = TypeKind(29)
|
||||
TypeKind.FLOAT128 = TypeKind(30)
|
||||
TypeKind.HALF = TypeKind(31)
|
||||
TypeKind.COMPLEX = TypeKind(100)
|
||||
TypeKind.POINTER = TypeKind(101)
|
||||
TypeKind.BLOCKPOINTER = TypeKind(102)
|
||||
|
@ -1907,6 +2004,47 @@ TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
|
|||
TypeKind.MEMBERPOINTER = TypeKind(117)
|
||||
TypeKind.AUTO = TypeKind(118)
|
||||
TypeKind.ELABORATED = TypeKind(119)
|
||||
TypeKind.PIPE = TypeKind(120)
|
||||
TypeKind.OCLIMAGE1DRO = TypeKind(121)
|
||||
TypeKind.OCLIMAGE1DARRAYRO = TypeKind(122)
|
||||
TypeKind.OCLIMAGE1DBUFFERRO = TypeKind(123)
|
||||
TypeKind.OCLIMAGE2DRO = TypeKind(124)
|
||||
TypeKind.OCLIMAGE2DARRAYRO = TypeKind(125)
|
||||
TypeKind.OCLIMAGE2DDEPTHRO = TypeKind(126)
|
||||
TypeKind.OCLIMAGE2DARRAYDEPTHRO = TypeKind(127)
|
||||
TypeKind.OCLIMAGE2DMSAARO = TypeKind(128)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAARO = TypeKind(129)
|
||||
TypeKind.OCLIMAGE2DMSAADEPTHRO = TypeKind(130)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAADEPTHRO = TypeKind(131)
|
||||
TypeKind.OCLIMAGE3DRO = TypeKind(132)
|
||||
TypeKind.OCLIMAGE1DWO = TypeKind(133)
|
||||
TypeKind.OCLIMAGE1DARRAYWO = TypeKind(134)
|
||||
TypeKind.OCLIMAGE1DBUFFERWO = TypeKind(135)
|
||||
TypeKind.OCLIMAGE2DWO = TypeKind(136)
|
||||
TypeKind.OCLIMAGE2DARRAYWO = TypeKind(137)
|
||||
TypeKind.OCLIMAGE2DDEPTHWO = TypeKind(138)
|
||||
TypeKind.OCLIMAGE2DARRAYDEPTHWO = TypeKind(139)
|
||||
TypeKind.OCLIMAGE2DMSAAWO = TypeKind(140)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAAWO = TypeKind(141)
|
||||
TypeKind.OCLIMAGE2DMSAADEPTHWO = TypeKind(142)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAADEPTHWO = TypeKind(143)
|
||||
TypeKind.OCLIMAGE3DWO = TypeKind(144)
|
||||
TypeKind.OCLIMAGE1DRW = TypeKind(145)
|
||||
TypeKind.OCLIMAGE1DARRAYRW = TypeKind(146)
|
||||
TypeKind.OCLIMAGE1DBUFFERRW = TypeKind(147)
|
||||
TypeKind.OCLIMAGE2DRW = TypeKind(148)
|
||||
TypeKind.OCLIMAGE2DARRAYRW = TypeKind(149)
|
||||
TypeKind.OCLIMAGE2DDEPTHRW = TypeKind(150)
|
||||
TypeKind.OCLIMAGE2DARRAYDEPTHRW = TypeKind(151)
|
||||
TypeKind.OCLIMAGE2DMSAARW = TypeKind(152)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAARW = TypeKind(153)
|
||||
TypeKind.OCLIMAGE2DMSAADEPTHRW = TypeKind(154)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAADEPTHRW = TypeKind(155)
|
||||
TypeKind.OCLIMAGE3DRW = TypeKind(156)
|
||||
TypeKind.OCLSAMPLER = TypeKind(157)
|
||||
TypeKind.OCLEVENT = TypeKind(158)
|
||||
TypeKind.OCLQUEUE = TypeKind(159)
|
||||
TypeKind.OCLRESERVEID = TypeKind(160)
|
||||
|
||||
class RefQualifierKind(BaseEnumeration):
|
||||
"""Describes a specific ref-qualifier of a type."""
|
||||
|
@ -2065,6 +2203,12 @@ class Type(Structure):
|
|||
|
||||
return conf.lib.clang_isFunctionTypeVariadic(self)
|
||||
|
||||
def get_address_space(self):
|
||||
return conf.lib.clang_getAddressSpace(self)
|
||||
|
||||
def get_typedef_name(self):
|
||||
return conf.lib.clang_getTypedefName(self)
|
||||
|
||||
def is_pod(self):
|
||||
"""Determine whether this Type represents plain old data (POD)."""
|
||||
return conf.lib.clang_isPODType(self)
|
||||
|
@ -2127,7 +2271,7 @@ class Type(Structure):
|
|||
"""
|
||||
Retrieve the offset of a field in the record.
|
||||
"""
|
||||
return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname))
|
||||
return conf.lib.clang_Type_getOffsetOf(self, fieldname)
|
||||
|
||||
def get_ref_qualifier(self):
|
||||
"""
|
||||
|
@ -2151,6 +2295,14 @@ class Type(Structure):
|
|||
callbacks['fields_visit'](visitor), fields)
|
||||
return iter(fields)
|
||||
|
||||
def get_exception_specification_kind(self):
|
||||
"""
|
||||
Return the kind of the exception specification; a value from
|
||||
the ExceptionSpecificationKind enumeration.
|
||||
"""
|
||||
return ExceptionSpecificationKind.from_id(
|
||||
conf.lib.clang.getExceptionSpecificationType(self))
|
||||
|
||||
@property
|
||||
def spelling(self):
|
||||
"""Retrieve the spelling of this Type."""
|
||||
|
@ -2238,7 +2390,7 @@ class CompletionChunk:
|
|||
def spelling(self):
|
||||
if self.__kindNumber in SpellingCache:
|
||||
return SpellingCache[self.__kindNumber]
|
||||
return conf.lib.clang_getCompletionChunkText(self.cs, self.key).spelling
|
||||
return conf.lib.clang_getCompletionChunkText(self.cs, self.key)
|
||||
|
||||
# We do not use @CachedProperty here, as the manual implementation is
|
||||
# apparently still significantly faster. Please profile carefully if you
|
||||
|
@ -2344,7 +2496,7 @@ class CompletionString(ClangObject):
|
|||
return " | ".join([str(a) for a in self]) \
|
||||
+ " || Priority: " + str(self.priority) \
|
||||
+ " || Availability: " + str(self.availability) \
|
||||
+ " || Brief comment: " + str(self.briefComment.spelling)
|
||||
+ " || Brief comment: " + str(self.briefComment)
|
||||
|
||||
availabilityKinds = {
|
||||
0: CompletionChunk.Kind("Available"),
|
||||
|
@ -2541,7 +2693,7 @@ class TranslationUnit(ClangObject):
|
|||
|
||||
args_array = None
|
||||
if len(args) > 0:
|
||||
args_array = (c_char_p * len(args))(* args)
|
||||
args_array = (c_char_p * len(args))(*[b(x) for x in args])
|
||||
|
||||
unsaved_array = None
|
||||
if len(unsaved_files) > 0:
|
||||
|
@ -2550,8 +2702,8 @@ class TranslationUnit(ClangObject):
|
|||
if hasattr(contents, "read"):
|
||||
contents = contents.read()
|
||||
|
||||
unsaved_array[i].name = name
|
||||
unsaved_array[i].contents = contents
|
||||
unsaved_array[i].name = b(name)
|
||||
unsaved_array[i].contents = b(contents)
|
||||
unsaved_array[i].length = len(contents)
|
||||
|
||||
ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array,
|
||||
|
@ -2796,8 +2948,8 @@ class TranslationUnit(ClangObject):
|
|||
print(value)
|
||||
if not isinstance(value, str):
|
||||
raise TypeError('Unexpected unsaved file contents.')
|
||||
unsaved_files_array[i].name = name
|
||||
unsaved_files_array[i].contents = value
|
||||
unsaved_files_array[i].name = b(name)
|
||||
unsaved_files_array[i].contents = b(value)
|
||||
unsaved_files_array[i].length = len(value)
|
||||
ptr = conf.lib.clang_codeCompleteAt(self, path, line, column,
|
||||
unsaved_files_array, len(unsaved_files), options)
|
||||
|
@ -2832,7 +2984,7 @@ class File(ClangObject):
|
|||
@property
|
||||
def name(self):
|
||||
"""Return the complete file and path name of the file."""
|
||||
return conf.lib.clang_getCString(conf.lib.clang_getFileName(self))
|
||||
return conf.lib.clang_getFileName(self)
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
|
@ -3063,7 +3215,7 @@ functionList = [
|
|||
[c_object_p]),
|
||||
|
||||
("clang_CompilationDatabase_fromDirectory",
|
||||
[c_char_p, POINTER(c_uint)],
|
||||
[c_interop_string, POINTER(c_uint)],
|
||||
c_object_p,
|
||||
CompilationDatabase.from_result),
|
||||
|
||||
|
@ -3073,7 +3225,7 @@ functionList = [
|
|||
CompileCommands.from_result),
|
||||
|
||||
("clang_CompilationDatabase_getCompileCommands",
|
||||
[c_object_p, c_char_p],
|
||||
[c_object_p, c_interop_string],
|
||||
c_object_p,
|
||||
CompileCommands.from_result),
|
||||
|
||||
|
@ -3108,7 +3260,7 @@ functionList = [
|
|||
c_uint),
|
||||
|
||||
("clang_codeCompleteAt",
|
||||
[TranslationUnit, c_char_p, c_int, c_int, c_void_p, c_int, c_int],
|
||||
[TranslationUnit, c_interop_string, c_int, c_int, c_void_p, c_int, c_int],
|
||||
POINTER(CCRStructure)),
|
||||
|
||||
("clang_codeCompleteGetDiagnostic",
|
||||
|
@ -3124,7 +3276,7 @@ functionList = [
|
|||
c_object_p),
|
||||
|
||||
("clang_createTranslationUnit",
|
||||
[Index, c_char_p],
|
||||
[Index, c_interop_string],
|
||||
c_object_p),
|
||||
|
||||
("clang_CXXConstructor_isConvertingConstructor",
|
||||
|
@ -3167,6 +3319,10 @@ functionList = [
|
|||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_EnumDecl_isScoped",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_defaultDiagnosticDisplayOptions",
|
||||
[],
|
||||
c_uint),
|
||||
|
@ -3214,7 +3370,8 @@ functionList = [
|
|||
|
||||
("clang_formatDiagnostic",
|
||||
[Diagnostic, c_uint],
|
||||
_CXString),
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getArgType",
|
||||
[Type, c_uint],
|
||||
|
@ -3254,7 +3411,8 @@ functionList = [
|
|||
|
||||
("clang_getCompletionBriefComment",
|
||||
[c_void_p],
|
||||
_CXString),
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getCompletionChunkCompletionString",
|
||||
[c_void_p, c_int],
|
||||
|
@ -3266,7 +3424,8 @@ functionList = [
|
|||
|
||||
("clang_getCompletionChunkText",
|
||||
[c_void_p, c_int],
|
||||
_CXString),
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getCompletionPriority",
|
||||
[c_void_p],
|
||||
|
@ -3274,7 +3433,8 @@ functionList = [
|
|||
|
||||
("clang_getCString",
|
||||
[_CXString],
|
||||
c_char_p),
|
||||
c_interop_string,
|
||||
c_interop_string.to_python_string),
|
||||
|
||||
("clang_getCursor",
|
||||
[TranslationUnit, SourceLocation],
|
||||
|
@ -3421,12 +3581,13 @@ functionList = [
|
|||
Type.from_result),
|
||||
|
||||
("clang_getFile",
|
||||
[TranslationUnit, c_char_p],
|
||||
[TranslationUnit, c_interop_string],
|
||||
c_object_p),
|
||||
|
||||
("clang_getFileName",
|
||||
[File],
|
||||
_CXString), # TODO go through _CXString.from_result?
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getFileTime",
|
||||
[File],
|
||||
|
@ -3550,7 +3711,8 @@ functionList = [
|
|||
|
||||
("clang_getTUResourceUsageName",
|
||||
[c_uint],
|
||||
c_char_p),
|
||||
c_interop_string,
|
||||
c_interop_string.to_python_string),
|
||||
|
||||
("clang_getTypeDeclaration",
|
||||
[Type],
|
||||
|
@ -3562,6 +3724,11 @@ functionList = [
|
|||
Type,
|
||||
Type.from_result),
|
||||
|
||||
("clang_getTypedefName",
|
||||
[Type],
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getTypeKindSpelling",
|
||||
[c_uint],
|
||||
_CXString,
|
||||
|
@ -3645,7 +3812,7 @@ functionList = [
|
|||
bool),
|
||||
|
||||
("clang_parseTranslationUnit",
|
||||
[Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int],
|
||||
[Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int],
|
||||
c_object_p),
|
||||
|
||||
("clang_reparseTranslationUnit",
|
||||
|
@ -3653,7 +3820,7 @@ functionList = [
|
|||
c_int),
|
||||
|
||||
("clang_saveTranslationUnit",
|
||||
[TranslationUnit, c_char_p, c_uint],
|
||||
[TranslationUnit, c_interop_string, c_uint],
|
||||
c_int),
|
||||
|
||||
("clang_tokenize",
|
||||
|
@ -3725,7 +3892,7 @@ functionList = [
|
|||
Type.from_result),
|
||||
|
||||
("clang_Type_getOffsetOf",
|
||||
[Type, c_char_p],
|
||||
[Type, c_interop_string],
|
||||
c_longlong),
|
||||
|
||||
("clang_Type_getSizeOf",
|
||||
|
@ -3784,7 +3951,8 @@ def register_functions(lib, ignore_errors):
|
|||
def register(item):
|
||||
return register_function(lib, item, ignore_errors)
|
||||
|
||||
map(register, functionList)
|
||||
for f in functionList:
|
||||
register(f)
|
||||
|
||||
class Config:
|
||||
library_path = None
|
||||
|
|
|
@ -255,6 +255,22 @@ def test_is_virtual_method():
|
|||
assert foo.is_virtual_method()
|
||||
assert not bar.is_virtual_method()
|
||||
|
||||
def test_is_scoped_enum():
|
||||
"""Ensure Cursor.is_scoped_enum works."""
|
||||
source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
|
||||
tu = get_tu(source, lang='cpp')
|
||||
|
||||
cls = get_cursor(tu, 'X')
|
||||
regular_enum = get_cursor(tu, 'RegularEnum')
|
||||
scoped_enum = get_cursor(tu, 'ScopedEnum')
|
||||
assert cls is not None
|
||||
assert regular_enum is not None
|
||||
assert scoped_enum is not None
|
||||
|
||||
assert not cls.is_scoped_enum()
|
||||
assert not regular_enum.is_scoped_enum()
|
||||
assert scoped_enum.is_scoped_enum()
|
||||
|
||||
def test_underlying_type():
|
||||
tu = get_tu('typedef int foo;')
|
||||
typedef = get_cursor(tu, 'foo')
|
||||
|
|
|
@ -59,9 +59,12 @@ int SOME_DEFINE;
|
|||
assert spellings[-1] == 'y'
|
||||
|
||||
def test_unsaved_files_2():
|
||||
import StringIO
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except:
|
||||
from io import StringIO
|
||||
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
|
||||
('fake.c', StringIO.StringIO('int x;'))])
|
||||
('fake.c', StringIO('int x;'))])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-1] == 'x'
|
||||
|
||||
|
|
|
@ -37,37 +37,44 @@ def test_a_struct():
|
|||
assert not fields[0].type.is_const_qualified()
|
||||
assert fields[0].type.kind == TypeKind.INT
|
||||
assert fields[0].type.get_canonical().kind == TypeKind.INT
|
||||
assert fields[0].type.get_typedef_name() == ''
|
||||
|
||||
assert fields[1].spelling == 'b'
|
||||
assert not fields[1].type.is_const_qualified()
|
||||
assert fields[1].type.kind == TypeKind.TYPEDEF
|
||||
assert fields[1].type.get_canonical().kind == TypeKind.INT
|
||||
assert fields[1].type.get_declaration().spelling == 'I'
|
||||
assert fields[1].type.get_typedef_name() == 'I'
|
||||
|
||||
assert fields[2].spelling == 'c'
|
||||
assert not fields[2].type.is_const_qualified()
|
||||
assert fields[2].type.kind == TypeKind.LONG
|
||||
assert fields[2].type.get_canonical().kind == TypeKind.LONG
|
||||
assert fields[2].type.get_typedef_name() == ''
|
||||
|
||||
assert fields[3].spelling == 'd'
|
||||
assert not fields[3].type.is_const_qualified()
|
||||
assert fields[3].type.kind == TypeKind.ULONG
|
||||
assert fields[3].type.get_canonical().kind == TypeKind.ULONG
|
||||
assert fields[3].type.get_typedef_name() == ''
|
||||
|
||||
assert fields[4].spelling == 'e'
|
||||
assert not fields[4].type.is_const_qualified()
|
||||
assert fields[4].type.kind == TypeKind.LONG
|
||||
assert fields[4].type.get_canonical().kind == TypeKind.LONG
|
||||
assert fields[4].type.get_typedef_name() == ''
|
||||
|
||||
assert fields[5].spelling == 'f'
|
||||
assert fields[5].type.is_const_qualified()
|
||||
assert fields[5].type.kind == TypeKind.INT
|
||||
assert fields[5].type.get_canonical().kind == TypeKind.INT
|
||||
assert fields[5].type.get_typedef_name() == ''
|
||||
|
||||
assert fields[6].spelling == 'g'
|
||||
assert not fields[6].type.is_const_qualified()
|
||||
assert fields[6].type.kind == TypeKind.POINTER
|
||||
assert fields[6].type.get_pointee().kind == TypeKind.INT
|
||||
assert fields[6].type.get_typedef_name() == ''
|
||||
|
||||
assert fields[7].spelling == 'h'
|
||||
assert not fields[7].type.is_const_qualified()
|
||||
|
@ -75,6 +82,7 @@ def test_a_struct():
|
|||
assert fields[7].type.get_pointee().kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
|
||||
assert fields[7].type.get_typedef_name() == ''
|
||||
|
||||
def test_references():
|
||||
"""Ensure that a Type maintains a reference to a TranslationUnit."""
|
||||
|
@ -404,3 +412,12 @@ def test_decay():
|
|||
assert a.kind == TypeKind.INCOMPLETEARRAY
|
||||
assert a.element_type.kind == TypeKind.INT
|
||||
assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
|
||||
|
||||
def test_addrspace():
|
||||
"""Ensure the address space can be queried"""
|
||||
tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c')
|
||||
|
||||
testInteger = get_cursor(tu, 'testInteger')
|
||||
|
||||
assert testInteger is not None, "Could not find testInteger."
|
||||
assert testInteger.type.get_address_space() == 2
|
||||
|
|
27
external/bsd/llvm/dist/clang/bindings/python/tests/test_exception_specification_kind.py
vendored
Normal file
27
external/bsd/llvm/dist/clang/bindings/python/tests/test_exception_specification_kind.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
import clang.cindex
|
||||
from clang.cindex import ExceptionSpecificationKind
|
||||
from .util import get_tu
|
||||
|
||||
|
||||
def find_function_declarations(node, declarations=[]):
|
||||
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
|
||||
declarations.append((node.spelling, node.exception_specification_kind))
|
||||
for child in node.get_children():
|
||||
declarations = find_function_declarations(child, declarations)
|
||||
return declarations
|
||||
|
||||
|
||||
def test_exception_specification_kind():
|
||||
source = """int square1(int x);
|
||||
int square2(int x) noexcept;
|
||||
int square3(int x) noexcept(noexcept(x * x));"""
|
||||
|
||||
tu = get_tu(source, lang='cpp', flags=['-std=c++14'])
|
||||
|
||||
declarations = find_function_declarations(tu.cursor)
|
||||
expected = [
|
||||
('square1', ExceptionSpecificationKind.NONE),
|
||||
('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT),
|
||||
('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT)
|
||||
]
|
||||
assert declarations == expected
|
|
@ -0,0 +1,6 @@
|
|||
# This file sets up a CMakeCache for Apple-style stage2 ThinLTO bootstrap. It is
|
||||
# specified by the stage1 build.
|
||||
|
||||
|
||||
set(LLVM_ENABLE_LTO THIN CACHE BOOL "")
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Apple-stage2.cmake)
|
|
@ -13,6 +13,7 @@ set(CLANG_LINKS_TO_CREATE clang++ cc c++ CACHE STRING "")
|
|||
set(CMAKE_MACOSX_RPATH ON CACHE BOOL "")
|
||||
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
|
||||
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
|
||||
set(LLVM_ENABLE_MODULES ON CACHE BOOL "")
|
||||
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
|
||||
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
|
||||
set(BUG_REPORT_URL "http://developer.apple.com/bugreporter/" CACHE STRING "")
|
||||
|
@ -28,8 +29,10 @@ set(LLVM_BUILD_TESTS ON CACHE BOOL "")
|
|||
set(LLVM_ENABLE_LTO ON CACHE BOOL "")
|
||||
set(CMAKE_C_FLAGS "-fno-stack-protector -fno-common -Wno-profile-instr-unprofiled" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS "-fno-stack-protector -fno-common -Wno-profile-instr-unprofiled" CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
if(LLVM_ENABLE_LTO AND NOT LLVM_ENABLE_LTO STREQUAL "THIN")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
endif()
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
|
||||
|
||||
set(LIBCXX_INSTALL_LIBRARY OFF CACHE BOOL "")
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
set(LLVM_TARGETS_TO_BUILD ARM;X86 CACHE STRING "")
|
||||
|
||||
# Builtins
|
||||
set(LLVM_BUILTIN_TARGETS "armv7m-none-eabi;armv6m-none-eabi;armv7em-none-eabi" CACHE STRING "Builtin Targets")
|
||||
|
||||
set(BUILTINS_armv6m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV6M_SYSROOT} CACHE STRING "armv6m-none-eabi Sysroot")
|
||||
set(BUILTINS_armv6m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv6m-none-eabi System Name")
|
||||
set(BUILTINS_armv6m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv6m-none-eabi Baremetal build")
|
||||
set(BUILTINS_armv6m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv6m-none-eabi os dir")
|
||||
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7M_SYSROOT} CACHE STRING "armv7m-none-eabi Sysroot")
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7m-none-eabi System Name")
|
||||
set(BUILTINS_armv7m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7m-none-eabi Baremetal build")
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi C Flags")
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi ASM Flags")
|
||||
set(BUILTINS_armv7m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7m-none-eabi os dir")
|
||||
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7EM_SYSROOT} CACHE STRING "armv7em-none-eabi Sysroot")
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7em-none-eabi System Name")
|
||||
set(BUILTINS_armv7em-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7em-none-eabi Baremetal build")
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi C Flags")
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi ASM Flags")
|
||||
set(BUILTINS_armv7em-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7em-none-eabi os dir")
|
||||
|
||||
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
|
||||
set(LLVM_TOOLCHAIN_TOOLS
|
||||
llc
|
||||
llvm-ar
|
||||
llvm-cxxfilt
|
||||
llvm-dwarfdump
|
||||
llvm-dsymutil
|
||||
llvm-nm
|
||||
llvm-objdump
|
||||
llvm-ranlib
|
||||
llvm-readobj
|
||||
llvm-size
|
||||
llvm-symbolizer
|
||||
opt
|
||||
CACHE STRING "")
|
||||
|
||||
set(LLVM_DISTRIBUTION_COMPONENTS
|
||||
clang
|
||||
lld
|
||||
clang-headers
|
||||
builtins-armv6m-none-eabi
|
||||
builtins-armv7m-none-eabi
|
||||
builtins-armv7em-none-eabi
|
||||
runtimes
|
||||
${LLVM_TOOLCHAIN_TOOLS}
|
||||
CACHE STRING "")
|
|
@ -29,6 +29,13 @@ set(CLANG_BOOTSTRAP_TARGETS
|
|||
|
||||
# Setup the bootstrap build.
|
||||
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
|
||||
set(CLANG_BOOTSTRAP_CMAKE_ARGS
|
||||
-C ${CMAKE_CURRENT_LIST_DIR}/DistributionExample-stage2.cmake
|
||||
CACHE STRING "")
|
||||
|
||||
if(STAGE2_CACHE_FILE)
|
||||
set(CLANG_BOOTSTRAP_CMAKE_ARGS
|
||||
-C ${STAGE2_CACHE_FILE}
|
||||
CACHE STRING "")
|
||||
else()
|
||||
set(CLANG_BOOTSTRAP_CMAKE_ARGS
|
||||
-C ${CMAKE_CURRENT_LIST_DIR}/DistributionExample-stage2.cmake
|
||||
CACHE STRING "")
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
# This file sets up a CMakeCache for the second stage of a Fuchsia toolchain
|
||||
# build.
|
||||
|
||||
set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "")
|
||||
|
||||
set(PACKAGE_VENDOR Fuchsia CACHE STRING "")
|
||||
|
||||
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
|
||||
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
|
||||
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
|
||||
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
|
||||
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
|
||||
|
||||
set(LLVM_ENABLE_LTO ON CACHE BOOL "")
|
||||
if(NOT APPLE)
|
||||
set(LLVM_ENABLE_LLD ON CACHE BOOL "")
|
||||
set(CLANG_DEFAULT_LINKER lld CACHE STRING "")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(LLDB_CODESIGN_IDENTITY "" CACHE STRING "")
|
||||
endif()
|
||||
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
|
||||
set(LLVM_BUILTIN_TARGETS "x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "")
|
||||
foreach(target x86_64;aarch64)
|
||||
set(BUILTINS_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
|
||||
set(BUILTINS_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
|
||||
endforeach()
|
||||
if(NOT APPLE)
|
||||
list(APPEND LLVM_BUILTIN_TARGETS "default")
|
||||
endif()
|
||||
|
||||
set(LLVM_RUNTIME_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "")
|
||||
foreach(target x86_64;aarch64)
|
||||
set(RUNTIMES_${target}-fuchsia_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")
|
||||
set(RUNTIMES_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
|
||||
set(RUNTIMES_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
|
||||
set(RUNTIMES_${target}-fuchsia_UNIX 1 CACHE BOOL "")
|
||||
set(RUNTIMES_${target}-fuchsia_LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
|
||||
set(RUNTIMES_${target}-fuchsia_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(RUNTIMES_${target}-fuchsia_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
endforeach()
|
||||
|
||||
# Setup toolchain.
|
||||
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
|
||||
set(LLVM_TOOLCHAIN_TOOLS
|
||||
llc
|
||||
llvm-ar
|
||||
llvm-cov
|
||||
llvm-cxxfilt
|
||||
llvm-dwarfdump
|
||||
llvm-dsymutil
|
||||
llvm-lib
|
||||
llvm-nm
|
||||
llvm-objdump
|
||||
llvm-profdata
|
||||
llvm-ranlib
|
||||
llvm-readelf
|
||||
llvm-readobj
|
||||
llvm-size
|
||||
llvm-symbolizer
|
||||
opt
|
||||
CACHE STRING "")
|
||||
|
||||
set(LLVM_DISTRIBUTION_COMPONENTS
|
||||
clang
|
||||
lld
|
||||
lldb
|
||||
liblldb
|
||||
LTO
|
||||
clang-format
|
||||
clang-headers
|
||||
clang-tidy
|
||||
clangd
|
||||
builtins
|
||||
runtimes
|
||||
${LLVM_TOOLCHAIN_TOOLS}
|
||||
CACHE STRING "")
|
|
@ -0,0 +1,52 @@
|
|||
# This file sets up a CMakeCache for a Fuchsia toolchain build.
|
||||
|
||||
set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
|
||||
|
||||
set(PACKAGE_VENDOR Fuchsia CACHE STRING "")
|
||||
|
||||
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
|
||||
set(CLANG_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
|
||||
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
|
||||
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
|
||||
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
|
||||
|
||||
set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
|
||||
if(NOT APPLE)
|
||||
set(BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(COMPILER_RT_ENABLE_IOS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_ENABLE_TVOS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_ENABLE_WATCHOS OFF CACHE BOOL "")
|
||||
endif()
|
||||
|
||||
set(CLANG_BOOTSTRAP_TARGETS
|
||||
check-all
|
||||
check-llvm
|
||||
check-clang
|
||||
llvm-config
|
||||
test-suite
|
||||
test-depends
|
||||
llvm-test-depends
|
||||
clang-test-depends
|
||||
distribution
|
||||
install-distribution
|
||||
clang CACHE STRING "")
|
||||
|
||||
foreach(target x86_64;aarch64)
|
||||
if(FUCHSIA_${target}_SYSROOT)
|
||||
list(APPEND EXTRA_ARGS -DFUCHSIA_${target}_SYSROOT=${FUCHSIA_${target}_SYSROOT})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Setup the bootstrap build.
|
||||
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
|
||||
set(CLANG_BOOTSTRAP_CMAKE_ARGS
|
||||
${EXTRA_ARGS}
|
||||
-C ${CMAKE_CURRENT_LIST_DIR}/Fuchsia-stage2.cmake
|
||||
CACHE STRING "")
|
|
@ -4,17 +4,27 @@
|
|||
set(CLANG_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/clang)
|
||||
set(clang_cmake_builddir "${CMAKE_BINARY_DIR}/${CLANG_INSTALL_PACKAGE_DIR}")
|
||||
|
||||
# Keep this in sync with llvm/cmake/CMakeLists.txt!
|
||||
set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm)
|
||||
set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}")
|
||||
|
||||
get_property(CLANG_EXPORTS GLOBAL PROPERTY CLANG_EXPORTS)
|
||||
export(TARGETS ${CLANG_EXPORTS} FILE ${clang_cmake_builddir}/ClangTargets.cmake)
|
||||
|
||||
# Generate ClangConfig.cmake for the build tree.
|
||||
set(CLANG_CONFIG_CMAKE_DIR "${clang_cmake_builddir}")
|
||||
set(CLANG_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}")
|
||||
set(CLANG_CONFIG_EXPORTS_FILE "${clang_cmake_builddir}/ClangTargets.cmake")
|
||||
set(CLANG_CONFIG_INCLUDE_DIRS
|
||||
"${CLANG_SOURCE_DIR}/include"
|
||||
"${CLANG_BINARY_DIR}/include"
|
||||
)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ClangConfig.cmake.in
|
||||
${clang_cmake_builddir}/ClangConfig.cmake
|
||||
@ONLY)
|
||||
set(CLANG_CONFIG_CMAKE_DIR)
|
||||
set(CLANG_CONFIG_LLVM_CMAKE_DIR)
|
||||
set(CLANG_CONFIG_EXPORTS_FILE)
|
||||
|
||||
# Generate ClangConfig.cmake for the install tree.
|
||||
|
@ -29,7 +39,11 @@ foreach(p ${_count})
|
|||
get_filename_component(CLANG_INSTALL_PREFIX \"\${CLANG_INSTALL_PREFIX}\" PATH)")
|
||||
endforeach(p)
|
||||
set(CLANG_CONFIG_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${CLANG_INSTALL_PACKAGE_DIR}")
|
||||
set(CLANG_CONFIG_LLVM_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}")
|
||||
set(CLANG_CONFIG_EXPORTS_FILE "\${CLANG_CMAKE_DIR}/ClangTargets.cmake")
|
||||
set(CLANG_CONFIG_INCLUDE_DIRS
|
||||
"\${CLANG_INSTALL_PREFIX}/include"
|
||||
)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ClangConfig.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ClangConfig.cmake
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
# This file allows users to call find_package(Clang) and pick up our targets.
|
||||
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
|
||||
@CLANG_CONFIG_CODE@
|
||||
|
||||
find_package(LLVM REQUIRED CONFIG
|
||||
HINTS "@CLANG_CONFIG_LLVM_CMAKE_DIR@")
|
||||
|
||||
set(CLANG_EXPORTED_TARGETS "@CLANG_EXPORTS@")
|
||||
set(CLANG_CMAKE_DIR "@CLANG_CONFIG_CMAKE_DIR@")
|
||||
set(CLANG_INCLUDE_DIRS "@CLANG_CONFIG_INCLUDE_DIRS@")
|
||||
|
||||
# Provide all our library targets to users.
|
||||
include("@CLANG_CONFIG_EXPORTS_FILE@")
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
find_path(Z3_INCLUDE_DIR NAMES z3.h
|
||||
PATH_SUFFIXES libz3 z3
|
||||
)
|
||||
|
||||
find_library(Z3_LIBRARIES NAMES z3 libz3
|
||||
)
|
||||
|
||||
find_program(Z3_EXECUTABLE z3)
|
||||
|
||||
if(Z3_INCLUDE_DIR AND Z3_EXECUTABLE)
|
||||
execute_process (COMMAND ${Z3_EXECUTABLE} -version
|
||||
OUTPUT_VARIABLE libz3_version_str
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
string(REGEX REPLACE "^Z3 version ([0-9.]+)" "\\1"
|
||||
Z3_VERSION_STRING "${libz3_version_str}")
|
||||
unset(libz3_version_str)
|
||||
endif()
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set Z3_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Z3
|
||||
REQUIRED_VARS Z3_LIBRARIES Z3_INCLUDE_DIR
|
||||
VERSION_VAR Z3_VERSION_STRING)
|
||||
|
||||
mark_as_advanced(Z3_INCLUDE_DIR Z3_LIBRARIES)
|
File diff suppressed because it is too large
Load Diff
|
@ -2258,16 +2258,13 @@ non-block type [*]_. Equivalent to the following code:
|
|||
|
||||
.. code-block:: objc
|
||||
|
||||
id objc_storeStrong(id *object, id value) {
|
||||
value = [value retain];
|
||||
void objc_storeStrong(id *object, id value) {
|
||||
id oldValue = *object;
|
||||
value = [value retain];
|
||||
*object = value;
|
||||
[oldValue release];
|
||||
return value;
|
||||
}
|
||||
|
||||
Always returns ``value``.
|
||||
|
||||
.. [*] This does not imply that a ``__strong`` object of block type is an
|
||||
invalid argument to this function. Rather it implies that an ``objc_retain``
|
||||
and not an ``objc_retainBlock`` operation will be emitted if the argument is
|
||||
|
|
|
@ -856,15 +856,15 @@ mentioned above, call:
|
|||
|
||||
.. code-block:: c
|
||||
|
||||
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
|
||||
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<apropos>);
|
||||
|
||||
in the copy helper and:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
_Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
|
||||
_Block_object_dispose(->target, BLOCK_FIELD_<apropos>);
|
||||
|
||||
in the dispose helper where ``<appropo>`` is:
|
||||
in the dispose helper where ``<apropos>`` is:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
|
@ -888,7 +888,7 @@ and functions are generated in the same manner.
|
|||
Under ObjC we allow ``__weak`` as an attribute on ``__block`` variables, and
|
||||
this causes the addition of ``BLOCK_FIELD_IS_WEAK`` orred onto the
|
||||
``BLOCK_FIELD_IS_BYREF`` flag when copying the ``block_byref`` structure in the
|
||||
``Block`` copy helper, and onto the ``BLOCK_FIELD_<appropo>`` field within the
|
||||
``Block`` copy helper, and onto the ``BLOCK_FIELD_<apropos>`` field within the
|
||||
``block_byref`` copy/dispose helper calls.
|
||||
|
||||
The prototypes, and summary, of the helper functions are:
|
||||
|
|
|
@ -91,8 +91,8 @@ endif()
|
|||
endif()
|
||||
|
||||
if (LLVM_ENABLE_SPHINX)
|
||||
include(AddSphinxTarget)
|
||||
if (SPHINX_FOUND)
|
||||
include(AddSphinxTarget)
|
||||
if (${SPHINX_OUTPUT_HTML})
|
||||
add_sphinx_target(html clang)
|
||||
add_custom_command(TARGET docs-clang-html POST_BUILD
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -120,6 +120,18 @@ entity.
|
|||
It operates on the current, potentially unsaved buffer and does not create
|
||||
or save any files. To revert a formatting, just undo.
|
||||
|
||||
An alternative option is to format changes when saving a file and thus to
|
||||
have a zero-effort integration into the coding workflow. To do this, add this to
|
||||
your `.vimrc`:
|
||||
|
||||
.. code-block:: vim
|
||||
|
||||
function! Formatonsave()
|
||||
let l:formatdiff = 1
|
||||
pyf ~/llvm/tools/clang/tools/clang-format/clang-format.py
|
||||
endfunction
|
||||
autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave()
|
||||
|
||||
|
||||
Emacs Integration
|
||||
=================
|
||||
|
@ -162,8 +174,9 @@ Download the latest Visual Studio extension from the `alpha build site
|
|||
Script for patch reformatting
|
||||
=============================
|
||||
|
||||
The python script `clang/tools/clang-format-diff.py` parses the output of
|
||||
a unified diff and reformats all contained lines with :program:`clang-format`.
|
||||
The python script `clang/tools/clang-format/clang-format-diff.py` parses the
|
||||
output of a unified diff and reformats all contained lines with
|
||||
:program:`clang-format`.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -437,12 +437,17 @@ export this information, every DSO implements
|
|||
|
||||
.. code-block:: none
|
||||
|
||||
void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr)
|
||||
void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData)
|
||||
|
||||
This function provides external modules with access to CFI checks for the
|
||||
targets inside this DSO. For each known ``CallSiteTypeId``, this function
|
||||
performs an ``llvm.type.test`` with the corresponding type identifier. It
|
||||
aborts if the type is unknown, or if the check fails.
|
||||
This function provides external modules with access to CFI checks for
|
||||
the targets inside this DSO. For each known ``CallSiteTypeId``, this
|
||||
function performs an ``llvm.type.test`` with the corresponding type
|
||||
identifier. It reports an error if the type is unknown, or if the
|
||||
check fails. Depending on the values of compiler flags
|
||||
``-fsanitize-trap`` and ``-fsanitize-recover``, this function may
|
||||
print an error, abort and/or return to the caller. ``DiagData`` is an
|
||||
opaque pointer to the diagnostic information about the error, or
|
||||
``null`` if the caller does not provide this information.
|
||||
|
||||
The basic implementation is a large switch statement over all values
|
||||
of CallSiteTypeId supported by this DSO, and each case is similar to
|
||||
|
@ -452,11 +457,10 @@ CFI Shadow
|
|||
----------
|
||||
|
||||
To route CFI checks to the target DSO's __cfi_check function, a
|
||||
mapping from possible virtual / indirect call targets to
|
||||
the corresponding __cfi_check functions is maintained. This mapping is
|
||||
mapping from possible virtual / indirect call targets to the
|
||||
corresponding __cfi_check functions is maintained. This mapping is
|
||||
implemented as a sparse array of 2 bytes for every possible page (4096
|
||||
bytes) of memory. The table is kept readonly (FIXME: not yet) most of
|
||||
the time.
|
||||
bytes) of memory. The table is kept readonly most of the time.
|
||||
|
||||
There are 3 types of shadow values:
|
||||
|
||||
|
@ -481,14 +485,24 @@ them.
|
|||
CFI_SlowPath
|
||||
------------
|
||||
|
||||
The slow path check is implemented in compiler-rt library as
|
||||
The slow path check is implemented in a runtime support library as
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
void __cfi_slowpath(uint64 CallSiteTypeId, void *TargetAddr)
|
||||
void __cfi_slowpath_diag(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData)
|
||||
|
||||
This functions loads a shadow value for ``TargetAddr``, finds the
|
||||
address of __cfi_check as described above and calls that.
|
||||
These functions loads a shadow value for ``TargetAddr``, finds the
|
||||
address of ``__cfi_check`` as described above and calls
|
||||
that. ``DiagData`` is an opaque pointer to diagnostic data which is
|
||||
passed verbatim to ``__cfi_check``, and ``__cfi_slowpath`` passes
|
||||
``nullptr`` instead.
|
||||
|
||||
Compiler-RT library contains reference implementations of slowpath
|
||||
functions, but they have unresolvable issues with correctness and
|
||||
performance in the handling of dlopen(). It is recommended that
|
||||
platforms provide their own implementations, usually as part of libc
|
||||
or libdl.
|
||||
|
||||
Position-independent executable requirement
|
||||
-------------------------------------------
|
||||
|
@ -498,12 +512,100 @@ In non-PIE executables the address of an external function (taken from
|
|||
the main executable) is the address of that function’s PLT record in
|
||||
the main executable. This would break the CFI checks.
|
||||
|
||||
Backward-edge CFI for return statements (RCFI)
|
||||
==============================================
|
||||
|
||||
This section is a proposal. As of March 2017 it is not implemented.
|
||||
|
||||
Backward-edge control flow (`RET` instructions) can be hijacked
|
||||
via overwriting the return address (`RA`) on stack.
|
||||
Various mitigation techniques (e.g. `SafeStack`_, `RFG`_, `Intel CET`_)
|
||||
try to detect or prevent `RA` corruption on stack.
|
||||
|
||||
RCFI enforces the expected control flow in several different ways described below.
|
||||
RCFI heavily relies on LTO.
|
||||
|
||||
Leaf Functions
|
||||
--------------
|
||||
If `f()` is a leaf function (i.e. it has no calls
|
||||
except maybe no-return calls) it can be called using a special calling convention
|
||||
that stores `RA` in a dedicated register `R` before the `CALL` instruction.
|
||||
`f()` does not spill `R` and does not use the `RET` instruction,
|
||||
instead it uses the value in `R` to `JMP` to `RA`.
|
||||
|
||||
This flavour of CFI is *precise*, i.e. the function is guaranteed to return
|
||||
to the point exactly following the call.
|
||||
|
||||
An alternative approach is to
|
||||
copy `RA` from stack to `R` in the first instruction of `f()`,
|
||||
then `JMP` to `R`.
|
||||
This approach is simpler to implement (does not require changing the caller)
|
||||
but weaker (there is a small window when `RA` is actually stored on stack).
|
||||
|
||||
|
||||
Functions called once
|
||||
---------------------
|
||||
Suppose `f()` is called in just one place in the program
|
||||
(assuming we can verify this in LTO mode).
|
||||
In this case we can replace the `RET` instruction with a `JMP` instruction
|
||||
with the immediate constant for `RA`.
|
||||
This will *precisely* enforce the return control flow no matter what is stored on stack.
|
||||
|
||||
Another variant is to compare `RA` on stack with the known constant and abort
|
||||
if they don't match; then `JMP` to the known constant address.
|
||||
|
||||
Functions called in a small number of call sites
|
||||
------------------------------------------------
|
||||
We may extend the above approach to cases where `f()`
|
||||
is called more than once (but still a small number of times).
|
||||
With LTO we know all possible values of `RA` and we check them
|
||||
one-by-one (or using binary search) against the value on stack.
|
||||
If the match is found, we `JMP` to the known constant address, otherwise abort.
|
||||
|
||||
This protection is *near-precise*, i.e. it guarantees that the control flow will
|
||||
be transferred to one of the valid return addresses for this function,
|
||||
but not necessary to the point of the most recent `CALL`.
|
||||
|
||||
General case
|
||||
------------
|
||||
For functions called multiple times a *return jump table* is constructed
|
||||
in the same manner as jump tables for indirect function calls (see above).
|
||||
The correct jump table entry (or it's index) is passed by `CALL` to `f()`
|
||||
(as an extra argument) and then spilled to stack.
|
||||
The `RET` instruction is replaced with a load of the jump table entry,
|
||||
jump table range check, and `JMP` to the jump table entry.
|
||||
|
||||
This protection is also *near-precise*.
|
||||
|
||||
Returns from functions called indirectly
|
||||
----------------------------------------
|
||||
|
||||
If a function is called indirectly, the return jump table is constructed for the
|
||||
equivalence class of functions instead of a single function.
|
||||
|
||||
Cross-DSO calls
|
||||
---------------
|
||||
Consider two instrumented DSOs, `A` and `B`. `A` defines `f()` and `B` calls it.
|
||||
|
||||
This case will be handled similarly to the cross-DSO scheme using the slow path callback.
|
||||
|
||||
Non-goals
|
||||
---------
|
||||
|
||||
RCFI does not protect `RET` instructions:
|
||||
* in non-instrumented DSOs,
|
||||
* in instrumented DSOs for functions that are called from non-instrumented DSOs,
|
||||
* embedded into other instructions (e.g. `0f4fc3 cmovg %ebx,%eax`).
|
||||
|
||||
.. _SafeStack: https://clang.llvm.org/docs/SafeStack.html
|
||||
.. _RFG: http://xlab.tencent.com/en/2016/11/02/return-flow-guard
|
||||
.. _Intel CET: https://software.intel.com/en-us/blogs/2016/06/09/intel-release-new-technology-specifications-protect-rop-attacks
|
||||
|
||||
Hardware support
|
||||
================
|
||||
|
||||
We believe that the above design can be efficiently implemented in hardware.
|
||||
A single new instruction added to an ISA would allow to perform the CFI check
|
||||
A single new instruction added to an ISA would allow to perform the forward-edge CFI check
|
||||
with fewer bytes per check (smaller code size overhead) and potentially more
|
||||
efficiently. The current software-only instrumentation requires at least
|
||||
32-bytes per check (on x86_64).
|
||||
|
@ -540,7 +642,7 @@ The bit vector lookup is probably too complex for a hardware implementation.
|
|||
Jump(kFailedCheckTarget);
|
||||
}
|
||||
|
||||
An alternative and more compact enconding would not use `kFailedCheckTarget`,
|
||||
An alternative and more compact encoding would not use `kFailedCheckTarget`,
|
||||
and will trap on check failure instead.
|
||||
This will allow us to fit the instruction into **8-9 bytes**.
|
||||
The cross-DSO checks will be performed by a trap handler and
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -85,3 +85,16 @@ List of projects and tools
|
|||
errors, fixit hints). See also `<http://l.rw.rw/clang_plugin>`_ for
|
||||
step-by-step instructions."
|
||||
|
||||
`<https://phabricator.kde.org/source/clazy>`_
|
||||
"clazy is a compiler plugin which allows clang to understand Qt semantics.
|
||||
You get more than 50 Qt related compiler warnings, ranging from unneeded
|
||||
memory allocations to misusage of API, including fix-its for automatic
|
||||
refactoring."
|
||||
|
||||
`<https://gerrit.libreoffice.org/gitweb?p=core.git;a=blob_plain;f=compilerplugins/README;hb=HEAD>`_
|
||||
"LibreOffice uses a Clang plugin infrastructure to check during the build
|
||||
various things, some more, some less specific to the LibreOffice source code.
|
||||
There are currently around 50 such checkers, from flagging C-style casts and
|
||||
uses of reserved identifiers to ensuring that code adheres to lifecycle
|
||||
protocols for certain LibreOffice-specific classes. They may serve as
|
||||
examples for writing RecursiveASTVisitor-based plugins."
|
||||
|
|
|
@ -10,15 +10,16 @@ using link-time optimization; in the case where LTO is not being used, the
|
|||
linkage unit's LTO unit is empty. Each linkage unit has only a single LTO unit.
|
||||
|
||||
The LTO visibility of a class is used by the compiler to determine which
|
||||
classes the virtual function call optimization and control flow integrity
|
||||
features apply to. These features use whole-program information, so they
|
||||
require the entire class hierarchy to be visible in order to work correctly.
|
||||
classes the whole-program devirtualization (``-fwhole-program-vtables``) and
|
||||
control flow integrity (``-fsanitize=cfi-vcall``) features apply to. These
|
||||
features use whole-program information, so they require the entire class
|
||||
hierarchy to be visible in order to work correctly.
|
||||
|
||||
If any translation unit in the program uses either of the virtual function
|
||||
call optimization or control flow integrity features, it is effectively an
|
||||
ODR violation to define a class with hidden LTO visibility in multiple linkage
|
||||
If any translation unit in the program uses either of the whole-program
|
||||
devirtualization or control flow integrity features, it is effectively an ODR
|
||||
violation to define a class with hidden LTO visibility in multiple linkage
|
||||
units. A class with public LTO visibility may be defined in multiple linkage
|
||||
units, but the tradeoff is that the virtual function call optimization and
|
||||
units, but the tradeoff is that the whole-program devirtualization and
|
||||
control flow integrity features can only be applied to classes with hidden LTO
|
||||
visibility. A class's LTO visibility is treated as an ODR-relevant property
|
||||
of its definition, so it must be consistent between translation units.
|
||||
|
|
|
@ -356,7 +356,7 @@ is:
|
|||
|
||||
Query for this feature with ``__has_extension(attribute_ext_vector_type)``.
|
||||
|
||||
Giving ``-faltivec`` option to clang enables support for AltiVec vector syntax
|
||||
Giving ``-maltivec`` option to clang enables support for AltiVec vector syntax
|
||||
and functions. For example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
@ -780,14 +780,14 @@ Use ``__has_feature(cxx_variadic_templates)`` or
|
|||
``__has_extension(cxx_variadic_templates)`` to determine if support for
|
||||
variadic templates is enabled.
|
||||
|
||||
C++1y
|
||||
C++14
|
||||
-----
|
||||
|
||||
The features listed below are part of the committee draft for the C++1y
|
||||
standard. As a result, all these features are enabled with the ``-std=c++1y``
|
||||
or ``-std=gnu++1y`` option when compiling C++ code.
|
||||
The features listed below are part of the C++14 standard. As a result, all
|
||||
these features are enabled with the ``-std=C++14`` or ``-std=gnu++14`` option
|
||||
when compiling C++ code.
|
||||
|
||||
C++1y binary literals
|
||||
C++14 binary literals
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_binary_literals)`` or
|
||||
|
@ -795,37 +795,37 @@ Use ``__has_feature(cxx_binary_literals)`` or
|
|||
binary literals (for instance, ``0b10010``) are recognized. Clang supports this
|
||||
feature as an extension in all language modes.
|
||||
|
||||
C++1y contextual conversions
|
||||
C++14 contextual conversions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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++14 rules
|
||||
are used when performing an implicit conversion for an array bound in a
|
||||
*new-expression*, the operand of a *delete-expression*, an integral constant
|
||||
expression, or a condition in a ``switch`` statement.
|
||||
|
||||
C++1y decltype(auto)
|
||||
C++14 decltype(auto)
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_decltype_auto)`` or
|
||||
``__has_extension(cxx_decltype_auto)`` to determine if support
|
||||
for the ``decltype(auto)`` placeholder type is enabled.
|
||||
|
||||
C++1y default initializers for aggregates
|
||||
C++14 default initializers for aggregates
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_aggregate_nsdmi)`` or
|
||||
``__has_extension(cxx_aggregate_nsdmi)`` to determine if support
|
||||
for default initializers in aggregate members is enabled.
|
||||
|
||||
C++1y digit separators
|
||||
C++14 digit separators
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__cpp_digit_separators`` to determine if support for digit separators
|
||||
using single quotes (for instance, ``10'000``) is enabled. At this time, there
|
||||
is no corresponding ``__has_feature`` name
|
||||
|
||||
C++1y generalized lambda capture
|
||||
C++14 generalized lambda capture
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_init_captures)`` or
|
||||
|
@ -833,7 +833,7 @@ Use ``__has_feature(cxx_init_captures)`` or
|
|||
lambda captures with explicit initializers is enabled
|
||||
(for instance, ``[n(0)] { return ++n; }``).
|
||||
|
||||
C++1y generic lambdas
|
||||
C++14 generic lambdas
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_generic_lambdas)`` or
|
||||
|
@ -841,7 +841,7 @@ Use ``__has_feature(cxx_generic_lambdas)`` or
|
|||
(polymorphic) lambdas is enabled
|
||||
(for instance, ``[] (auto x) { return x + 1; }``).
|
||||
|
||||
C++1y relaxed constexpr
|
||||
C++14 relaxed constexpr
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_relaxed_constexpr)`` or
|
||||
|
@ -849,7 +849,7 @@ Use ``__has_feature(cxx_relaxed_constexpr)`` or
|
|||
declarations, local variable modification, and control flow constructs
|
||||
are permitted in ``constexpr`` functions.
|
||||
|
||||
C++1y return type deduction
|
||||
C++14 return type deduction
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_return_type_deduction)`` or
|
||||
|
@ -857,7 +857,7 @@ Use ``__has_feature(cxx_return_type_deduction)`` or
|
|||
for return type deduction for functions (using ``auto`` as a return type)
|
||||
is enabled.
|
||||
|
||||
C++1y runtime-sized arrays
|
||||
C++14 runtime-sized arrays
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_runtime_array)`` or
|
||||
|
@ -866,7 +866,7 @@ for arrays of runtime bound (a restricted form of variable-length arrays)
|
|||
is enabled.
|
||||
Clang's implementation of this feature is incomplete.
|
||||
|
||||
C++1y variable templates
|
||||
C++14 variable templates
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``__has_feature(cxx_variable_templates)`` or
|
||||
|
@ -993,6 +993,7 @@ The following type trait primitives are supported by Clang:
|
|||
* ``__has_trivial_destructor`` (GNU, Microsoft)
|
||||
* ``__has_virtual_destructor`` (GNU, Microsoft)
|
||||
* ``__is_abstract`` (GNU, Microsoft)
|
||||
* ``__is_aggregate`` (GNU, Microsoft)
|
||||
* ``__is_base_of`` (GNU, Microsoft)
|
||||
* ``__is_class`` (GNU, Microsoft)
|
||||
* ``__is_convertible_to`` (Microsoft)
|
||||
|
@ -1270,6 +1271,87 @@ Further examples of these attributes are available in the static analyzer's `lis
|
|||
Query for these features with ``__has_attribute(ns_consumed)``,
|
||||
``__has_attribute(ns_returns_retained)``, etc.
|
||||
|
||||
Objective-C @available
|
||||
----------------------
|
||||
|
||||
It is possible to use the newest SDK but still build a program that can run on
|
||||
older versions of macOS and iOS by passing ``-mmacosx-version-min=`` /
|
||||
``-miphoneos-version-min=``.
|
||||
|
||||
Before LLVM 5.0, when calling a function that exists only in the OS that's
|
||||
newer than the target OS (as determined by the minimum deployment version),
|
||||
programmers had to carefully check if the function exists at runtime, using
|
||||
null checks for weakly-linked C functions, ``+class`` for Objective-C classes,
|
||||
and ``-respondsToSelector:`` or ``+instancesRespondToSelector:`` for
|
||||
Objective-C methods. If such a check was missed, the program would compile
|
||||
fine, run fine on newer systems, but crash on older systems.
|
||||
|
||||
As of LLVM 5.0, ``-Wunguarded-availability`` uses the `availability attributes
|
||||
<http://clang.llvm.org/docs/AttributeReference.html#availability>`_ together
|
||||
with the new ``@available()`` keyword to assist with this issue.
|
||||
When a method that's introduced in the OS newer than the target OS is called, a
|
||||
-Wunguarded-availability warning is emitted if that call is not guarded:
|
||||
|
||||
.. code-block:: objc
|
||||
|
||||
void my_fun(NSSomeClass* var) {
|
||||
// If fancyNewMethod was added in e.g. macOS 10.12, but the code is
|
||||
// built with -mmacosx-version-min=10.11, then this unconditional call
|
||||
// will emit a -Wunguarded-availability warning:
|
||||
[var fancyNewMethod];
|
||||
}
|
||||
|
||||
To fix the warning and to avoid the crash on macOS 10.11, wrap it in
|
||||
``if(@available())``:
|
||||
|
||||
.. code-block:: objc
|
||||
|
||||
void my_fun(NSSomeClass* var) {
|
||||
if (@available(macOS 10.12, *)) {
|
||||
[var fancyNewMethod];
|
||||
} else {
|
||||
// Put fallback behavior for old macOS versions (and for non-mac
|
||||
// platforms) here.
|
||||
}
|
||||
}
|
||||
|
||||
The ``*`` is required and means that platforms not explicitly listed will take
|
||||
the true branch, and the compiler will emit ``-Wunguarded-availability``
|
||||
warnings for unlisted platforms based on those platform's deployment target.
|
||||
More than one platform can be listed in ``@available()``:
|
||||
|
||||
.. code-block:: objc
|
||||
|
||||
void my_fun(NSSomeClass* var) {
|
||||
if (@available(macOS 10.12, iOS 10, *)) {
|
||||
[var fancyNewMethod];
|
||||
}
|
||||
}
|
||||
|
||||
If the caller of ``my_fun()`` already checks that ``my_fun()`` is only called
|
||||
on 10.12, then add an `availability attribute
|
||||
<http://clang.llvm.org/docs/AttributeReference.html#availability>`_ to it,
|
||||
which will also suppress the warning and require that calls to my_fun() are
|
||||
checked:
|
||||
|
||||
.. code-block:: objc
|
||||
|
||||
API_AVAILABLE(macos(10.12)) void my_fun(NSSomeClass* var) {
|
||||
[var fancyNewMethod]; // Now ok.
|
||||
}
|
||||
|
||||
``@available()`` is only available in Objective-C code. To use the feature
|
||||
in C and C++ code, use the ``__builtin_available()`` spelling instead.
|
||||
|
||||
If existing code uses null checks or ``-respondsToSelector:``, it should
|
||||
be changed to use ``@available()`` (or ``__builtin_available``) instead.
|
||||
|
||||
``-Wunguarded-availability`` is disabled by default, but
|
||||
``-Wunguarded-availability-new``, which only emits this warning for APIs
|
||||
that have been introduced in macOS >= 10.13, iOS >= 11, watchOS >= 4 and
|
||||
tvOS >= 11, is enabled by default.
|
||||
|
||||
.. _langext-overloading:
|
||||
|
||||
Objective-C++ ABI: protocol-qualifier mangling of parameters
|
||||
------------------------------------------------------------
|
||||
|
@ -1286,8 +1368,6 @@ parameters of protocol-qualified type.
|
|||
Query the presence of this new mangling with
|
||||
``__has_feature(objc_protocol_qualifier_mangling)``.
|
||||
|
||||
.. _langext-overloading:
|
||||
|
||||
Initializer lists for complex numbers in C
|
||||
==========================================
|
||||
|
||||
|
@ -1780,7 +1860,7 @@ String builtins
|
|||
---------------
|
||||
|
||||
Clang provides constant expression evaluation support for builtins forms of
|
||||
the following functions from the C standard library ``<strings.h>`` header:
|
||||
the following functions from the C standard library ``<string.h>`` header:
|
||||
|
||||
* ``memchr``
|
||||
* ``memcmp``
|
||||
|
@ -2312,3 +2392,253 @@ For example, the hint ``vectorize_width(4)`` is ignored if the loop is not
|
|||
proven safe to vectorize. To identify and diagnose optimization issues use
|
||||
`-Rpass`, `-Rpass-missed`, and `-Rpass-analysis` command line options. See the
|
||||
user guide for details.
|
||||
|
||||
Extensions to specify floating-point flags
|
||||
====================================================
|
||||
|
||||
The ``#pragma clang fp`` pragma allows floating-point options to be specified
|
||||
for a section of the source code. This pragma can only appear at file scope or
|
||||
at the start of a compound statement (excluding comments). When using within a
|
||||
compound statement, the pragma is active within the scope of the compound
|
||||
statement.
|
||||
|
||||
Currently, only FP contraction can be controlled with the pragma. ``#pragma
|
||||
clang fp contract`` specifies whether the compiler should contract a multiply
|
||||
and an addition (or subtraction) into a fused FMA operation when supported by
|
||||
the target.
|
||||
|
||||
The pragma can take three values: ``on``, ``fast`` and ``off``. The ``on``
|
||||
option is identical to using ``#pragma STDC FP_CONTRACT(ON)`` and it allows
|
||||
fusion as specified the language standard. The ``fast`` option allows fusiong
|
||||
in cases when the language standard does not make this possible (e.g. across
|
||||
statements in C)
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
for(...) {
|
||||
#pragma clang fp contract(fast)
|
||||
a = b[i] * c[i];
|
||||
d[i] += a;
|
||||
}
|
||||
|
||||
|
||||
The pragma can also be used with ``off`` which turns FP contraction off for a
|
||||
section of the code. This can be useful when fast contraction is otherwise
|
||||
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
|
||||
|
||||
Specifying an attribute for multiple declarations (#pragma clang attribute)
|
||||
===========================================================================
|
||||
|
||||
The ``#pragma clang attribute`` directive can be used to apply an attribute to
|
||||
multiple declarations. The ``#pragma clang attribute push`` variation of the
|
||||
directive pushes a new attribute to the attribute stack. The declarations that
|
||||
follow the pragma receive the attributes that are on the attribute stack, until
|
||||
the stack is cleared using a ``#pragma clang attribute pop`` directive. Multiple
|
||||
push directives can be nested inside each other.
|
||||
|
||||
The attributes that are used in the ``#pragma clang attribute`` directives
|
||||
can be written using the GNU-style syntax:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push(__attribute__((annotate("custom"))), apply_to = function)
|
||||
|
||||
void function(); // The function now has the annotate("custom") attribute
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
The attributes can also be written using the C++11 style syntax:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push([[noreturn]], apply_to = function)
|
||||
|
||||
void function(); // The function now has the [[noreturn]] attribute
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
The ``__declspec`` style syntax is also supported:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push(__declspec(dllexport), apply_to = function)
|
||||
|
||||
void function(); // The function now has the __declspec(dllexport) attribute
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
A single push directive accepts only one attribute regardless of the syntax
|
||||
used.
|
||||
|
||||
Subject Match Rules
|
||||
-------------------
|
||||
|
||||
The set of declarations that receive a single attribute from the attribute stack
|
||||
depends on the subject match rules that were specified in the pragma. Subject
|
||||
match rules are specified after the attribute. The compiler expects an
|
||||
identifier that corresponds to the subject set specifier. The ``apply_to``
|
||||
specifier is currently the only supported subject set specifier. It allows you
|
||||
to specify match rules that form a subset of the attribute's allowed subject
|
||||
set, i.e. the compiler doesn't require all of the attribute's subjects. For
|
||||
example, an attribute like ``[[nodiscard]]`` whose subject set includes
|
||||
``enum``, ``record`` and ``hasType(functionType)``, requires the presence of at
|
||||
least one of these rules after ``apply_to``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push([[nodiscard]], apply_to = enum)
|
||||
|
||||
enum Enum1 { A1, B1 }; // The enum will receive [[nodiscard]]
|
||||
|
||||
struct Record1 { }; // The struct will *not* receive [[nodiscard]]
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
#pragma clang attribute push([[nodiscard]], apply_to = any(record, enum))
|
||||
|
||||
enum Enum2 { A2, B2 }; // The enum will receive [[nodiscard]]
|
||||
|
||||
struct Record2 { }; // The struct *will* receive [[nodiscard]]
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
// This is an error, since [[nodiscard]] can't be applied to namespaces:
|
||||
#pragma clang attribute push([[nodiscard]], apply_to = any(record, namespace))
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
Multiple match rules can be specified using the ``any`` match rule, as shown
|
||||
in the example above. The ``any`` rule applies attributes to all declarations
|
||||
that are matched by at least one of the rules in the ``any``. It doesn't nest
|
||||
and can't be used inside the other match rules. Redundant match rules or rules
|
||||
that conflict with one another should not be used inside of ``any``.
|
||||
|
||||
Clang supports the following match rules:
|
||||
|
||||
- ``function``: Can be used to apply attributes to functions. This includes C++
|
||||
member functions, static functions, operators, and constructors/destructors.
|
||||
|
||||
- ``function(is_member)``: Can be used to apply attributes to C++ member
|
||||
functions. This includes members like static functions, operators, and
|
||||
constructors/destructors.
|
||||
|
||||
- ``hasType(functionType)``: Can be used to apply attributes to functions, C++
|
||||
member functions, and variables/fields whose type is a function pointer. It
|
||||
does not apply attributes to Objective-C methods or blocks.
|
||||
|
||||
- ``type_alias``: Can be used to apply attributes to ``typedef`` declarations
|
||||
and C++11 type aliases.
|
||||
|
||||
- ``record``: Can be used to apply attributes to ``struct``, ``class``, and
|
||||
``union`` declarations.
|
||||
|
||||
- ``record(unless(is_union))``: Can be used to apply attributes only to
|
||||
``struct`` and ``class`` declarations.
|
||||
|
||||
- ``enum``: Can be be used to apply attributes to enumeration declarations.
|
||||
|
||||
- ``enum_constant``: Can be used to apply attributes to enumerators.
|
||||
|
||||
- ``variable``: Can be used to apply attributes to variables, including
|
||||
local variables, parameters, global variables, and static member variables.
|
||||
It does not apply attributes to instance member variables or Objective-C
|
||||
ivars.
|
||||
|
||||
- ``variable(is_thread_local)``: Can be used to apply attributes to thread-local
|
||||
variables only.
|
||||
|
||||
- ``variable(is_global)``: Can be used to apply attributes to global variables
|
||||
only.
|
||||
|
||||
- ``variable(is_parameter)``: Can be used to apply attributes to parameters
|
||||
only.
|
||||
|
||||
- ``variable(unless(is_parameter))``: Can be used to apply attributes to all
|
||||
the variables that are not parameters.
|
||||
|
||||
- ``field``: Can be used to apply attributes to non-static member variables
|
||||
in a record. This includes Objective-C ivars.
|
||||
|
||||
- ``namespace``: Can be used to apply attributes to ``namespace`` declarations.
|
||||
|
||||
- ``objc_interface``: Can be used to apply attributes to ``@interface``
|
||||
declarations.
|
||||
|
||||
- ``objc_protocol``: Can be used to apply attributes to ``@protocol``
|
||||
declarations.
|
||||
|
||||
- ``objc_category``: Can be used to apply attributes to category declarations,
|
||||
including class extensions.
|
||||
|
||||
- ``objc_method``: Can be used to apply attributes to Objective-C methods,
|
||||
including instance and class methods. Implicit methods like implicit property
|
||||
getters and setters do not receive the attribute.
|
||||
|
||||
- ``objc_method(is_instance)``: Can be used to apply attributes to Objective-C
|
||||
instance methods.
|
||||
|
||||
- ``objc_property``: Can be used to apply attributes to ``@property``
|
||||
declarations.
|
||||
|
||||
- ``block``: Can be used to apply attributes to block declarations. This does
|
||||
not include variables/fields of block pointer type.
|
||||
|
||||
The use of ``unless`` in match rules is currently restricted to a strict set of
|
||||
sub-rules that are used by the supported attributes. That means that even though
|
||||
``variable(unless(is_parameter))`` is a valid match rule,
|
||||
``variable(unless(is_thread_local))`` is not.
|
||||
|
||||
Supported Attributes
|
||||
--------------------
|
||||
|
||||
Not all attributes can be used with the ``#pragma clang attribute`` directive.
|
||||
Notably, statement attributes like ``[[fallthrough]]`` or type attributes
|
||||
like ``address_space`` aren't supported by this directive. You can determine
|
||||
whether or not an attribute is supported by the pragma by referring to the
|
||||
:doc:`individual documentation for that attribute <AttributeReference>`.
|
||||
|
||||
The attributes are applied to all matching declarations individually, even when
|
||||
the attribute is semantically incorrect. The attributes that aren't applied to
|
||||
any declaration are not verified semantically.
|
||||
|
||||
Specifying section names for global objects (#pragma clang section)
|
||||
===================================================================
|
||||
|
||||
The ``#pragma clang section`` directive provides a means to assign section-names
|
||||
to global variables, functions and static variables.
|
||||
|
||||
The section names can be specified as:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang section bss="myBSS" data="myData" rodata="myRodata" text="myText"
|
||||
|
||||
The section names can be reverted back to default name by supplying an empty
|
||||
string to the section kind, for example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang section bss="" data="" text="" rodata=""
|
||||
|
||||
The ``#pragma clang section`` directive obeys the following rules:
|
||||
|
||||
* The pragma applies to all global variable, statics and function declarations
|
||||
from the pragma to the end of the translation unit.
|
||||
|
||||
* The pragma clang section is enabled automatically, without need of any flags.
|
||||
|
||||
* This feature is only defined to work sensibly for ELF targets.
|
||||
|
||||
* If section name is specified through _attribute_((section("myname"))), then
|
||||
the attribute name gains precedence.
|
||||
|
||||
* Global variables that are initialized to zero will be placed in the named
|
||||
bss section, if one is present.
|
||||
|
||||
* The ``#pragma clang section`` directive does not does try to infer section-kind
|
||||
from the name. For example, naming a section "``.bss.mySec``" does NOT mean
|
||||
it will be a bss section name.
|
||||
|
||||
* The decision about which section-kind applies to each global is taken in the back-end.
|
||||
Once the section-kind is known, appropriate section name, as specified by the user using
|
||||
``#pragma clang section`` directive, is applied to that global.
|
||||
|
|
|
@ -337,6 +337,15 @@ nonTypeTemplateParmDecl()
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcCategoryDecl0')"><a name="objcCategoryDecl0Anchor">objcCategoryDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCCategoryDecl.html">ObjCCategoryDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="objcCategoryDecl0"><pre>Matches Objective-C category declarations.
|
||||
|
||||
Example matches Foo (Additions)
|
||||
@interface Foo (Additions)
|
||||
@end
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcInterfaceDecl0')"><a name="objcInterfaceDecl0Anchor">objcInterfaceDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="objcInterfaceDecl0"><pre>Matches Objective-C interface declarations.
|
||||
|
||||
|
@ -346,6 +355,50 @@ Example matches Foo
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcIvarDecl0')"><a name="objcIvarDecl0Anchor">objcIvarDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCIvarDecl.html">ObjCIvarDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="objcIvarDecl0"><pre>Matches Objective-C instance variable declarations.
|
||||
|
||||
Example matches _enabled
|
||||
@implementation Foo {
|
||||
BOOL _enabled;
|
||||
}
|
||||
@end
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcMethodDecl0')"><a name="objcMethodDecl0Anchor">objcMethodDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="objcMethodDecl0"><pre>Matches Objective-C method declarations.
|
||||
|
||||
Example matches both declaration and definition of -[Foo method]
|
||||
@interface Foo
|
||||
- (void)method;
|
||||
@end
|
||||
|
||||
@implementation Foo
|
||||
- (void)method {}
|
||||
@end
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcPropertyDecl0')"><a name="objcPropertyDecl0Anchor">objcPropertyDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCPropertyDecl.html">ObjCPropertyDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="objcPropertyDecl0"><pre>Matches Objective-C property declarations.
|
||||
|
||||
Example matches enabled
|
||||
@interface Foo
|
||||
@property BOOL enabled;
|
||||
@end
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcProtocolDecl0')"><a name="objcProtocolDecl0Anchor">objcProtocolDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCProtocolDecl.html">ObjCProtocolDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="objcProtocolDecl0"><pre>Matches Objective-C protocol declarations.
|
||||
|
||||
Example matches FooDelegate
|
||||
@protocol FooDelegate
|
||||
@end
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('parmVarDecl0')"><a name="parmVarDecl0Anchor">parmVarDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="parmVarDecl0"><pre>Matches parameter variable declarations.
|
||||
|
||||
|
@ -416,6 +469,15 @@ typeAliasDecl()
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('typeAliasTemplateDecl0')"><a name="typeAliasTemplateDecl0Anchor">typeAliasTemplateDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeAliasTemplateDecl.html">TypeAliasTemplateDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="typeAliasTemplateDecl0"><pre>Matches type alias template declarations.
|
||||
|
||||
typeAliasTemplateDecl() matches
|
||||
template <typename T>
|
||||
using Y = X<T>;
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('typedefDecl0')"><a name="typedefDecl0Anchor">typedefDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefDecl.html">TypedefDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="typedefDecl0"><pre>Matches typedef declarations.
|
||||
|
||||
|
@ -862,6 +924,19 @@ in
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxStdInitializerListExpr0')"><a name="cxxStdInitializerListExpr0Anchor">cxxStdInitializerListExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStdInitializerListExpr.html">CXXStdInitializerListExpr</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="cxxStdInitializerListExpr0"><pre>Matches C++ initializer list expressions.
|
||||
|
||||
Given
|
||||
std::vector<int> a({ 1, 2, 3 });
|
||||
std::vector<int> b = { 4, 5 };
|
||||
int c[] = { 6, 7 };
|
||||
std::pair<int, int> d = { 8, 9 };
|
||||
cxxStdInitializerListExpr()
|
||||
matches "{ 1, 2, 3 }" and "{ 4, 5 }"
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTemporaryObjectExpr0')"><a name="cxxTemporaryObjectExpr0Anchor">cxxTemporaryObjectExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTemporaryObjectExpr.html">CXXTemporaryObjectExpr</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="cxxTemporaryObjectExpr0"><pre>Matches functional cast expressions having N != 1 arguments
|
||||
|
||||
|
@ -1098,7 +1173,7 @@ Example matches [&](){return 5;}
|
|||
<tr><td colspan="4" class="doc" id="materializeTemporaryExpr0"><pre>Matches nodes where temporaries are materialized.
|
||||
|
||||
Example: Given
|
||||
struct T {void func()};
|
||||
struct T {void func();};
|
||||
T f();
|
||||
void g(T);
|
||||
materializeTemporaryExpr() matches 'f()' in these statements
|
||||
|
@ -1784,17 +1859,44 @@ Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<CXXBoolLiteral></td><td class="name" onclick="toggle('equals2')"><a name="equals2Anchor">equals</a></td><td>ValueT Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value.
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>></td><td class="name" onclick="toggle('equals2')"><a name="equals2Anchor">equals</a></td><td>ValueT Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value of type ValueT.
|
||||
|
||||
Example matches true (matcher = cxxBoolLiteral(equals(true)))
|
||||
true
|
||||
Given
|
||||
f('false, 3.14, 42);
|
||||
characterLiteral(equals(0))
|
||||
matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
|
||||
match false
|
||||
floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
|
||||
match 3.14
|
||||
integerLiteral(equals(42))
|
||||
matches 42
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
|
||||
Note that you cannot directly match a negative numeric literal because the
|
||||
minus sign is not part of the literal: It is a unary operator whose operand
|
||||
is the positive numeric literal. Instead, you must use a unaryOperator()
|
||||
matcher to match the minus sign:
|
||||
|
||||
unaryOperator(hasOperatorName("-"),
|
||||
hasUnaryOperand(integerLiteral(equals(13))))
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
|
||||
Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>></td><td class="name" onclick="toggle('equals5')"><a name="equals5Anchor">equals</a></td><td>bool Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals5"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>></td><td class="name" onclick="toggle('equals11')"><a name="equals11Anchor">equals</a></td><td>double Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals11"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>></td><td class="name" onclick="toggle('equals8')"><a name="equals8Anchor">equals</a></td><td>unsigned Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals8"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>></td><td class="name" onclick="toggle('isCatchAll0')"><a name="isCatchAll0Anchor">isCatchAll</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isCatchAll0"><pre>Matches a C++ catch statement that has a catch-all handler.
|
||||
|
||||
|
@ -2221,16 +2323,43 @@ Example: matches the implicit cast around 0
|
|||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>></td><td class="name" onclick="toggle('equals3')"><a name="equals3Anchor">equals</a></td><td>ValueT Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value.
|
||||
<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value of type ValueT.
|
||||
|
||||
Example matches true (matcher = cxxBoolLiteral(equals(true)))
|
||||
true
|
||||
Given
|
||||
f('false, 3.14, 42);
|
||||
characterLiteral(equals(0))
|
||||
matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
|
||||
match false
|
||||
floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
|
||||
match 3.14
|
||||
integerLiteral(equals(42))
|
||||
matches 42
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
|
||||
Note that you cannot directly match a negative numeric literal because the
|
||||
minus sign is not part of the literal: It is a unary operator whose operand
|
||||
is the positive numeric literal. Instead, you must use a unaryOperator()
|
||||
matcher to match the minus sign:
|
||||
|
||||
unaryOperator(hasOperatorName("-"),
|
||||
hasUnaryOperand(integerLiteral(equals(13))))
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
|
||||
Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>></td><td class="name" onclick="toggle('equals4')"><a name="equals4Anchor">equals</a></td><td>bool Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals4"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>></td><td class="name" onclick="toggle('equals10')"><a name="equals10Anchor">equals</a></td><td>double Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals10"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>></td><td class="name" onclick="toggle('equals7')"><a name="equals7Anchor">equals</a></td><td>unsigned Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals7"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('templateArgumentCountIs0')"><a name="templateArgumentCountIs0Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="templateArgumentCountIs0"><pre>Matches if the number of template arguments equals N.
|
||||
|
||||
|
@ -2458,16 +2587,35 @@ fieldDecl(isBitField())
|
|||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>></td><td class="name" onclick="toggle('equals1')"><a name="equals1Anchor">equals</a></td><td>ValueT Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value.
|
||||
<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value of type ValueT.
|
||||
|
||||
Example matches true (matcher = cxxBoolLiteral(equals(true)))
|
||||
true
|
||||
Given
|
||||
f('false, 3.14, 42);
|
||||
characterLiteral(equals(0))
|
||||
matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
|
||||
match false
|
||||
floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
|
||||
match 3.14
|
||||
integerLiteral(equals(42))
|
||||
matches 42
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
|
||||
Note that you cannot directly match a negative numeric literal because the
|
||||
minus sign is not part of the literal: It is a unary operator whose operand
|
||||
is the positive numeric literal. Instead, you must use a unaryOperator()
|
||||
matcher to match the minus sign:
|
||||
|
||||
unaryOperator(hasOperatorName("-"),
|
||||
hasUnaryOperand(integerLiteral(equals(13))))
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
|
||||
Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>></td><td class="name" onclick="toggle('equals12')"><a name="equals12Anchor">equals</a></td><td>double Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals12"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasDynamicExceptionSpec0')"><a name="hasDynamicExceptionSpec0Anchor">hasDynamicExceptionSpec</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasDynamicExceptionSpec0"><pre>Matches functions that have a dynamic exception specification.
|
||||
|
||||
|
@ -2730,16 +2878,43 @@ functionProtoType(parameterCountIs(3))
|
|||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>></td><td class="name" onclick="toggle('equals0')"><a name="equals0Anchor">equals</a></td><td>ValueT Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value.
|
||||
<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value of type ValueT.
|
||||
|
||||
Example matches true (matcher = cxxBoolLiteral(equals(true)))
|
||||
true
|
||||
Given
|
||||
f('false, 3.14, 42);
|
||||
characterLiteral(equals(0))
|
||||
matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
|
||||
match false
|
||||
floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
|
||||
match 3.14
|
||||
integerLiteral(equals(42))
|
||||
matches 42
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<CXXBoolLiteral>,
|
||||
Note that you cannot directly match a negative numeric literal because the
|
||||
minus sign is not part of the literal: It is a unary operator whose operand
|
||||
is the positive numeric literal. Instead, you must use a unaryOperator()
|
||||
matcher to match the minus sign:
|
||||
|
||||
unaryOperator(hasOperatorName("-"),
|
||||
hasUnaryOperand(integerLiteral(equals(13))))
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>,
|
||||
Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>></td><td class="name" onclick="toggle('equals6')"><a name="equals6Anchor">equals</a></td><td>bool Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals6"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>></td><td class="name" onclick="toggle('equals13')"><a name="equals13Anchor">equals</a></td><td>double Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals13"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>></td><td class="name" onclick="toggle('equals9')"><a name="equals9Anchor">equals</a></td><td>unsigned Value</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="equals9"><pre></pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('isArrow0')"><a name="isArrow0Anchor">isArrow</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isArrow0"><pre>Matches member expressions that are called with '->' as opposed
|
||||
to '.'.
|
||||
|
@ -5171,7 +5346,7 @@ Example matches y in x(y)
|
|||
<tr><td colspan="4" class="doc" id="hasReceiverType0"><pre>Matches on the receiver of an ObjectiveC Message expression.
|
||||
|
||||
Example
|
||||
matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
|
||||
matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
|
||||
matches the [webView ...] message invocation.
|
||||
NSString *webViewJavaScript = ...
|
||||
UIWebView *webView = ...
|
||||
|
@ -5419,7 +5594,7 @@ alignof.
|
|||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('forFunction0')"><a name="forFunction0Anchor">forFunction</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>> InnerMatcher</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="forFunction0"><pre>Matches declaration of the function the statemenet belongs to
|
||||
<tr><td colspan="4" class="doc" id="forFunction0"><pre>Matches declaration of the function the statement belongs to
|
||||
|
||||
Given:
|
||||
F& operator=(const F& o) {
|
||||
|
|
|
@ -28,7 +28,9 @@ The core routine of LibFormat is ``reformat()``:
|
|||
|
||||
This reads a token stream out of the lexer ``Lex`` and reformats all the code
|
||||
ranges in ``Ranges``. The ``FormatStyle`` controls basic decisions made during
|
||||
formatting. A list of options can be found under :ref:`style-options`.
|
||||
formatting. A list of options can be found under :ref:`style-options`.
|
||||
|
||||
The style options are described in :doc:`ClangFormatStyleOptions`.
|
||||
|
||||
|
||||
.. _style-options:
|
||||
|
|
|
@ -27,7 +27,7 @@ executable, so make sure to use ``clang`` (not ``ld``) for the final
|
|||
link step. When linking shared libraries, the MemorySanitizer run-time
|
||||
is not linked, so ``-Wl,-z,defs`` may cause link errors (don't use it
|
||||
with MemorySanitizer). To get a reasonable performance add ``-O1`` or
|
||||
higher. To get meaninful stack traces in error messages add
|
||||
higher. To get meaningful stack traces in error messages add
|
||||
``-fno-omit-frame-pointer``. To get perfect stack traces you may need
|
||||
to disable inlining (just use ``-O1``) and tail call elimination
|
||||
(``-fno-optimize-sibling-calls``).
|
||||
|
|
|
@ -360,6 +360,7 @@ The ``framework`` qualifier specifies that this module corresponds to a Darwin-s
|
|||
Name.framework/
|
||||
Modules/module.modulemap Module map for the framework
|
||||
Headers/ Subdirectory containing framework headers
|
||||
PrivateHeaders/ Subdirectory containing framework private headers
|
||||
Frameworks/ Subdirectory containing embedded frameworks
|
||||
Resources/ Subdirectory containing additional resources
|
||||
Name Symbolic link to the shared library for the framework
|
||||
|
@ -402,7 +403,7 @@ A *requires-declaration* specifies the requirements that an importing translatio
|
|||
*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 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. When building a module for use by a compilation, submodules requiring unavailable features are ignored. The optional ``!`` indicates that a feature is incompatible with the module.
|
||||
|
||||
The following features are defined:
|
||||
|
||||
|
@ -412,6 +413,9 @@ altivec
|
|||
blocks
|
||||
The "blocks" language feature is available.
|
||||
|
||||
coroutines
|
||||
Support for the coroutines TS is available.
|
||||
|
||||
cplusplus
|
||||
C++ support is available.
|
||||
|
||||
|
@ -465,9 +469,16 @@ A header declaration specifies that a particular header is associated with the e
|
|||
.. parsed-literal::
|
||||
|
||||
*header-declaration*:
|
||||
``private``:sub:`opt` ``textual``:sub:`opt` ``header`` *string-literal*
|
||||
``umbrella`` ``header`` *string-literal*
|
||||
``exclude`` ``header`` *string-literal*
|
||||
``private``:sub:`opt` ``textual``:sub:`opt` ``header`` *string-literal* *header-attrs*:sub:`opt`
|
||||
``umbrella`` ``header`` *string-literal* *header-attrs*:sub:`opt`
|
||||
``exclude`` ``header`` *string-literal* *header-attrs*:sub:`opt`
|
||||
|
||||
*header-attrs*:
|
||||
'{' *header-attr** '}'
|
||||
|
||||
*header-attr*:
|
||||
``size`` *integer-literal*
|
||||
``mtime`` *integer-literal*
|
||||
|
||||
A header declaration that does not contain ``exclude`` nor ``textual`` 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.
|
||||
|
||||
|
@ -500,6 +511,18 @@ A header with the ``exclude`` specifier is excluded from the module. It will not
|
|||
|
||||
A given header shall not be referenced by more than one *header-declaration*.
|
||||
|
||||
Two *header-declaration*\s, or a *header-declaration* and a ``#include``, are
|
||||
considered to refer to the same file if the paths resolve to the same file
|
||||
and the specified *header-attr*\s (if any) match the attributes of that file,
|
||||
even if the file is named differently (for instance, by a relative path or
|
||||
via symlinks).
|
||||
|
||||
.. note::
|
||||
The use of *header-attr*\s avoids the need for Clang to speculatively
|
||||
``stat`` every header referenced by a module map. It is recommended that
|
||||
*header-attr*\s only be used in machine-generated module maps, to avoid
|
||||
mismatches between attribute values and the corresponding files.
|
||||
|
||||
Umbrella directory declaration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
An umbrella directory declaration specifies that all of the headers in the specified directory should be included within the module.
|
||||
|
@ -842,6 +865,16 @@ would be available when ``Foo_Private.h`` is available, making it
|
|||
easier to split a library's public and private APIs along header
|
||||
boundaries.
|
||||
|
||||
When writing a private module as part of a *framework*, it's recommended that:
|
||||
|
||||
* Headers for this module are present in the ``PrivateHeaders``
|
||||
framework subdirectory.
|
||||
* The private module is defined as a *submodule* of the public framework (if
|
||||
there's one), similar to how ``Foo.Private`` is defined in the example above.
|
||||
* The ``explicit`` keyword should be used to guarantee that its content will
|
||||
only be available when the submodule itself is explicitly named (through a
|
||||
``@import`` for example).
|
||||
|
||||
Modularizing a Platform
|
||||
=======================
|
||||
To get any benefit out of modules, one needs to introduce module maps for software libraries starting at the bottom of the stack. This typically means introducing a module map covering the operating system's headers and the C standard library headers (in ``/usr/include``, for a Unix system).
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
=======================================
|
||||
Clang 4.0.0 (In-Progress) Release Notes
|
||||
Clang 5.0.0 (In-Progress) Release Notes
|
||||
=======================================
|
||||
|
||||
.. contents::
|
||||
|
@ -10,15 +10,15 @@ Written by the `LLVM Team <http://llvm.org/>`_
|
|||
|
||||
.. warning::
|
||||
|
||||
These are in-progress notes for the upcoming Clang 4.0.0 release. You may
|
||||
prefer the `Clang 3.9 Release Notes
|
||||
<http://llvm.org/releases/3.9.0/tools/clang/docs/ReleaseNotes.html>`_.
|
||||
These are in-progress notes for the upcoming Clang 5 release.
|
||||
Release notes for previous releases can be found on
|
||||
`the Download Page <http://releases.llvm.org/download.html>`_.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document contains the release notes for the Clang C/C++/Objective-C
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 4.0.0. Here we
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 5.0.0. Here we
|
||||
describe the status of Clang in some detail, including major
|
||||
improvements from the previous release and new feature work. For the
|
||||
general LLVM release notes, see `the LLVM
|
||||
|
@ -31,7 +31,12 @@ the latest release, please check out the main please see the `Clang Web
|
|||
Site <http://clang.llvm.org>`_ or the `LLVM Web
|
||||
Site <http://llvm.org>`_.
|
||||
|
||||
What's New in Clang 4.0.0?
|
||||
Note that if you are reading this file from a Subversion checkout or the
|
||||
main Clang web page, this document applies to the *next* release, not
|
||||
the current one. To see the release notes for a specific release, please
|
||||
see the `releases page <http://llvm.org/releases/>`_.
|
||||
|
||||
What's New in Clang 5.0.0?
|
||||
==========================
|
||||
|
||||
Some of the major new features and improvements to Clang are listed
|
||||
|
@ -42,56 +47,32 @@ sections with improvements to Clang's support for those languages.
|
|||
Major New Features
|
||||
------------------
|
||||
|
||||
- The ``diagnose_if`` attribute has been added to clang. This attribute allows
|
||||
clang to emit a warning or error if a function call meets one or more
|
||||
user-specified conditions.
|
||||
|
||||
- Enhanced devirtualization with
|
||||
`-fstrict-vtable-pointers <UsersManual.html#cmdoption-fstrict-vtable-pointers>`_.
|
||||
Clang devirtualizes across different basic blocks, like loops:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
struct A {
|
||||
virtual void foo();
|
||||
};
|
||||
void indirect(A &a, int n) {
|
||||
for (int i = 0 ; i < n; i++)
|
||||
a.foo();
|
||||
}
|
||||
void test(int n) {
|
||||
A a;
|
||||
indirect(a, n);
|
||||
}
|
||||
|
||||
|
||||
- ...
|
||||
|
||||
Improvements to ThinLTO (-flto=thin)
|
||||
------------------------------------
|
||||
- Integration with profile data (PGO). When available, profile data enables
|
||||
more accurate function importing decisions, as well as cross-module indirect
|
||||
call promotion.
|
||||
- Significant build-time and binary-size improvements when compiling with debug
|
||||
info (-g).
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- ...
|
||||
- -Wcast-qual was implemented for C++. C-style casts are now properly
|
||||
diagnosed.
|
||||
|
||||
- -Wunused-lambda-capture warns when a variable explicitly captured
|
||||
by a lambda is not used in the body of the lambda.
|
||||
|
||||
New Compiler Flags
|
||||
------------------
|
||||
|
||||
The option -Og has been added to optimize the debugging experience.
|
||||
For now, this option is exactly the same as -O1. However, in the future,
|
||||
some other optimizations might be enabled or disabled.
|
||||
|
||||
The option -MJ has been added to simplify adding JSON compilation
|
||||
database output into existing build systems.
|
||||
|
||||
The option ....
|
||||
|
||||
Deprecated Compiler Flags
|
||||
-------------------------
|
||||
|
||||
The following options are deprecated and ignored. They will be removed in
|
||||
future versions of Clang.
|
||||
|
||||
- -fslp-vectorize-aggressive used to enable the BB vectorizing pass. They have been superseeded
|
||||
by the normal SLP vectorizer.
|
||||
- -fno-slp-vectorize-aggressive used to be the default behavior of clang.
|
||||
|
||||
New Pragmas in Clang
|
||||
-----------------------
|
||||
|
||||
|
@ -101,7 +82,9 @@ Clang now supports the ...
|
|||
Attribute Changes in Clang
|
||||
--------------------------
|
||||
|
||||
- ...
|
||||
- The ``overloadable`` attribute now allows at most one function with a given
|
||||
name to lack the ``overloadable`` attribute. This unmarked function will not
|
||||
have its name mangled.
|
||||
|
||||
Windows Support
|
||||
---------------
|
||||
|
@ -149,7 +132,7 @@ OpenMP Support in Clang
|
|||
Internal API Changes
|
||||
--------------------
|
||||
|
||||
These are major API changes that have happened since the 3.9 release of
|
||||
These are major API changes that have happened since the 4.0.0 release of
|
||||
Clang. If upgrading an external codebase that uses Clang as a library,
|
||||
this section should help get you past the largest hurdles of upgrading.
|
||||
|
||||
|
@ -160,20 +143,90 @@ AST Matchers
|
|||
|
||||
...
|
||||
|
||||
|
||||
clang-format
|
||||
------------
|
||||
|
||||
* Option **BreakBeforeInheritanceComma** added to break before ``:`` and ``,`` in case of
|
||||
multiple inheritance in a class declaration. Enabled by default in the Mozilla coding style.
|
||||
|
||||
+---------------------+----------------------------------------+
|
||||
| true | false |
|
||||
+=====================+========================================+
|
||||
| .. code-block:: c++ | .. code-block:: c++ |
|
||||
| | |
|
||||
| class MyClass | class MyClass : public X, public Y { |
|
||||
| : public X | }; |
|
||||
| , public Y { | |
|
||||
| }; | |
|
||||
+---------------------+----------------------------------------+
|
||||
|
||||
* Align block comment decorations.
|
||||
|
||||
+----------------------+---------------------+
|
||||
| Before | After |
|
||||
+======================+=====================+
|
||||
| .. code-block:: c++ | .. code-block:: c++ |
|
||||
| | |
|
||||
| /* line 1 | /* line 1 |
|
||||
| * line 2 | * line 2 |
|
||||
| */ | */ |
|
||||
+----------------------+---------------------+
|
||||
|
||||
* The :doc:`ClangFormatStyleOptions` documentation provides detailed examples for most options.
|
||||
|
||||
* Namespace end comments are now added or updated automatically.
|
||||
|
||||
+---------------------+---------------------+
|
||||
| Before | After |
|
||||
+=====================+=====================+
|
||||
| .. code-block:: c++ | .. code-block:: c++ |
|
||||
| | |
|
||||
| namespace A { | namespace A { |
|
||||
| int i; | int i; |
|
||||
| int j; | int j; |
|
||||
| } | } |
|
||||
+---------------------+---------------------+
|
||||
|
||||
* Comment reflow support added. Overly long comment lines will now be reflown with the rest of
|
||||
the paragraph instead of just broken. Option **ReflowComments** added and enabled by default.
|
||||
|
||||
libclang
|
||||
--------
|
||||
|
||||
...
|
||||
|
||||
With the option --show-description, scan-build's list of defects will also
|
||||
show the description of the defects.
|
||||
|
||||
|
||||
Static Analyzer
|
||||
---------------
|
||||
|
||||
...
|
||||
|
||||
Undefined Behavior Sanitizer (UBSan)
|
||||
------------------------------------
|
||||
|
||||
- The Undefined Behavior Sanitizer has a new check for pointer overflow. This
|
||||
check is on by default. The flag to control this functionality is
|
||||
-fsanitize=pointer-overflow.
|
||||
|
||||
Pointer overflow is an indicator of undefined behavior: when a pointer
|
||||
indexing expression wraps around the address space, or produces other
|
||||
unexpected results, its result may not point to a valid object.
|
||||
|
||||
- UBSan has several new checks which detect violations of nullability
|
||||
annotations. These checks are off by default. The flag to control this group
|
||||
of checks is -fsanitize=nullability. The checks can be individially enabled
|
||||
by -fsanitize=nullability-arg (which checks calls),
|
||||
-fsanitize=nullability-assign (which checks assignments), and
|
||||
-fsanitize=nullability-return (which checks return statements).
|
||||
|
||||
- UBSan can now detect invalid loads from bitfields and from ObjC BOOLs.
|
||||
|
||||
- UBSan can now avoid emitting unnecessary type checks in C++ class methods and
|
||||
in several other cases where the result is known at compile-time. UBSan can
|
||||
also avoid emitting unnecessary overflow checks in arithmetic expressions
|
||||
with promoted integer operands.
|
||||
|
||||
Core Analysis Improvements
|
||||
==========================
|
||||
|
||||
|
|
|
@ -8,351 +8,35 @@ SanitizerCoverage
|
|||
Introduction
|
||||
============
|
||||
|
||||
Sanitizer tools have a very simple code coverage tool built in. It allows to
|
||||
get function-level, basic-block-level, and edge-level coverage at a very low
|
||||
cost.
|
||||
|
||||
How to build and run
|
||||
====================
|
||||
|
||||
SanitizerCoverage can be used with :doc:`AddressSanitizer`,
|
||||
:doc:`LeakSanitizer`, :doc:`MemorySanitizer`,
|
||||
UndefinedBehaviorSanitizer, or without any sanitizer. Pass one of the
|
||||
following compile-time flags:
|
||||
|
||||
* ``-fsanitize-coverage=func`` for function-level coverage (very fast).
|
||||
* ``-fsanitize-coverage=bb`` for basic-block-level coverage (may add up to 30%
|
||||
**extra** slowdown).
|
||||
* ``-fsanitize-coverage=edge`` for edge-level coverage (up to 40% slowdown).
|
||||
|
||||
You may also specify ``-fsanitize-coverage=indirect-calls`` for
|
||||
additional `caller-callee coverage`_.
|
||||
|
||||
At run time, pass ``coverage=1`` in ``ASAN_OPTIONS``,
|
||||
``LSAN_OPTIONS``, ``MSAN_OPTIONS`` or ``UBSAN_OPTIONS``, as
|
||||
appropriate. For the standalone coverage mode, use ``UBSAN_OPTIONS``.
|
||||
|
||||
To get `Coverage counters`_, add ``-fsanitize-coverage=8bit-counters``
|
||||
to one of the above compile-time flags. At runtime, use
|
||||
``*SAN_OPTIONS=coverage=1:coverage_counters=1``.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% cat -n cov.cc
|
||||
1 #include <stdio.h>
|
||||
2 __attribute__((noinline))
|
||||
3 void foo() { printf("foo\n"); }
|
||||
4
|
||||
5 int main(int argc, char **argv) {
|
||||
6 if (argc == 2)
|
||||
7 foo();
|
||||
8 printf("main\n");
|
||||
9 }
|
||||
% clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=func
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out; ls -l *sancov
|
||||
main
|
||||
-rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out foo ; ls -l *sancov
|
||||
foo
|
||||
main
|
||||
-rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
|
||||
-rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
|
||||
|
||||
Every time you run an executable instrumented with SanitizerCoverage
|
||||
one ``*.sancov`` file is created during the process shutdown.
|
||||
If the executable is dynamically linked against instrumented DSOs,
|
||||
one ``*.sancov`` file will be also created for every DSO.
|
||||
|
||||
Postprocessing
|
||||
==============
|
||||
|
||||
The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic,
|
||||
one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the
|
||||
magic defines the size of the following offsets. The rest of the data is the
|
||||
offsets in the corresponding binary/DSO that were executed during the run.
|
||||
|
||||
A simple script
|
||||
``$LLVM/projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py`` is
|
||||
provided to dump these offsets.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% sancov.py print a.out.22679.sancov a.out.22673.sancov
|
||||
sancov.py: read 2 PCs from a.out.22679.sancov
|
||||
sancov.py: read 1 PCs from a.out.22673.sancov
|
||||
sancov.py: 2 files merged; 2 PCs total
|
||||
0x465250
|
||||
0x4652a0
|
||||
|
||||
You can then filter the output of ``sancov.py`` through ``addr2line --exe
|
||||
ObjectFile`` or ``llvm-symbolizer --obj ObjectFile`` to get file names and line
|
||||
numbers:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% sancov.py print a.out.22679.sancov a.out.22673.sancov 2> /dev/null | llvm-symbolizer --obj a.out
|
||||
cov.cc:3
|
||||
cov.cc:5
|
||||
|
||||
Sancov Tool
|
||||
===========
|
||||
|
||||
A new experimental ``sancov`` tool is developed to process coverage files.
|
||||
The tool is part of LLVM project and is currently supported only on Linux.
|
||||
It can handle symbolization tasks autonomously without any extra support
|
||||
from the environment. You need to pass .sancov files (named
|
||||
``<module_name>.<pid>.sancov`` and paths to all corresponding binary elf files.
|
||||
Sancov matches these files using module names and binaries file names.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
USAGE: sancov [options] <action> (<binary file>|<.sancov file>)...
|
||||
|
||||
Action (required)
|
||||
-print - Print coverage addresses
|
||||
-covered-functions - Print all covered functions.
|
||||
-not-covered-functions - Print all not covered functions.
|
||||
-symbolize - Symbolizes the report.
|
||||
|
||||
Options
|
||||
-blacklist=<string> - Blacklist file (sanitizer blacklist format).
|
||||
-demangle - Print demangled function name.
|
||||
-strip_path_prefix=<string> - Strip this prefix from file paths in reports
|
||||
|
||||
|
||||
Coverage Reports (Experimental)
|
||||
================================
|
||||
|
||||
``.sancov`` files do not contain enough information to generate a source-level
|
||||
coverage report. The missing information is contained
|
||||
in debug info of the binary. Thus the ``.sancov`` has to be symbolized
|
||||
to produce a ``.symcov`` file first:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sancov -symbolize my_program.123.sancov my_program > my_program.123.symcov
|
||||
|
||||
The ``.symcov`` file can be browsed overlayed over the source code by
|
||||
running ``tools/sancov/coverage-report-server.py`` script that will start
|
||||
an HTTP server.
|
||||
|
||||
|
||||
How good is the coverage?
|
||||
=========================
|
||||
|
||||
It is possible to find out which PCs are not covered, by subtracting the covered
|
||||
set from the set of all instrumented PCs. The latter can be obtained by listing
|
||||
all callsites of ``__sanitizer_cov()`` in the binary. On Linux, ``sancov.py``
|
||||
can do this for you. Just supply the path to binary and a list of covered PCs:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% sancov.py print a.out.12345.sancov > covered.txt
|
||||
sancov.py: read 2 64-bit PCs from a.out.12345.sancov
|
||||
sancov.py: 1 file merged; 2 PCs total
|
||||
% sancov.py missing a.out < covered.txt
|
||||
sancov.py: found 3 instrumented PCs in a.out
|
||||
sancov.py: read 2 PCs from stdin
|
||||
sancov.py: 1 PCs missing from coverage
|
||||
0x4cc61c
|
||||
|
||||
Edge coverage
|
||||
=============
|
||||
|
||||
Consider this code:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void foo(int *a) {
|
||||
if (a)
|
||||
*a = 0;
|
||||
}
|
||||
|
||||
It contains 3 basic blocks, let's name them A, B, C:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
A
|
||||
|\
|
||||
| \
|
||||
| B
|
||||
| /
|
||||
|/
|
||||
C
|
||||
|
||||
If blocks A, B, and C are all covered we know for certain that the edges A=>B
|
||||
and B=>C were executed, but we still don't know if the edge A=>C was executed.
|
||||
Such edges of control flow graph are called
|
||||
`critical <http://en.wikipedia.org/wiki/Control_flow_graph#Special_edges>`_. The
|
||||
edge-level coverage (``-fsanitize-coverage=edge``) simply splits all critical
|
||||
edges by introducing new dummy blocks and then instruments those blocks:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
A
|
||||
|\
|
||||
| \
|
||||
D B
|
||||
| /
|
||||
|/
|
||||
C
|
||||
|
||||
Bitset
|
||||
======
|
||||
|
||||
When ``coverage_bitset=1`` run-time flag is given, the coverage will also be
|
||||
dumped as a bitset (text file with 1 for blocks that have been executed and 0
|
||||
for blocks that were not).
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -fsanitize=address -fsanitize-coverage=edge cov.cc
|
||||
% ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out
|
||||
main
|
||||
% ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out 1
|
||||
foo
|
||||
main
|
||||
% head *bitset*
|
||||
==> a.out.38214.bitset-sancov <==
|
||||
01101
|
||||
==> a.out.6128.bitset-sancov <==
|
||||
11011%
|
||||
|
||||
For a given executable the length of the bitset is always the same (well,
|
||||
unless dlopen/dlclose come into play), so the bitset coverage can be
|
||||
easily used for bitset-based corpus distillation.
|
||||
|
||||
Caller-callee coverage
|
||||
======================
|
||||
|
||||
(Experimental!)
|
||||
Every indirect function call is instrumented with a run-time function call that
|
||||
captures caller and callee. At the shutdown time the process dumps a separate
|
||||
file called ``caller-callee.PID.sancov`` which contains caller/callee pairs as
|
||||
pairs of lines (odd lines are callers, even lines are callees)
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
a.out 0x4a2e0c
|
||||
a.out 0x4a6510
|
||||
a.out 0x4a2e0c
|
||||
a.out 0x4a87f0
|
||||
|
||||
Current limitations:
|
||||
|
||||
* Only the first 14 callees for every caller are recorded, the rest are silently
|
||||
ignored.
|
||||
* The output format is not very compact since caller and callee may reside in
|
||||
different modules and we need to spell out the module names.
|
||||
* The routine that dumps the output is not optimized for speed
|
||||
* Only Linux x86_64 is tested so far.
|
||||
* Sandboxes are not supported.
|
||||
|
||||
Coverage counters
|
||||
=================
|
||||
|
||||
This experimental feature is inspired by
|
||||
`AFL <http://lcamtuf.coredump.cx/afl/technical_details.txt>`__'s coverage
|
||||
instrumentation. With additional compile-time and run-time flags you can get
|
||||
more sensitive coverage information. In addition to boolean values assigned to
|
||||
every basic block (edge) the instrumentation will collect imprecise counters.
|
||||
On exit, every counter will be mapped to a 8-bit bitset representing counter
|
||||
ranges: ``1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+`` and those 8-bit bitsets will
|
||||
be dumped to disk.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=edge,8bit-counters
|
||||
% ASAN_OPTIONS="coverage=1:coverage_counters=1" ./a.out
|
||||
% ls -l *counters-sancov
|
||||
... a.out.17110.counters-sancov
|
||||
% xxd *counters-sancov
|
||||
0000000: 0001 0100 01
|
||||
|
||||
These counters may also be used for in-process coverage-guided fuzzers. See
|
||||
``include/sanitizer/coverage_interface.h``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// The coverage instrumentation may optionally provide imprecise counters.
|
||||
// Rather than exposing the counter values to the user we instead map
|
||||
// the counters to a bitset.
|
||||
// Every counter is associated with 8 bits in the bitset.
|
||||
// We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+
|
||||
// The i-th bit is set to 1 if the counter value is in the i-th range.
|
||||
// This counter-based coverage implementation is *not* thread-safe.
|
||||
|
||||
// Returns the number of registered coverage counters.
|
||||
uintptr_t __sanitizer_get_number_of_counters();
|
||||
// Updates the counter 'bitset', clears the counters and returns the number of
|
||||
// new bits in 'bitset'.
|
||||
// If 'bitset' is nullptr, only clears the counters.
|
||||
// Otherwise 'bitset' should be at least
|
||||
// __sanitizer_get_number_of_counters bytes long and 8-aligned.
|
||||
uintptr_t
|
||||
__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
|
||||
|
||||
Tracing basic blocks
|
||||
====================
|
||||
Experimental support for basic block (or edge) tracing.
|
||||
With ``-fsanitize-coverage=trace-bb`` the compiler will insert
|
||||
``__sanitizer_cov_trace_basic_block(s32 *id)`` before every function, basic block, or edge
|
||||
(depending on the value of ``-fsanitize-coverage=[func,bb,edge]``).
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang -g -fsanitize=address -fsanitize-coverage=edge,trace-bb foo.cc
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out
|
||||
|
||||
This will produce two files after the process exit:
|
||||
`trace-points.PID.sancov` and `trace-events.PID.sancov`.
|
||||
The first file will contain a textual description of all the instrumented points in the program
|
||||
in the form that you can feed into llvm-symbolizer (e.g. `a.out 0x4dca89`), one per line.
|
||||
The second file will contain the actual execution trace as a sequence of 4-byte integers
|
||||
-- these integers are the indices into the array of instrumented points (the first file).
|
||||
|
||||
Basic block tracing is currently supported only for single-threaded applications.
|
||||
|
||||
|
||||
Tracing PCs
|
||||
===========
|
||||
*Experimental* feature similar to tracing basic blocks, but with a different API.
|
||||
With ``-fsanitize-coverage=trace-pc`` the compiler will insert
|
||||
``__sanitizer_cov_trace_pc()`` on every edge.
|
||||
With an additional ``...=trace-pc,indirect-calls`` flag
|
||||
``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
|
||||
These callbacks are not implemented in the Sanitizer run-time and should be defined
|
||||
by the user. So, these flags do not require the other sanitizer to be used.
|
||||
This mechanism is used for fuzzing the Linux kernel (https://github.com/google/syzkaller)
|
||||
and can be used with `AFL <http://lcamtuf.coredump.cx/afl>`__.
|
||||
LLVM has a simple code coverage instrumentation built in (SanitizerCoverage).
|
||||
It inserts calls to user-defined functions on function-, basic-block-, and edge- levels.
|
||||
Default implementations of those callbacks are provided and implement
|
||||
simple coverage reporting and visualization,
|
||||
however if you need *just* coverage visualization you may want to use
|
||||
:doc:`SourceBasedCodeCoverage <SourceBasedCodeCoverage>` instead.
|
||||
|
||||
Tracing PCs with guards
|
||||
=======================
|
||||
Another *experimental* feature that tries to combine the functionality of `trace-pc`,
|
||||
`8bit-counters` and boolean coverage.
|
||||
|
||||
With ``-fsanitize-coverage=trace-pc-guard`` the compiler will insert the following code
|
||||
on every edge:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
if (guard_variable)
|
||||
__sanitizer_cov_trace_pc_guard(&guard_variable)
|
||||
__sanitizer_cov_trace_pc_guard(&guard_variable)
|
||||
|
||||
Every edge will have its own `guard_variable` (uint32_t).
|
||||
|
||||
The compler will also insert a module constructor that will call
|
||||
The compler will also insert calls to a module constructor:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// The guards are [start, stop).
|
||||
// This function may be called multiple times with the same values of start/stop.
|
||||
// This function will be called at least once per DSO and may be called
|
||||
// more than once with the same values of start/stop.
|
||||
__sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop);
|
||||
|
||||
Similarly to `trace-pc,indirect-calls`, with `trace-pc-guards,indirect-calls`
|
||||
With an additional ``...=trace-pc,indirect-calls`` flag
|
||||
``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
|
||||
|
||||
The functions `__sanitizer_cov_trace_pc_*` should be defined by the user.
|
||||
|
@ -367,10 +51,10 @@ Example:
|
|||
#include <sanitizer/coverage_interface.h>
|
||||
|
||||
// This callback is inserted by the compiler as a module constructor
|
||||
// into every compilation unit. 'start' and 'stop' correspond to the
|
||||
// into every DSO. 'start' and 'stop' correspond to the
|
||||
// beginning and end of the section with the guards for the entire
|
||||
// binary (executable or DSO) and so it will be called multiple times
|
||||
// with the same parameters.
|
||||
// binary (executable or DSO). The callback will be called at least
|
||||
// once per DSO and may be called multiple times with the same parameters.
|
||||
extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
|
||||
uint32_t *stop) {
|
||||
static uint64_t N; // Counter for the guards.
|
||||
|
@ -435,6 +119,76 @@ Example:
|
|||
guard: 0x71bcdc 4 PC 0x4ecdc7 in main trace-pc-guard-example.cc:4:17
|
||||
guard: 0x71bcd0 1 PC 0x4ecd20 in foo() trace-pc-guard-example.cc:2:14
|
||||
|
||||
Tracing PCs
|
||||
===========
|
||||
|
||||
With ``-fsanitize-coverage=trace-pc`` the compiler will insert
|
||||
``__sanitizer_cov_trace_pc()`` on every edge.
|
||||
With an additional ``...=trace-pc,indirect-calls`` flag
|
||||
``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
|
||||
These callbacks are not implemented in the Sanitizer run-time and should be defined
|
||||
by the user.
|
||||
This mechanism is used for fuzzing the Linux kernel
|
||||
(https://github.com/google/syzkaller).
|
||||
|
||||
|
||||
Instrumentation points
|
||||
======================
|
||||
Sanitizer Coverage offers different levels of instrumentation.
|
||||
|
||||
* ``edge`` (default): edges are instrumented (see below).
|
||||
* ``bb``: basic blocks are instrumented.
|
||||
* ``func``: only the entry block of every function will be instrumented.
|
||||
|
||||
Use these flags together with ``trace-pc-guard`` or ``trace-pc``,
|
||||
like this: ``-fsanitize-coverage=func,trace-pc-guard``.
|
||||
|
||||
When ``edge`` or ``bb`` is used, some of the edges/blocks may still be left
|
||||
uninstrumented (pruned) if such instrumentation is considered redundant.
|
||||
Use ``no-prune`` (e.g. ``-fsanitize-coverage=bb,no-prune,trace-pc-guard``)
|
||||
to disable pruning. This could be useful for better coverage visualization.
|
||||
|
||||
|
||||
Edge coverage
|
||||
-------------
|
||||
|
||||
Consider this code:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void foo(int *a) {
|
||||
if (a)
|
||||
*a = 0;
|
||||
}
|
||||
|
||||
It contains 3 basic blocks, let's name them A, B, C:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
A
|
||||
|\
|
||||
| \
|
||||
| B
|
||||
| /
|
||||
|/
|
||||
C
|
||||
|
||||
If blocks A, B, and C are all covered we know for certain that the edges A=>B
|
||||
and B=>C were executed, but we still don't know if the edge A=>C was executed.
|
||||
Such edges of control flow graph are called
|
||||
`critical <http://en.wikipedia.org/wiki/Control_flow_graph#Special_edges>`_. The
|
||||
edge-level coverage simply splits all critical
|
||||
edges by introducing new dummy blocks and then instruments those blocks:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
A
|
||||
|\
|
||||
| \
|
||||
D B
|
||||
| /
|
||||
|/
|
||||
C
|
||||
|
||||
Tracing data flow
|
||||
=================
|
||||
|
@ -475,10 +229,100 @@ the `LLVM GEP instructions <http://llvm.org/docs/GetElementPtr.html>`_
|
|||
|
||||
|
||||
This interface is a subject to change.
|
||||
The current implementation is not thread-safe and thus can be safely used only for single-threaded targets.
|
||||
|
||||
Default implementation
|
||||
======================
|
||||
|
||||
The sanitizer run-time (AddressSanitizer, MemorySanitizer, etc) provide a
|
||||
default implementations of some of the coverage callbacks.
|
||||
You may use this implementation to dump the coverage on disk at the process
|
||||
exit.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% cat -n cov.cc
|
||||
1 #include <stdio.h>
|
||||
2 __attribute__((noinline))
|
||||
3 void foo() { printf("foo\n"); }
|
||||
4
|
||||
5 int main(int argc, char **argv) {
|
||||
6 if (argc == 2)
|
||||
7 foo();
|
||||
8 printf("main\n");
|
||||
9 }
|
||||
% clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=trace-pc-guard
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out; wc -c *.sancov
|
||||
main
|
||||
SanitizerCoverage: ./a.out.7312.sancov 2 PCs written
|
||||
24 a.out.7312.sancov
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out foo ; wc -c *.sancov
|
||||
foo
|
||||
main
|
||||
SanitizerCoverage: ./a.out.7316.sancov 3 PCs written
|
||||
24 a.out.7312.sancov
|
||||
32 a.out.7316.sancov
|
||||
|
||||
Every time you run an executable instrumented with SanitizerCoverage
|
||||
one ``*.sancov`` file is created during the process shutdown.
|
||||
If the executable is dynamically linked against instrumented DSOs,
|
||||
one ``*.sancov`` file will be also created for every DSO.
|
||||
|
||||
Sancov data format
|
||||
------------------
|
||||
|
||||
The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic,
|
||||
one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the
|
||||
magic defines the size of the following offsets. The rest of the data is the
|
||||
offsets in the corresponding binary/DSO that were executed during the run.
|
||||
|
||||
Sancov Tool
|
||||
-----------
|
||||
|
||||
An simple ``sancov`` tool is provided to process coverage files.
|
||||
The tool is part of LLVM project and is currently supported only on Linux.
|
||||
It can handle symbolization tasks autonomously without any extra support
|
||||
from the environment. You need to pass .sancov files (named
|
||||
``<module_name>.<pid>.sancov`` and paths to all corresponding binary elf files.
|
||||
Sancov matches these files using module names and binaries file names.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
USAGE: sancov [options] <action> (<binary file>|<.sancov file>)...
|
||||
|
||||
Action (required)
|
||||
-print - Print coverage addresses
|
||||
-covered-functions - Print all covered functions.
|
||||
-not-covered-functions - Print all not covered functions.
|
||||
-symbolize - Symbolizes the report.
|
||||
|
||||
Options
|
||||
-blacklist=<string> - Blacklist file (sanitizer blacklist format).
|
||||
-demangle - Print demangled function name.
|
||||
-strip_path_prefix=<string> - Strip this prefix from file paths in reports
|
||||
|
||||
|
||||
Coverage Reports
|
||||
----------------
|
||||
|
||||
**Experimental**
|
||||
|
||||
``.sancov`` files do not contain enough information to generate a source-level
|
||||
coverage report. The missing information is contained
|
||||
in debug info of the binary. Thus the ``.sancov`` has to be symbolized
|
||||
to produce a ``.symcov`` file first:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sancov -symbolize my_program.123.sancov my_program > my_program.123.symcov
|
||||
|
||||
The ``.symcov`` file can be browsed overlayed over the source code by
|
||||
running ``tools/sancov/coverage-report-server.py`` script that will start
|
||||
an HTTP server.
|
||||
|
||||
Output directory
|
||||
================
|
||||
----------------
|
||||
|
||||
By default, .sancov files are created in the current working directory.
|
||||
This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``:
|
||||
|
@ -489,95 +333,3 @@ This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``:
|
|||
% ls -l /tmp/cov/*sancov
|
||||
-rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
|
||||
-rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
|
||||
|
||||
Sudden death
|
||||
============
|
||||
|
||||
Normally, coverage data is collected in memory and saved to disk when the
|
||||
program exits (with an ``atexit()`` handler), when a SIGSEGV is caught, or when
|
||||
``__sanitizer_cov_dump()`` is called.
|
||||
|
||||
If the program ends with a signal that ASan does not handle (or can not handle
|
||||
at all, like SIGKILL), coverage data will be lost. This is a big problem on
|
||||
Android, where SIGKILL is a normal way of evicting applications from memory.
|
||||
|
||||
With ``ASAN_OPTIONS=coverage=1:coverage_direct=1`` coverage data is written to a
|
||||
memory-mapped file as soon as it collected.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% ASAN_OPTIONS="coverage=1:coverage_direct=1" ./a.out
|
||||
main
|
||||
% ls
|
||||
7036.sancov.map 7036.sancov.raw a.out
|
||||
% sancov.py rawunpack 7036.sancov.raw
|
||||
sancov.py: reading map 7036.sancov.map
|
||||
sancov.py: unpacking 7036.sancov.raw
|
||||
writing 1 PCs to a.out.7036.sancov
|
||||
% sancov.py print a.out.7036.sancov
|
||||
sancov.py: read 1 PCs from a.out.7036.sancov
|
||||
sancov.py: 1 files merged; 1 PCs total
|
||||
0x4b2bae
|
||||
|
||||
Note that on 64-bit platforms, this method writes 2x more data than the default,
|
||||
because it stores full PC values instead of 32-bit offsets.
|
||||
|
||||
In-process fuzzing
|
||||
==================
|
||||
|
||||
Coverage data could be useful for fuzzers and sometimes it is preferable to run
|
||||
a fuzzer in the same process as the code being fuzzed (in-process fuzzer).
|
||||
|
||||
You can use ``__sanitizer_get_total_unique_coverage()`` from
|
||||
``<sanitizer/coverage_interface.h>`` which returns the number of currently
|
||||
covered entities in the program. This will tell the fuzzer if the coverage has
|
||||
increased after testing every new input.
|
||||
|
||||
If a fuzzer finds a bug in the ASan run, you will need to save the reproducer
|
||||
before exiting the process. Use ``__asan_set_death_callback`` from
|
||||
``<sanitizer/asan_interface.h>`` to do that.
|
||||
|
||||
An example of such fuzzer can be found in `the LLVM tree
|
||||
<http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/README.txt?view=markup>`_.
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
This coverage implementation is **fast**. With function-level coverage
|
||||
(``-fsanitize-coverage=func``) the overhead is not measurable. With
|
||||
basic-block-level coverage (``-fsanitize-coverage=bb``) the overhead varies
|
||||
between 0 and 25%.
|
||||
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
benchmark cov0 cov1 diff 0-1 cov2 diff 0-2 diff 1-2
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
400.perlbench 1296.00 1307.00 1.01 1465.00 1.13 1.12
|
||||
401.bzip2 858.00 854.00 1.00 1010.00 1.18 1.18
|
||||
403.gcc 613.00 617.00 1.01 683.00 1.11 1.11
|
||||
429.mcf 605.00 582.00 0.96 610.00 1.01 1.05
|
||||
445.gobmk 896.00 880.00 0.98 1050.00 1.17 1.19
|
||||
456.hmmer 892.00 892.00 1.00 918.00 1.03 1.03
|
||||
458.sjeng 995.00 1009.00 1.01 1217.00 1.22 1.21
|
||||
462.libquantum 497.00 492.00 0.99 534.00 1.07 1.09
|
||||
464.h264ref 1461.00 1467.00 1.00 1543.00 1.06 1.05
|
||||
471.omnetpp 575.00 590.00 1.03 660.00 1.15 1.12
|
||||
473.astar 658.00 652.00 0.99 715.00 1.09 1.10
|
||||
483.xalancbmk 471.00 491.00 1.04 582.00 1.24 1.19
|
||||
433.milc 616.00 627.00 1.02 627.00 1.02 1.00
|
||||
444.namd 602.00 601.00 1.00 654.00 1.09 1.09
|
||||
447.dealII 630.00 634.00 1.01 653.00 1.04 1.03
|
||||
450.soplex 365.00 368.00 1.01 395.00 1.08 1.07
|
||||
453.povray 427.00 434.00 1.02 495.00 1.16 1.14
|
||||
470.lbm 357.00 375.00 1.05 370.00 1.04 0.99
|
||||
482.sphinx3 927.00 928.00 1.00 1000.00 1.08 1.08
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
|
||||
Why another coverage?
|
||||
=====================
|
||||
|
||||
Why did we implement yet another code coverage?
|
||||
* We needed something that is lightning fast, plays well with
|
||||
AddressSanitizer, and does not significantly increase the binary size.
|
||||
* Traditional coverage implementations based in global counters
|
||||
`suffer from contention on counters
|
||||
<https://groups.google.com/forum/#!topic/llvm-dev/cDqYgnxNEhY>`_.
|
||||
|
|
|
@ -18,6 +18,7 @@ Clang ships two other code coverage implementations:
|
|||
various sanitizers. It can provide up to edge-level coverage.
|
||||
|
||||
* gcov - A GCC-compatible coverage implementation which operates on DebugInfo.
|
||||
This is enabled by ``-ftest-coverage`` or ``--coverage``.
|
||||
|
||||
From this point onwards "code coverage" will refer to the source-based kind.
|
||||
|
||||
|
@ -256,6 +257,8 @@ without using static initializers, do this manually:
|
|||
otherwise. Calling this function multiple times appends profile data to an
|
||||
existing on-disk raw profile.
|
||||
|
||||
In C++ files, declare these as ``extern "C"``.
|
||||
|
||||
Collecting coverage reports for the llvm project
|
||||
================================================
|
||||
|
||||
|
@ -271,6 +274,11 @@ To specify an alternate directory for raw profiles, use
|
|||
Drawbacks and limitations
|
||||
=========================
|
||||
|
||||
* Prior to version 2.26, the GNU binutils BFD linker is not able link programs
|
||||
compiled with ``-fcoverage-mapping`` in its ``--gc-sections`` mode. Possible
|
||||
workarounds include disabling ``--gc-sections``, upgrading to a newer version
|
||||
of BFD, or using the Gold linker.
|
||||
|
||||
* Code coverage does not handle unpredictable changes in control flow or stack
|
||||
unwinding in the presence of exceptions precisely. Consider the following
|
||||
function:
|
||||
|
|
|
@ -123,6 +123,52 @@ which currently must be enabled through a linker option.
|
|||
``-Wl,-plugin-opt,cache-dir=/path/to/cache``
|
||||
- ld64 (support in clang 3.9 and Xcode 8):
|
||||
``-Wl,-cache_path_lto,/path/to/cache``
|
||||
- lld (as of LLVM r296702):
|
||||
``-Wl,--thinlto-cache-dir=/path/to/cache``
|
||||
|
||||
Cache Pruning
|
||||
-------------
|
||||
|
||||
To help keep the size of the cache under control, ThinLTO supports cache
|
||||
pruning. Cache pruning is supported with ld64 and ELF lld, but currently only
|
||||
ELF lld allows you to control the policy with a policy string. The cache
|
||||
policy must be specified with a linker option.
|
||||
|
||||
- ELF lld (as of LLVM r298036):
|
||||
``-Wl,--thinlto-cache-policy,POLICY``
|
||||
|
||||
A policy string is a series of key-value pairs separated by ``:`` characters.
|
||||
Possible key-value pairs are:
|
||||
|
||||
- ``cache_size=X%``: The maximum size for the cache directory is ``X`` percent
|
||||
of the available space on the the disk. Set to 100 to indicate no limit,
|
||||
50 to indicate that the cache size will not be left over half the available
|
||||
disk space. A value over 100 is invalid. A value of 0 disables the percentage
|
||||
size-based pruning. The default is 75%.
|
||||
|
||||
- ``cache_size_bytes=X``, ``cache_size_bytes=Xk``, ``cache_size_bytes=Xm``,
|
||||
``cache_size_bytes=Xg``:
|
||||
Sets the maximum size for the cache directory to ``X`` bytes (or KB, MB,
|
||||
GB respectively). A value over the amount of available space on the disk
|
||||
will be reduced to the amount of available space. A value of 0 disables
|
||||
the byte size-based pruning. The default is no byte size-based pruning.
|
||||
|
||||
Note that ThinLTO will apply both size-based pruning policies simultaneously,
|
||||
and changing one does not affect the other. For example, a policy of
|
||||
``cache_size_bytes=1g`` on its own will cause both the 1GB and default 75%
|
||||
policies to be applied unless the default ``cache_size`` is overridden.
|
||||
|
||||
- ``prune_after=Xs``, ``prune_after=Xm``, ``prune_after=Xh``: Sets the
|
||||
expiration time for cache files to ``X`` seconds (or minutes, hours
|
||||
respectively). When a file hasn't been accessed for ``prune_after`` seconds,
|
||||
it is removed from the cache. A value of 0 disables the expiration-based
|
||||
pruning. The default is 1 week.
|
||||
|
||||
- ``prune_interval=Xs``, ``prune_interval=Xm``, ``prune_interval=Xh``:
|
||||
Sets the pruning interval to ``X`` seconds (or minutes, hours
|
||||
respectively). This is intended to be used to avoid scanning the directory
|
||||
too often. It does not impact the decision of which files to prune. A
|
||||
value of 0 forces the scan to occur. The default is every 20 minutes.
|
||||
|
||||
Clang Bootstrap
|
||||
---------------
|
||||
|
|
|
@ -764,8 +764,6 @@ implementation.
|
|||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
|
||||
#define CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
|
@ -886,11 +884,11 @@ implementation.
|
|||
|
||||
// Deprecated.
|
||||
#define PT_GUARDED_VAR \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded)
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var)
|
||||
|
||||
// Deprecated.
|
||||
#define GUARDED_VAR \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(guarded)
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(guarded_var)
|
||||
|
||||
// Replaced by REQUIRES
|
||||
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||
|
|
|
@ -50,9 +50,9 @@ instead of ``clang++`` if you're compiling/linking C code.
|
|||
You can enable only a subset of :ref:`checks <ubsan-checks>` offered by UBSan,
|
||||
and define the desired behavior for each kind of check:
|
||||
|
||||
* print a verbose error report and continue execution (default);
|
||||
* print a verbose error report and exit the program;
|
||||
* execute a trap instruction (doesn't require UBSan run-time support).
|
||||
* ``-fsanitize=...``: print a verbose error report and continue execution (default);
|
||||
* ``-fno-sanitize-recover=...``: print a verbose error report and exit the program;
|
||||
* ``-fsanitize-trap=...``: execute a trap instruction (doesn't require UBSan run-time support).
|
||||
|
||||
For example if you compile/link your program as:
|
||||
|
||||
|
@ -92,6 +92,12 @@ Available checks are:
|
|||
parameter which is declared to never be null.
|
||||
- ``-fsanitize=null``: Use of a null pointer or creation of a null
|
||||
reference.
|
||||
- ``-fsanitize=nullability-arg``: Passing null as a function parameter
|
||||
which is annotated with ``_Nonnull``.
|
||||
- ``-fsanitize=nullability-assign``: Assigning null to an lvalue which
|
||||
is annotated with ``_Nonnull``.
|
||||
- ``-fsanitize=nullability-return``: Returning null from a function with
|
||||
a return type annotated with ``_Nonnull``.
|
||||
- ``-fsanitize=object-size``: An attempt to potentially use bytes which
|
||||
the optimizer can determine are not part of the object being accessed.
|
||||
This will also detect some types of undefined behavior that may not
|
||||
|
@ -100,6 +106,8 @@ Available checks are:
|
|||
invalid pointers. These checks are made in terms of
|
||||
``__builtin_object_size``, and consequently may be able to detect more
|
||||
problems at higher optimization levels.
|
||||
- ``-fsanitize=pointer-overflow``: Performing pointer arithmetic which
|
||||
overflows.
|
||||
- ``-fsanitize=return``: In C++, reaching the end of a
|
||||
value-returning function without returning a value.
|
||||
- ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
|
||||
|
@ -117,7 +125,9 @@ Available checks are:
|
|||
- ``-fsanitize=unreachable``: If control flow reaches
|
||||
``__builtin_unreachable``.
|
||||
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer
|
||||
overflows.
|
||||
overflows. Note that unlike signed integer overflow, unsigned integer
|
||||
is not undefined behavior. However, while it has well-defined semantics,
|
||||
it is often unintentional, so UBSan offers to catch it.
|
||||
- ``-fsanitize=vla-bound``: A variable-length array whose bound
|
||||
does not evaluate to a positive value.
|
||||
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that
|
||||
|
@ -128,11 +138,21 @@ Available checks are:
|
|||
|
||||
You can also use the following check groups:
|
||||
- ``-fsanitize=undefined``: All of the checks listed above other than
|
||||
``unsigned-integer-overflow``.
|
||||
``unsigned-integer-overflow`` and the ``nullability-*`` checks.
|
||||
- ``-fsanitize=undefined-trap``: Deprecated alias of
|
||||
``-fsanitize=undefined``.
|
||||
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
|
||||
behavior (e.g. unsigned integer overflow).
|
||||
- ``-fsanitize=nullability``: Enables ``nullability-arg``,
|
||||
``nullability-assign``, and ``nullability-return``. While violating
|
||||
nullability does not have undefined behavior, it is often unintentional,
|
||||
so UBSan offers to catch it.
|
||||
|
||||
Volatile
|
||||
--------
|
||||
|
||||
The ``null``, ``alignment``, ``object-size``, and ``vptr`` checks do not apply
|
||||
to pointers to types with the ``volatile`` qualifier.
|
||||
|
||||
Stack traces and report symbolization
|
||||
=====================================
|
||||
|
|
|
@ -322,18 +322,40 @@ output format of the diagnostics that it generates.
|
|||
by category, so it should be a high level category. We want dozens
|
||||
of these, not hundreds or thousands of them.
|
||||
|
||||
.. _opt_fsave-optimization-record:
|
||||
|
||||
**-fsave-optimization-record**
|
||||
Write optimization remarks to a YAML file.
|
||||
|
||||
This option, which defaults to off, controls whether Clang writes
|
||||
optimization reports to a YAML file. By recording diagnostics in a file,
|
||||
using a structured YAML format, users can parse or sort the remarks in a
|
||||
convenient way.
|
||||
|
||||
.. _opt_foptimization-record-file:
|
||||
|
||||
**-foptimization-record-file**
|
||||
Control the file to which optimization reports are written.
|
||||
|
||||
When optimization reports are being output (see
|
||||
:ref:`-fsave-optimization-record <opt_fsave-optimization-record>`), this
|
||||
option controls the file to which those reports are written.
|
||||
|
||||
If this option is not used, optimization records are output to a file named
|
||||
after the primary file being compiled. If that's "foo.c", for example,
|
||||
optimization records are output to "foo.opt.yaml".
|
||||
|
||||
.. _opt_fdiagnostics-show-hotness:
|
||||
|
||||
**-f[no-]diagnostics-show-hotness**
|
||||
Enable profile hotness information in diagnostic line.
|
||||
|
||||
This option, which defaults to off, controls whether Clang prints the
|
||||
profile hotness associated with a diagnostics in the presence of
|
||||
profile-guided optimization information. This is currently supported with
|
||||
optimization remarks (see :ref:`Options to Emit Optimization Reports
|
||||
<rpass>`). The hotness information allows users to focus on the hot
|
||||
optimization remarks that are likely to be more relevant for run-time
|
||||
performance.
|
||||
This option controls whether Clang prints the profile hotness associated
|
||||
with diagnostics in the presence of profile-guided optimization information.
|
||||
This is currently supported with optimization remarks (see
|
||||
:ref:`Options to Emit Optimization Reports <rpass>`). The hotness information
|
||||
allows users to focus on the hot optimization remarks that are likely to be
|
||||
more relevant for run-time performance.
|
||||
|
||||
For example, in this output, the block containing the callsite of `foo` was
|
||||
executed 3000 times according to the profile data:
|
||||
|
@ -344,6 +366,23 @@ output format of the diagnostics that it generates.
|
|||
sum += foo(x, x - 2);
|
||||
^
|
||||
|
||||
This option is implied when
|
||||
:ref:`-fsave-optimization-record <opt_fsave-optimization-record>` is used.
|
||||
Otherwise, it defaults to off.
|
||||
|
||||
.. _opt_fdiagnostics-hotness-threshold:
|
||||
|
||||
**-fdiagnostics-hotness-threshold**
|
||||
Prevent optimization remarks from being output if they do not have at least
|
||||
this hotness value.
|
||||
|
||||
This option, which defaults to zero, controls the minimum hotness an
|
||||
optimization remark would need in order to be output by Clang. This is
|
||||
currently supported with optimization remarks (see :ref:`Options to Emit
|
||||
Optimization Reports <rpass>`) when profile hotness information in
|
||||
diagnostics is enabled (see
|
||||
:ref:`-fdiagnostics-show-hotness <opt_fdiagnostics-show-hotness>`).
|
||||
|
||||
.. _opt_fdiagnostics-fixit-info:
|
||||
|
||||
**-f[no-]diagnostics-fixit-info**
|
||||
|
@ -562,6 +601,16 @@ control the crash diagnostics.
|
|||
The -fno-crash-diagnostics flag can be helpful for speeding the process
|
||||
of generating a delta reduced test case.
|
||||
|
||||
Clang is also capable of generating preprocessed source file(s) and associated
|
||||
run script(s) even without a crash. This is specially useful when trying to
|
||||
generate a reproducer for warnings or errors while using modules.
|
||||
|
||||
.. option:: -gen-reproducer
|
||||
|
||||
Generates preprocessed source files, a reproducer script and if relevant, a
|
||||
cache containing: built module pcm's and all headers needed to rebuilt the
|
||||
same modules.
|
||||
|
||||
.. _rpass:
|
||||
|
||||
Options to Emit Optimization Reports
|
||||
|
@ -757,6 +806,7 @@ existed.
|
|||
#if foo
|
||||
#endif foo // warning: extra tokens at end of #endif directive
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wextra-tokens"
|
||||
|
||||
#if foo
|
||||
|
@ -1695,6 +1745,22 @@ below. If multiple flags are present, the last one is used.
|
|||
|
||||
Generate complete debug info.
|
||||
|
||||
Controlling Macro Debug Info Generation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Debug info for C preprocessor macros increases the size of debug information in
|
||||
the binary. Macro debug info generated by Clang can be controlled by the flags
|
||||
listed below.
|
||||
|
||||
.. option:: -fdebug-macro
|
||||
|
||||
Generate debug info for preprocessor macros. This flag is discarded when
|
||||
**-g0** is enabled.
|
||||
|
||||
.. option:: -fno-debug-macro
|
||||
|
||||
Do not generate debug info for preprocessor macros (default).
|
||||
|
||||
Controlling Debugger "Tuning"
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -1862,7 +1928,7 @@ missing from this list, please send an e-mail to cfe-dev. This list
|
|||
currently excludes C++; see :ref:`C++ Language Features <cxx>`. Also, this
|
||||
list does not include bugs in mostly-implemented features; please see
|
||||
the `bug
|
||||
tracker <http://llvm.org/bugs/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer>`_
|
||||
tracker <https://bugs.llvm.org/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer>`_
|
||||
for known existing bugs (FIXME: Is there a section for bug-reporting
|
||||
guidelines somewhere?).
|
||||
|
||||
|
@ -2056,6 +2122,8 @@ can be given manually.
|
|||
In this case the kernel code should contain ``#include <opencl-c.h>`` just as a
|
||||
regular C include.
|
||||
|
||||
.. _opencl_cl_ext:
|
||||
|
||||
.. option:: -cl-ext
|
||||
|
||||
Disables support of OpenCL extensions. All OpenCL targets provide a list
|
||||
|
@ -2177,6 +2245,41 @@ To enable modules for OpenCL:
|
|||
|
||||
$ clang -target spir-unknown-unknown -c -emit-llvm -Xclang -finclude-default-header -fmodules -fimplicit-module-maps -fmodules-cache-path=<path to the generated module> test.cl
|
||||
|
||||
OpenCL Extensions
|
||||
-----------------
|
||||
|
||||
All of the ``cl_khr_*`` extensions from `the official OpenCL specification
|
||||
<https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/EXTENSION.html>`_
|
||||
up to and including version 2.0 are available and set per target depending on the
|
||||
support available in the specific architecture.
|
||||
|
||||
It is possible to alter the default extensions setting per target using
|
||||
``-cl-ext`` flag. (See :ref:`flags description <opencl_cl_ext>` for more details).
|
||||
|
||||
Vendor extensions can be added flexibly by declaring the list of types and
|
||||
functions associated with each extensions enclosed within the following
|
||||
compiler pragma directives:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#pragma OPENCL EXTENSION the_new_extension_name : begin
|
||||
// declare types and functions associated with the extension here
|
||||
#pragma OPENCL EXTENSION the_new_extension_name : end
|
||||
|
||||
For example, parsing the following code adds ``my_t`` type and ``my_func``
|
||||
function to the custom ``my_ext`` extension.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#pragma OPENCL EXTENSION my_ext : begin
|
||||
typedef struct{
|
||||
int a;
|
||||
}my_t;
|
||||
void my_func(my_t);
|
||||
#pragma OPENCL EXTENSION my_ext : end
|
||||
|
||||
Declaring the same types in different vendor extensions is disallowed.
|
||||
|
||||
OpenCL Metadata
|
||||
---------------
|
||||
|
||||
|
@ -2215,7 +2318,7 @@ does not have any effect on the IR. For more details reffer to the specification
|
|||
<https://www.khronos.org/registry/cl/specs/opencl-2.0-openclc.pdf#49>`_
|
||||
|
||||
|
||||
opencl_hint_unroll
|
||||
opencl_unroll_hint
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The implementation of this feature mirrors the unroll hint for C.
|
||||
|
@ -2236,7 +2339,7 @@ An example is the subgroup operations such as `intel_sub_group_shuffle
|
|||
|
||||
// Define custom my_sub_group_shuffle(data, c)
|
||||
// that makes use of intel_sub_group_shuffle
|
||||
r1 = …
|
||||
r1 = ...
|
||||
if (r0) r1 = computeA();
|
||||
// Shuffle data from r1 into r3
|
||||
// of threads id r2.
|
||||
|
@ -2247,7 +2350,7 @@ with non-SPMD semantics this is optimized to the following equivalent code:
|
|||
|
||||
.. code-block:: c
|
||||
|
||||
r1 = …
|
||||
r1 = ...
|
||||
if (!r0)
|
||||
// Incorrect functionality! The data in r1
|
||||
// have not been computed by all threads yet.
|
||||
|
@ -2462,7 +2565,7 @@ official `MinGW-w64 website <http://mingw-w64.sourceforge.net>`_.
|
|||
Clang expects the GCC executable "gcc.exe" compiled for
|
||||
``i686-w64-mingw32`` (or ``x86_64-w64-mingw32``) to be present on PATH.
|
||||
|
||||
`Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on
|
||||
`Some tests might fail <https://bugs.llvm.org/show_bug.cgi?id=9072>`_ on
|
||||
``x86_64-w64-mingw32``.
|
||||
|
||||
.. _clang-cl:
|
||||
|
@ -2505,7 +2608,7 @@ options 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>`_
|
||||
Please `file a bug <https://bugs.llvm.org/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:
|
||||
|
@ -2519,6 +2622,10 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
|||
/Brepro Emit an object file which can be reproduced over time
|
||||
/C Don't discard comments when preprocessing
|
||||
/c Compile only
|
||||
/d1reportAllClassLayout Dump record layout information
|
||||
/diagnostics:caret Enable caret and column diagnostics (on by default)
|
||||
/diagnostics:classic Disable column and caret diagnostics
|
||||
/diagnostics:column Disable caret diagnostics but keep column info
|
||||
/D <macro[=value]> Define macro
|
||||
/EH<value> Exception handling model
|
||||
/EP Disable linemarker output and preprocess to stdout
|
||||
|
@ -2613,6 +2720,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
|||
/Zc:threadSafeInit Enable thread-safe initialization of static variables
|
||||
/Zc:trigraphs- Disable trigraphs (default)
|
||||
/Zc:trigraphs Enable trigraphs
|
||||
/Zc:twoPhase- Disable two-phase name lookup in templates
|
||||
/Zc:twoPhase Enable two-phase name lookup in templates
|
||||
/Zd Emit debug line number tables only
|
||||
/Zi Alias for /Z7. Does not produce PDBs.
|
||||
/Zl Don't mention any default libraries in the object file
|
||||
|
@ -2625,12 +2734,14 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
|||
--analyze Run the static analyzer
|
||||
-fansi-escape-codes Use ANSI escape codes for diagnostics
|
||||
-fcolor-diagnostics Use colors in diagnostics
|
||||
-fdebug-macro Emit macro debug information
|
||||
-fdelayed-template-parsing
|
||||
Parse templated function definitions at the end of the translation unit
|
||||
-fdiagnostics-absolute-paths
|
||||
Print absolute paths in diagnostics
|
||||
-fdiagnostics-parseable-fixits
|
||||
Print fix-its in machine parseable form
|
||||
-flto=<value> Set LTO mode to either 'full' or 'thin'
|
||||
-flto Enable LTO in 'full' mode
|
||||
-fms-compatibility-version=<value>
|
||||
Dot-separated value representing the Microsoft compiler version
|
||||
|
@ -2639,12 +2750,27 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
|||
-fms-extensions Accept some non-standard constructs supported by the Microsoft compiler
|
||||
-fmsc-version=<value> Microsoft compiler version number to report in _MSC_VER
|
||||
(0 = don't define it (default))
|
||||
-fno-debug-macro Do not emit macro debug information
|
||||
-fno-delayed-template-parsing
|
||||
Disable delayed template parsing
|
||||
-fno-sanitize-address-use-after-scope
|
||||
Disable use-after-scope detection in AddressSanitizer
|
||||
-fno-sanitize-blacklist Don't use blacklist file for sanitizers
|
||||
-fno-sanitize-cfi-cross-dso
|
||||
Disable control flow integrity (CFI) checks for cross-DSO calls.
|
||||
-fno-sanitize-coverage=<value>
|
||||
Disable specified features of coverage instrumentation for Sanitizers
|
||||
-fno-sanitize-memory-track-origins
|
||||
Disable origins tracking in MemorySanitizer
|
||||
-fno-sanitize-recover=<value>
|
||||
Disable recovery for specified sanitizers
|
||||
-fno-sanitize-stats Disable sanitizer statistics gathering.
|
||||
-fno-sanitize-thread-atomics
|
||||
Disable atomic operations instrumentation in ThreadSanitizer
|
||||
-fno-sanitize-thread-func-entry-exit
|
||||
Disable function entry/exit instrumentation in ThreadSanitizer
|
||||
-fno-sanitize-thread-memory-access
|
||||
Disable memory access instrumentation in ThreadSanitizer
|
||||
-fno-sanitize-trap=<value>
|
||||
Disable trapping for specified sanitizers
|
||||
-fno-standalone-debug Limit debug information produced to reduce size of debug binary
|
||||
|
@ -2656,13 +2782,36 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
|||
(overridden by '=' form of option or LLVM_PROFILE_FILE env var)
|
||||
-fprofile-instr-use=<value>
|
||||
Use instrumentation data for profile-guided optimization
|
||||
-fsanitize-address-field-padding=<value>
|
||||
Level of field padding for AddressSanitizer
|
||||
-fsanitize-address-globals-dead-stripping
|
||||
Enable linker dead stripping of globals in AddressSanitizer
|
||||
-fsanitize-address-use-after-scope
|
||||
Enable use-after-scope detection in AddressSanitizer
|
||||
-fsanitize-blacklist=<value>
|
||||
Path to blacklist file for sanitizers
|
||||
-fsanitize-cfi-cross-dso
|
||||
Enable control flow integrity (CFI) checks for cross-DSO calls.
|
||||
-fsanitize-coverage=<value>
|
||||
Specify the type of coverage instrumentation for Sanitizers
|
||||
-fsanitize-memory-track-origins=<value>
|
||||
Enable origins tracking in MemorySanitizer
|
||||
-fsanitize-memory-track-origins
|
||||
Enable origins tracking in MemorySanitizer
|
||||
-fsanitize-memory-use-after-dtor
|
||||
Enable use-after-destroy detection in MemorySanitizer
|
||||
-fsanitize-recover=<value>
|
||||
Enable recovery for specified sanitizers
|
||||
-fsanitize-stats Enable sanitizer statistics gathering.
|
||||
-fsanitize-thread-atomics
|
||||
Enable atomic operations instrumentation in ThreadSanitizer (default)
|
||||
-fsanitize-thread-func-entry-exit
|
||||
Enable function entry/exit instrumentation in ThreadSanitizer (default)
|
||||
-fsanitize-thread-memory-access
|
||||
Enable memory access instrumentation in ThreadSanitizer (default)
|
||||
-fsanitize-trap=<value> Enable trapping for specified sanitizers
|
||||
-fsanitize-undefined-strip-path-components=<number>
|
||||
Strip (or keep only, if negative) a given number of path components when emitting check metadata.
|
||||
-fsanitize=<check> Turn on runtime checks for various forms of undefined or suspicious
|
||||
behavior. See user manual for available checks
|
||||
-fstandalone-debug Emit full debug info for all types used by the program
|
||||
|
@ -2670,6 +2819,7 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
|||
-gline-tables-only Emit debug line number tables only
|
||||
-miamcu Use Intel MCU ABI
|
||||
-mllvm <value> Additional arguments to forward to LLVM's option processing
|
||||
-nobuiltininc Disable builtin #include directories
|
||||
-Qunused-arguments Don't emit warning for unused driver arguments
|
||||
-R<remark> Enable the specified remark
|
||||
--target=<value> Generate code for the given target
|
||||
|
|
|
@ -178,15 +178,21 @@ ExprInspection checks
|
|||
This function explains the value of its argument in a human-readable manner
|
||||
in the warning message. You can make as many overrides of its prototype
|
||||
in the test code as necessary to explain various integral, pointer,
|
||||
or even record-type values.
|
||||
or even record-type values. To simplify usage in C code (where overloading
|
||||
the function declaration is not allowed), you may append an arbitrary suffix
|
||||
to the function name, without affecting functionality.
|
||||
|
||||
Example usage::
|
||||
|
||||
void clang_analyzer_explain(int);
|
||||
void clang_analyzer_explain(void *);
|
||||
|
||||
// Useful in C code
|
||||
void clang_analyzer_explain_int(int);
|
||||
|
||||
void foo(int param, void *ptr) {
|
||||
clang_analyzer_explain(param); // expected-warning{{argument 'param'}}
|
||||
clang_analyzer_explain_int(param); // expected-warning{{argument 'param'}}
|
||||
if (!ptr)
|
||||
clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
|
||||
}
|
||||
|
|
|
@ -48,10 +48,10 @@ copyright = u'2013-%d, Analyzer Team' % date.today().year
|
|||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '4.0'
|
||||
# The short version.
|
||||
version = '5'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '4.0'
|
||||
release = '5'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
@ -48,10 +48,10 @@ copyright = u'2007-%d, The Clang Team' % date.today().year
|
|||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '4.0'
|
||||
# The short version.
|
||||
version = '5'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '4.0'
|
||||
release = '5'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
@ -132,7 +132,7 @@ INLINE_INHERITED_MEMB = NO
|
|||
# shortest path that makes the file name unique will be used
|
||||
# The default value is: YES.
|
||||
|
||||
FULL_PATH_NAMES = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
|
||||
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
|
||||
# Stripping is only done if one of the specified strings matches the left-hand
|
||||
|
@ -144,7 +144,7 @@ FULL_PATH_NAMES = NO
|
|||
# will be relative from the directory where doxygen is started.
|
||||
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
|
||||
|
||||
STRIP_FROM_PATH = ../..
|
||||
STRIP_FROM_PATH = @abs_srcdir@/..
|
||||
|
||||
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
|
||||
# path mentioned in the documentation of a class, which tells the reader which
|
||||
|
@ -153,7 +153,7 @@ STRIP_FROM_PATH = ../..
|
|||
# specify the list of include paths that are normally passed to the compiler
|
||||
# using the -I flag.
|
||||
|
||||
STRIP_FROM_INC_PATH =
|
||||
STRIP_FROM_INC_PATH = @abs_srcdir@/../include
|
||||
|
||||
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
|
||||
# less readable) file names. This can be useful is your file systems doesn't
|
||||
|
@ -513,7 +513,7 @@ SHOW_GROUPED_MEMB_INC = NO
|
|||
# files with double quotes in the documentation rather than with sharp brackets.
|
||||
# The default value is: NO.
|
||||
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
FORCE_LOCAL_INCLUDES = YES
|
||||
|
||||
# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
|
||||
# documentation for inline members.
|
||||
|
@ -1885,7 +1885,7 @@ ENABLE_PREPROCESSING = YES
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
MACRO_EXPANSION = YES
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
|
||||
# the macro expansion is limited to the macros specified with the PREDEFINED and
|
||||
|
@ -1893,7 +1893,7 @@ MACRO_EXPANSION = NO
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
|
||||
# If the SEARCH_INCLUDES tag is set to YES the includes files in the
|
||||
# INCLUDE_PATH will be searched if a #include is found.
|
||||
|
@ -1925,7 +1925,7 @@ INCLUDE_FILE_PATTERNS =
|
|||
# recursively expanded use the := operator instead of the = operator.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
PREDEFINED =
|
||||
PREDEFINED = LLVM_ALIGNAS(x)=
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
|
|
|
@ -19,6 +19,7 @@ Using Clang as a Compiler
|
|||
UsersManual
|
||||
Toolchain
|
||||
LanguageExtensions
|
||||
ClangCommandLineReference
|
||||
AttributeReference
|
||||
DiagnosticsReference
|
||||
CrossCompilation
|
||||
|
|
|
@ -19,16 +19,15 @@ def substitute(text, tag, contents):
|
|||
return re.sub(pattern, '%s', text, flags=re.S) % replacement
|
||||
|
||||
def doxygen2rst(text):
|
||||
text = re.sub(r'([^/\*])\*', r'\1\\*', 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):
|
||||
def indent(text, columns, indent_first_line=True):
|
||||
indent = ' ' * columns
|
||||
s = re.sub(r'\n([^\n])', '\n' + indent + '\\1', text, flags=re.S)
|
||||
if s.startswith('\n'):
|
||||
if not indent_first_line or s.startswith('\n'):
|
||||
return s
|
||||
return indent + s
|
||||
|
||||
|
@ -65,7 +64,9 @@ class NestedField:
|
|||
self.comment = comment.strip()
|
||||
|
||||
def __str__(self):
|
||||
return '* ``%s`` %s' % (self.name, doxygen2rst(self.comment))
|
||||
return '\n* ``%s`` %s' % (
|
||||
self.name,
|
||||
doxygen2rst(indent(self.comment, 2, indent_first_line=False)))
|
||||
|
||||
class Enum:
|
||||
def __init__(self, name, comment):
|
||||
|
@ -180,7 +181,7 @@ def read_options(header):
|
|||
if enums.has_key(option.type):
|
||||
option.enum = enums[option.type]
|
||||
elif nested_structs.has_key(option.type):
|
||||
option.nested_struct = nested_structs[option.type];
|
||||
option.nested_struct = nested_structs[option.type]
|
||||
else:
|
||||
raise Exception('Unknown type: %s' % option.type)
|
||||
return options
|
||||
|
@ -196,4 +197,3 @@ contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text)
|
|||
|
||||
with open(DOC_FILE, 'wb') as output:
|
||||
output.write(contents)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
ExecutionEngine
|
||||
MC
|
||||
MCJIT
|
||||
Option
|
||||
Support
|
||||
native
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public inferface to use CompilationDatabase without *|
|
||||
|* This header provides a public interface to use CompilationDatabase without *|
|
||||
|* the full Clang C++ API. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public inferface to a Clang library for extracting *|
|
||||
|* This header provides a public interface to a Clang library for extracting *|
|
||||
|* high-level symbol information from source files without exposing the full *|
|
||||
|* Clang C++ API. *|
|
||||
|* *|
|
||||
|
@ -32,7 +32,7 @@
|
|||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||
*/
|
||||
#define CINDEX_VERSION_MAJOR 0
|
||||
#define CINDEX_VERSION_MINOR 37
|
||||
#define CINDEX_VERSION_MINOR 43
|
||||
|
||||
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
||||
((major) * 10000) \
|
||||
|
@ -80,6 +80,12 @@ extern "C" {
|
|||
*/
|
||||
typedef void *CXIndex;
|
||||
|
||||
/**
|
||||
* \brief An opaque type representing target information for a given translation
|
||||
* unit.
|
||||
*/
|
||||
typedef struct CXTargetInfoImpl *CXTargetInfo;
|
||||
|
||||
/**
|
||||
* \brief A single translation unit, which resides in an index.
|
||||
*/
|
||||
|
@ -165,7 +171,60 @@ typedef struct CXVersion {
|
|||
*/
|
||||
int Subminor;
|
||||
} CXVersion;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Describes the exception specification of a cursor.
|
||||
*
|
||||
* A negative value indicates that the cursor is not a function declaration.
|
||||
*/
|
||||
enum CXCursor_ExceptionSpecificationKind {
|
||||
|
||||
/**
|
||||
* \brief The cursor has no exception specification.
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_None,
|
||||
|
||||
/**
|
||||
* \brief The cursor has exception specification throw()
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_DynamicNone,
|
||||
|
||||
/**
|
||||
* \brief The cursor has exception specification throw(T1, T2)
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_Dynamic,
|
||||
|
||||
/**
|
||||
* \brief The cursor has exception specification throw(...).
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_MSAny,
|
||||
|
||||
/**
|
||||
* \brief The cursor has exception specification basic noexcept.
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_BasicNoexcept,
|
||||
|
||||
/**
|
||||
* \brief The cursor has exception specification computed noexcept.
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_ComputedNoexcept,
|
||||
|
||||
/**
|
||||
* \brief The exception specification has not yet been evaluated.
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_Unevaluated,
|
||||
|
||||
/**
|
||||
* \brief The exception specification has not yet been instantiated.
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_Uninstantiated,
|
||||
|
||||
/**
|
||||
* \brief The exception specification has not been parsed yet.
|
||||
*/
|
||||
CXCursor_ExceptionSpecificationKind_Unparsed
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Provides a shared context for creating translation units.
|
||||
*
|
||||
|
@ -478,8 +537,8 @@ CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location,
|
|||
unsigned *offset);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the file, line, column, and offset represented by
|
||||
* the given source location, as specified in a # line directive.
|
||||
* \brief Retrieve the file, line and column represented by the given source
|
||||
* location, as specified in a # line directive.
|
||||
*
|
||||
* Example: given the following source code in a file somefile.c
|
||||
*
|
||||
|
@ -1228,7 +1287,12 @@ enum CXTranslationUnit_Flags {
|
|||
* purposes of an IDE, this is undesirable behavior and as much information
|
||||
* as possible should be reported. Use this flag to enable this behavior.
|
||||
*/
|
||||
CXTranslationUnit_KeepGoing = 0x200
|
||||
CXTranslationUnit_KeepGoing = 0x200,
|
||||
|
||||
/**
|
||||
* \brief Sets the preprocessor in a mode for parsing a single file only.
|
||||
*/
|
||||
CXTranslationUnit_SingleFileParse = 0x400
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1412,6 +1476,15 @@ CINDEX_LINKAGE int clang_saveTranslationUnit(CXTranslationUnit TU,
|
|||
const char *FileName,
|
||||
unsigned options);
|
||||
|
||||
/**
|
||||
* \brief Suspend a translation unit in order to free memory associated with it.
|
||||
*
|
||||
* A suspended translation unit uses significantly less memory but on the other
|
||||
* side does not support any other calls than \c clang_reparseTranslationUnit
|
||||
* to resume it or \c clang_disposeTranslationUnit to dispose it completely.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_suspendTranslationUnit(CXTranslationUnit);
|
||||
|
||||
/**
|
||||
* \brief Destroy the specified CXTranslationUnit object.
|
||||
*/
|
||||
|
@ -1552,6 +1625,36 @@ CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU
|
|||
|
||||
CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage);
|
||||
|
||||
/**
|
||||
* \brief Get target information for this translation unit.
|
||||
*
|
||||
* The CXTargetInfo object cannot outlive the CXTranslationUnit object.
|
||||
*/
|
||||
CINDEX_LINKAGE CXTargetInfo
|
||||
clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit);
|
||||
|
||||
/**
|
||||
* \brief Destroy the CXTargetInfo object.
|
||||
*/
|
||||
CINDEX_LINKAGE void
|
||||
clang_TargetInfo_dispose(CXTargetInfo Info);
|
||||
|
||||
/**
|
||||
* \brief Get the normalized target triple as a string.
|
||||
*
|
||||
* Returns the empty string in case of any error.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_TargetInfo_getTriple(CXTargetInfo Info);
|
||||
|
||||
/**
|
||||
* \brief Get the pointer width of the target in bits.
|
||||
*
|
||||
* Returns -1 in case of error.
|
||||
*/
|
||||
CINDEX_LINKAGE int
|
||||
clang_TargetInfo_getPointerWidth(CXTargetInfo Info);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -3011,8 +3114,9 @@ enum CXTypeKind {
|
|||
CXType_ObjCClass = 28,
|
||||
CXType_ObjCSel = 29,
|
||||
CXType_Float128 = 30,
|
||||
CXType_Half = 31,
|
||||
CXType_FirstBuiltin = CXType_Void,
|
||||
CXType_LastBuiltin = CXType_ObjCSel,
|
||||
CXType_LastBuiltin = CXType_Half,
|
||||
|
||||
CXType_Complex = 100,
|
||||
CXType_Pointer = 101,
|
||||
|
@ -3039,7 +3143,52 @@ enum CXTypeKind {
|
|||
*
|
||||
* E.g., struct S, or via a qualified name, e.g., N::M::type, or both.
|
||||
*/
|
||||
CXType_Elaborated = 119
|
||||
CXType_Elaborated = 119,
|
||||
|
||||
/* OpenCL PipeType. */
|
||||
CXType_Pipe = 120,
|
||||
|
||||
/* OpenCL builtin types. */
|
||||
CXType_OCLImage1dRO = 121,
|
||||
CXType_OCLImage1dArrayRO = 122,
|
||||
CXType_OCLImage1dBufferRO = 123,
|
||||
CXType_OCLImage2dRO = 124,
|
||||
CXType_OCLImage2dArrayRO = 125,
|
||||
CXType_OCLImage2dDepthRO = 126,
|
||||
CXType_OCLImage2dArrayDepthRO = 127,
|
||||
CXType_OCLImage2dMSAARO = 128,
|
||||
CXType_OCLImage2dArrayMSAARO = 129,
|
||||
CXType_OCLImage2dMSAADepthRO = 130,
|
||||
CXType_OCLImage2dArrayMSAADepthRO = 131,
|
||||
CXType_OCLImage3dRO = 132,
|
||||
CXType_OCLImage1dWO = 133,
|
||||
CXType_OCLImage1dArrayWO = 134,
|
||||
CXType_OCLImage1dBufferWO = 135,
|
||||
CXType_OCLImage2dWO = 136,
|
||||
CXType_OCLImage2dArrayWO = 137,
|
||||
CXType_OCLImage2dDepthWO = 138,
|
||||
CXType_OCLImage2dArrayDepthWO = 139,
|
||||
CXType_OCLImage2dMSAAWO = 140,
|
||||
CXType_OCLImage2dArrayMSAAWO = 141,
|
||||
CXType_OCLImage2dMSAADepthWO = 142,
|
||||
CXType_OCLImage2dArrayMSAADepthWO = 143,
|
||||
CXType_OCLImage3dWO = 144,
|
||||
CXType_OCLImage1dRW = 145,
|
||||
CXType_OCLImage1dArrayRW = 146,
|
||||
CXType_OCLImage1dBufferRW = 147,
|
||||
CXType_OCLImage2dRW = 148,
|
||||
CXType_OCLImage2dArrayRW = 149,
|
||||
CXType_OCLImage2dDepthRW = 150,
|
||||
CXType_OCLImage2dArrayDepthRW = 151,
|
||||
CXType_OCLImage2dMSAARW = 152,
|
||||
CXType_OCLImage2dArrayMSAARW = 153,
|
||||
CXType_OCLImage2dMSAADepthRW = 154,
|
||||
CXType_OCLImage2dArrayMSAADepthRW = 155,
|
||||
CXType_OCLImage3dRW = 156,
|
||||
CXType_OCLSampler = 157,
|
||||
CXType_OCLEvent = 158,
|
||||
CXType_OCLQueue = 159,
|
||||
CXType_OCLReserveID = 160
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -3056,7 +3205,7 @@ enum CXCallingConv {
|
|||
CXCallingConv_AAPCS_VFP = 7,
|
||||
CXCallingConv_X86RegCall = 8,
|
||||
CXCallingConv_IntelOclBicc = 9,
|
||||
CXCallingConv_X86_64Win64 = 10,
|
||||
CXCallingConv_Win64 = 10,
|
||||
CXCallingConv_X86_64SysV = 11,
|
||||
CXCallingConv_X86VectorCall = 12,
|
||||
CXCallingConv_Swift = 13,
|
||||
|
@ -3325,6 +3474,16 @@ CINDEX_LINKAGE unsigned clang_isVolatileQualifiedType(CXType T);
|
|||
*/
|
||||
CINDEX_LINKAGE unsigned clang_isRestrictQualifiedType(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Returns the address space of the given type.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_getAddressSpace(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Returns the typedef name of the given type.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_getTypedefName(CXType CT);
|
||||
|
||||
/**
|
||||
* \brief For pointer types, returns the type of the pointee.
|
||||
*/
|
||||
|
@ -3364,6 +3523,13 @@ CINDEX_LINKAGE enum CXCallingConv clang_getFunctionTypeCallingConv(CXType T);
|
|||
*/
|
||||
CINDEX_LINKAGE CXType clang_getResultType(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the exception specification type associated with a function type.
|
||||
*
|
||||
* If a non-function type is passed in, an error code of -1 is returned.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_getExceptionSpecificationType(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the number of non-variadic parameters associated with a
|
||||
* function type.
|
||||
|
@ -3392,6 +3558,13 @@ CINDEX_LINKAGE unsigned clang_isFunctionTypeVariadic(CXType T);
|
|||
*/
|
||||
CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the exception specification type associated with a given cursor.
|
||||
*
|
||||
* This only returns a valid result if the cursor refers to a function or method.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_getCursorExceptionSpecificationType(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Return 1 if the CXType is a POD (plain old data) type, and 0
|
||||
* otherwise.
|
||||
|
@ -3435,6 +3608,16 @@ CINDEX_LINKAGE long long clang_getArraySize(CXType T);
|
|||
*/
|
||||
CINDEX_LINKAGE CXType clang_Type_getNamedType(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Determine if a typedef is 'transparent' tag.
|
||||
*
|
||||
* A typedef is considered 'transparent' if it shares a name and spelling
|
||||
* location with its underlying tag type, as is the case with the NS_ENUM macro.
|
||||
*
|
||||
* \returns non-zero if transparent and zero otherwise.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Type_isTransparentTagTypedef(CXType T);
|
||||
|
||||
/**
|
||||
* \brief List the possible error codes for \c clang_Type_getSizeOf,
|
||||
* \c clang_Type_getAlignOf, \c clang_Type_getOffsetOf and
|
||||
|
@ -3964,8 +4147,8 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
|
|||
CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Given a cursor pointing to an Objective-C message, returns the CXType
|
||||
* of the receiver.
|
||||
* \brief Given a cursor pointing to an Objective-C message or property
|
||||
* reference, or C++ method call, returns the CXType of the receiver.
|
||||
*/
|
||||
CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C);
|
||||
|
||||
|
@ -4023,8 +4206,8 @@ CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
|
|||
|
||||
/**
|
||||
* \brief Given a cursor that represents an Objective-C 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".
|
||||
* 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);
|
||||
|
||||
|
@ -4033,6 +4216,23 @@ CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
|
|||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Returns non-zero if the given cursor points to a symbol marked with
|
||||
* external_source_symbol attribute.
|
||||
*
|
||||
* \param language If non-NULL, and the attribute is present, will be set to
|
||||
* the 'language' string from the attribute.
|
||||
*
|
||||
* \param definedIn If non-NULL, and the attribute is present, will be set to
|
||||
* the 'definedIn' string from the attribute.
|
||||
*
|
||||
* \param isGenerated If non-NULL, and the attribute is present, will be set to
|
||||
* non-zero if the 'generated_declaration' is set in the attribute.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Cursor_isExternalSymbol(CXCursor C,
|
||||
CXString *language, CXString *definedIn,
|
||||
unsigned *isGenerated);
|
||||
|
||||
/**
|
||||
* \brief Given a cursor that represents a declaration, return the associated
|
||||
* comment's source range. The range may include multiple consecutive comments
|
||||
|
@ -4216,6 +4416,11 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
|
|||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Determine if an enum declaration refers to a scoped enum.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Determine if a C++ member function or member function template is
|
||||
* declared 'const'.
|
||||
|
@ -4700,7 +4905,7 @@ enum CXCompletionChunkKind {
|
|||
*/
|
||||
CXCompletionChunk_HorizontalSpace,
|
||||
/**
|
||||
* Vertical space ('\n'), after which it is generally a good idea to
|
||||
* Vertical space ('\\n'), after which it is generally a good idea to
|
||||
* perform indentation.
|
||||
*/
|
||||
CXCompletionChunk_VerticalSpace
|
||||
|
@ -5589,7 +5794,8 @@ typedef enum {
|
|||
CXIdxEntityLang_None = 0,
|
||||
CXIdxEntityLang_C = 1,
|
||||
CXIdxEntityLang_ObjC = 2,
|
||||
CXIdxEntityLang_CXX = 3
|
||||
CXIdxEntityLang_CXX = 3,
|
||||
CXIdxEntityLang_Swift = 4
|
||||
} CXIdxEntityLanguage;
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "clang/Basic/SanitizerBlacklist.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/XRayLists.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
@ -66,6 +67,7 @@
|
|||
#include <memory>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
@ -167,18 +169,20 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
mutable llvm::FoldingSet<DependentUnaryTransformType>
|
||||
DependentUnaryTransformTypes;
|
||||
mutable llvm::FoldingSet<AutoType> AutoTypes;
|
||||
mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
|
||||
DeducedTemplateSpecializationTypes;
|
||||
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
|
||||
llvm::FoldingSet<AttributedType> AttributedTypes;
|
||||
mutable llvm::FoldingSet<PipeType> PipeTypes;
|
||||
|
||||
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
|
||||
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
|
||||
mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
|
||||
mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
|
||||
SubstTemplateTemplateParms;
|
||||
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
|
||||
ASTContext&>
|
||||
ASTContext&>
|
||||
SubstTemplateTemplateParmPacks;
|
||||
|
||||
|
||||
/// \brief The set of nested name specifiers.
|
||||
///
|
||||
/// This set is managed by the NestedNameSpecifier class.
|
||||
|
@ -200,17 +204,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
|
||||
/// \brief A cache mapping from CXXRecordDecls to key functions.
|
||||
llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions;
|
||||
|
||||
|
||||
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
|
||||
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
|
||||
|
||||
|
||||
/// \brief Mapping from ObjCMethod to its duplicate declaration in the same
|
||||
/// interface.
|
||||
llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls;
|
||||
|
||||
/// \brief Mapping from __block VarDecls to their copy initialization expr.
|
||||
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
|
||||
|
||||
|
||||
/// \brief Mapping from class scope functions specialization to their
|
||||
/// template patterns.
|
||||
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
|
||||
|
@ -226,21 +230,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
/// is used in canonical template names.
|
||||
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
|
||||
TemplateTemplateParmDecl *Parm;
|
||||
|
||||
|
||||
public:
|
||||
CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm)
|
||||
CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm)
|
||||
: Parm(Parm) { }
|
||||
|
||||
|
||||
TemplateTemplateParmDecl *getParam() const { return Parm; }
|
||||
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
TemplateTemplateParmDecl *Parm);
|
||||
};
|
||||
mutable llvm::FoldingSet<CanonicalTemplateTemplateParm>
|
||||
CanonTemplateTemplateParms;
|
||||
|
||||
|
||||
TemplateTemplateParmDecl *
|
||||
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
|
||||
|
||||
|
@ -259,7 +263,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
|
||||
/// \brief The typedef for the predefined \c id type.
|
||||
mutable TypedefDecl *ObjCIdDecl;
|
||||
|
||||
|
||||
/// \brief The typedef for the predefined \c SEL type.
|
||||
mutable TypedefDecl *ObjCSelDecl;
|
||||
|
||||
|
@ -268,7 +272,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
|
||||
/// \brief The typedef for the predefined \c Protocol class in Objective-C.
|
||||
mutable ObjCInterfaceDecl *ObjCProtocolClassDecl;
|
||||
|
||||
|
||||
/// \brief The typedef for the predefined 'BOOL' type.
|
||||
mutable TypedefDecl *BOOLDecl;
|
||||
|
||||
|
@ -298,12 +302,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
mutable TypedefDecl *CFConstantStringTypeDecl;
|
||||
|
||||
mutable QualType ObjCSuperType;
|
||||
|
||||
|
||||
QualType ObjCNSStringType;
|
||||
|
||||
/// \brief The typedef declaration for the Objective-C "instancetype" type.
|
||||
TypedefDecl *ObjCInstanceTypeDecl;
|
||||
|
||||
|
||||
/// \brief The type for the C FILE type.
|
||||
TypeDecl *FILEDecl;
|
||||
|
||||
|
@ -451,11 +455,11 @@ private:
|
|||
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
|
||||
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
|
||||
typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
|
||||
ParameterIndexTable ParamIndices;
|
||||
|
||||
ParameterIndexTable ParamIndices;
|
||||
|
||||
ImportDecl *FirstLocalImport;
|
||||
ImportDecl *LastLocalImport;
|
||||
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
mutable ExternCContextDecl *ExternCContext;
|
||||
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl;
|
||||
|
@ -472,6 +476,10 @@ private:
|
|||
/// entities should not be instrumented.
|
||||
std::unique_ptr<SanitizerBlacklist> SanitizerBL;
|
||||
|
||||
/// \brief Function filtering mechanism to determine whether a given function
|
||||
/// should be imbued with the XRay "always" or "never" attributes.
|
||||
std::unique_ptr<XRayFunctionFilter> XRayFilter;
|
||||
|
||||
/// \brief The allocator used to create AST objects.
|
||||
///
|
||||
/// AST objects are never destructed; rather, all memory associated with the
|
||||
|
@ -488,7 +496,7 @@ private:
|
|||
/// \brief The logical -> physical address space map.
|
||||
const LangAS::Map *AddrSpaceMap;
|
||||
|
||||
/// \brief Address space map mangling must be used with language specific
|
||||
/// \brief Address space map mangling must be used with language specific
|
||||
/// address spaces (e.g. OpenCL/CUDA)
|
||||
bool AddrSpaceMapMangling;
|
||||
|
||||
|
@ -500,7 +508,7 @@ private:
|
|||
const TargetInfo *Target;
|
||||
const TargetInfo *AuxTarget;
|
||||
clang::PrintingPolicy PrintingPolicy;
|
||||
|
||||
|
||||
public:
|
||||
IdentifierTable &Idents;
|
||||
SelectorTable &Selectors;
|
||||
|
@ -604,7 +612,7 @@ public:
|
|||
void setPrintingPolicy(const clang::PrintingPolicy &Policy) {
|
||||
PrintingPolicy = Policy;
|
||||
}
|
||||
|
||||
|
||||
SourceManager& getSourceManager() { return SourceMgr; }
|
||||
const SourceManager& getSourceManager() const { return SourceMgr; }
|
||||
|
||||
|
@ -619,7 +627,7 @@ public:
|
|||
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
|
||||
}
|
||||
void Deallocate(void *Ptr) const { }
|
||||
|
||||
|
||||
/// Return the total amount of physical memory allocated for representing
|
||||
/// AST nodes and type information.
|
||||
size_t getASTAllocatedMemory() const {
|
||||
|
@ -627,7 +635,7 @@ public:
|
|||
}
|
||||
/// Return the total memory used for various side tables.
|
||||
size_t getSideTableAllocatedMemory() const;
|
||||
|
||||
|
||||
PartialDiagnostic::StorageAllocator &getDiagAllocator() {
|
||||
return DiagAllocator;
|
||||
}
|
||||
|
@ -647,13 +655,17 @@ public:
|
|||
QualType getRealTypeForBitwidth(unsigned DestWidth) const;
|
||||
|
||||
bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const;
|
||||
|
||||
|
||||
const LangOptions& getLangOpts() const { return LangOpts; }
|
||||
|
||||
const SanitizerBlacklist &getSanitizerBlacklist() const {
|
||||
return *SanitizerBL;
|
||||
}
|
||||
|
||||
const XRayFunctionFilter &getXRayFilter() const {
|
||||
return *XRayFilter;
|
||||
}
|
||||
|
||||
DiagnosticsEngine &getDiagnostics() const;
|
||||
|
||||
FullSourceLoc getFullLoc(SourceLocation Loc) const {
|
||||
|
@ -862,7 +874,7 @@ public:
|
|||
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
|
||||
|
||||
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
|
||||
|
||||
|
||||
// Access to the set of methods overridden by the given C++ method.
|
||||
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
|
||||
overridden_cxx_method_iterator
|
||||
|
@ -878,7 +890,7 @@ public:
|
|||
|
||||
/// \brief Note that the given C++ \p Method overrides the given \p
|
||||
/// Overridden method.
|
||||
void addOverriddenMethod(const CXXMethodDecl *Method,
|
||||
void addOverriddenMethod(const CXXMethodDecl *Method,
|
||||
const CXXMethodDecl *Overridden);
|
||||
|
||||
/// \brief Return C++ or ObjC overridden methods for the given \p Method.
|
||||
|
@ -891,7 +903,7 @@ public:
|
|||
void getOverriddenMethods(
|
||||
const NamedDecl *Method,
|
||||
SmallVectorImpl<const NamedDecl *> &Overridden) const;
|
||||
|
||||
|
||||
/// \brief Notify the AST context that a new import declaration has been
|
||||
/// parsed or implicitly created within this translation unit.
|
||||
void addedLocalImportDecl(ImportDecl *Import);
|
||||
|
@ -899,7 +911,7 @@ public:
|
|||
static ImportDecl *getNextLocalImport(ImportDecl *Import) {
|
||||
return Import->NextLocalImport;
|
||||
}
|
||||
|
||||
|
||||
typedef llvm::iterator_range<import_iterator> import_range;
|
||||
import_range local_imports() const {
|
||||
return import_range(import_iterator(FirstLocalImport), import_iterator());
|
||||
|
@ -923,7 +935,7 @@ public:
|
|||
|
||||
/// \brief Get the additional modules in which the definition \p Def has
|
||||
/// been merged.
|
||||
ArrayRef<Module*> getModulesWithMergedDefinition(NamedDecl *Def) {
|
||||
ArrayRef<Module*> getModulesWithMergedDefinition(const NamedDecl *Def) {
|
||||
auto MergedIt = MergedDefModules.find(Def);
|
||||
if (MergedIt == MergedDefModules.end())
|
||||
return None;
|
||||
|
@ -973,7 +985,7 @@ public:
|
|||
CanQualType SingletonId;
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
|
||||
CanQualType OCLQueueTy, OCLNDRangeTy, OCLReserveIDTy;
|
||||
CanQualType OCLQueueTy, OCLReserveIDTy;
|
||||
CanQualType OMPArraySectionTy;
|
||||
|
||||
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
|
||||
|
@ -1179,15 +1191,15 @@ public:
|
|||
|
||||
/// Returns true iff we need copy/dispose helpers for the given type.
|
||||
bool BlockRequiresCopying(QualType Ty, const VarDecl *D);
|
||||
|
||||
|
||||
|
||||
|
||||
/// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set
|
||||
/// to false in this case. If HasByrefExtendedLayout returns true, byref variable
|
||||
/// has extended lifetime.
|
||||
/// has extended lifetime.
|
||||
bool getByrefLifetime(QualType Ty,
|
||||
Qualifiers::ObjCLifetime &Lifetime,
|
||||
bool &HasByrefExtendedLayout) const;
|
||||
|
||||
|
||||
/// \brief Return the uniqued reference to the type for an lvalue reference
|
||||
/// to the specified type.
|
||||
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true)
|
||||
|
@ -1231,7 +1243,7 @@ public:
|
|||
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned IndexTypeQuals) const;
|
||||
|
||||
|
||||
/// \brief Returns a vla type where known sizes are replaced with [*].
|
||||
QualType getVariableArrayDecayedType(QualType Ty) const;
|
||||
|
||||
|
@ -1355,6 +1367,8 @@ public:
|
|||
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args) const;
|
||||
|
||||
TemplateArgument getInjectedTemplateArg(NamedDecl *ParamDecl);
|
||||
|
||||
/// Get a template argument list with one argument per template parameter
|
||||
/// in a template parameter list, such as for the injected class name of
|
||||
/// a class template.
|
||||
|
@ -1380,7 +1394,7 @@ public:
|
|||
QualType getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
|
||||
ArrayRef<ObjCProtocolDecl *> protocols,
|
||||
QualType Canonical = QualType()) const;
|
||||
|
||||
|
||||
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
|
||||
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
|
||||
/// QT's qualified-id protocol list adopt all protocols in IDecl's list
|
||||
|
@ -1412,6 +1426,11 @@ public:
|
|||
/// \brief C++11 deduction pattern for 'auto &&' type.
|
||||
QualType getAutoRRefDeductType() const;
|
||||
|
||||
/// \brief C++1z deduced class template specialization type.
|
||||
QualType getDeducedTemplateSpecializationType(TemplateName Template,
|
||||
QualType DeducedType,
|
||||
bool IsDependent) const;
|
||||
|
||||
/// \brief Return the unique reference to the type for the specified TagDecl
|
||||
/// (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(const TagDecl *Decl) const;
|
||||
|
@ -1422,6 +1441,10 @@ public:
|
|||
/// The sizeof operator requires this (C99 6.5.3.4p4).
|
||||
CanQualType getSizeType() const;
|
||||
|
||||
/// \brief Return the unique signed counterpart of
|
||||
/// the integer type corresponding to size_t.
|
||||
CanQualType getSignedSizeType() const;
|
||||
|
||||
/// \brief Return the unique type for "intmax_t" (C99 7.18.1.5), defined in
|
||||
/// <stdint.h>.
|
||||
CanQualType getIntMaxType() const;
|
||||
|
@ -1471,11 +1494,11 @@ public:
|
|||
|
||||
/// \brief Return the C structure type used to represent constant CFStrings.
|
||||
QualType getCFConstantStringType() const;
|
||||
|
||||
|
||||
/// \brief Returns the C struct type for objc_super
|
||||
QualType getObjCSuperType() const;
|
||||
void setObjCSuperType(QualType ST) { ObjCSuperType = ST; }
|
||||
|
||||
|
||||
/// Get the structure type used to representation CFStrings, or NULL
|
||||
/// if it hasn't yet been built.
|
||||
QualType getRawCFConstantStringType() const {
|
||||
|
@ -1496,11 +1519,11 @@ public:
|
|||
QualType getObjCNSStringType() const {
|
||||
return ObjCNSStringType;
|
||||
}
|
||||
|
||||
|
||||
void setObjCNSStringType(QualType T) {
|
||||
ObjCNSStringType = T;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the type that \c id has been defined to, which may be
|
||||
/// different from the built-in \c id if \c id has been typedef'd.
|
||||
QualType getObjCIdRedefinitionType() const {
|
||||
|
@ -1508,7 +1531,7 @@ public:
|
|||
return getObjCIdType();
|
||||
return ObjCIdRedefinitionType;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Set the user-written type that redefines \c id.
|
||||
void setObjCIdRedefinitionType(QualType RedefType) {
|
||||
ObjCIdRedefinitionType = RedefType;
|
||||
|
@ -1521,7 +1544,7 @@ public:
|
|||
return getObjCClassType();
|
||||
return ObjCClassRedefinitionType;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Set the user-written type that redefines 'SEL'.
|
||||
void setObjCClassRedefinitionType(QualType RedefType) {
|
||||
ObjCClassRedefinitionType = RedefType;
|
||||
|
@ -1534,7 +1557,7 @@ public:
|
|||
return getObjCSelType();
|
||||
return ObjCSelRedefinitionType;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Set the user-written type that redefines 'SEL'.
|
||||
void setObjCSelRedefinitionType(QualType RedefType) {
|
||||
ObjCSelRedefinitionType = RedefType;
|
||||
|
@ -1586,7 +1609,7 @@ public:
|
|||
/// \brief Retrieve the typedef declaration corresponding to the Objective-C
|
||||
/// "instancetype" type.
|
||||
TypedefDecl *getObjCInstanceTypeDecl();
|
||||
|
||||
|
||||
/// \brief Set the type for the C FILE type.
|
||||
void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
|
||||
|
||||
|
@ -1671,7 +1694,7 @@ public:
|
|||
|
||||
/// \brief Return the encoded type for this block declaration.
|
||||
std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const;
|
||||
|
||||
|
||||
/// getObjCEncodingForPropertyDecl - Return the encoded type for
|
||||
/// this method declaration. If non-NULL, Container must be either
|
||||
/// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should
|
||||
|
@ -1681,7 +1704,7 @@ public:
|
|||
|
||||
bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
|
||||
ObjCProtocolDecl *rProto) const;
|
||||
|
||||
|
||||
ObjCPropertyImplDecl *getObjCPropertyImplDeclForPropertyDecl(
|
||||
const ObjCPropertyDecl *PD,
|
||||
const Decl *Container) const;
|
||||
|
@ -1693,7 +1716,7 @@ public:
|
|||
/// \brief Retrieve the typedef corresponding to the predefined \c id type
|
||||
/// in Objective-C.
|
||||
TypedefDecl *getObjCIdDecl() const;
|
||||
|
||||
|
||||
/// \brief Represents the Objective-CC \c id type.
|
||||
///
|
||||
/// This is set up lazily, by Sema. \c id is always a (typedef for a)
|
||||
|
@ -1705,26 +1728,26 @@ public:
|
|||
/// \brief Retrieve the typedef corresponding to the predefined 'SEL' type
|
||||
/// in Objective-C.
|
||||
TypedefDecl *getObjCSelDecl() const;
|
||||
|
||||
|
||||
/// \brief Retrieve the type that corresponds to the predefined Objective-C
|
||||
/// 'SEL' type.
|
||||
QualType getObjCSelType() const {
|
||||
QualType getObjCSelType() const {
|
||||
return getTypeDeclType(getObjCSelDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the typedef declaration corresponding to the predefined
|
||||
/// Objective-C 'Class' type.
|
||||
TypedefDecl *getObjCClassDecl() const;
|
||||
|
||||
|
||||
/// \brief Represents the Objective-C \c Class type.
|
||||
///
|
||||
/// This is set up lazily, by Sema. \c Class is always a (typedef for a)
|
||||
/// pointer type, a pointer to a struct.
|
||||
QualType getObjCClassType() const {
|
||||
QualType getObjCClassType() const {
|
||||
return getTypeDeclType(getObjCClassDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the Objective-C class declaration corresponding to
|
||||
/// \brief Retrieve the Objective-C class declaration corresponding to
|
||||
/// the predefined \c Protocol class.
|
||||
ObjCInterfaceDecl *getObjCProtocolDecl() const;
|
||||
|
||||
|
@ -1742,12 +1765,12 @@ public:
|
|||
QualType getBOOLType() const {
|
||||
return getTypeDeclType(getBOOLDecl());
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the type of the Objective-C \c Protocol class.
|
||||
QualType getObjCProtoType() const {
|
||||
return getObjCInterfaceType(getObjCProtocolDecl());
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the C type declaration corresponding to the predefined
|
||||
/// \c __builtin_va_list type.
|
||||
TypedefDecl *getBuiltinVaListDecl() const;
|
||||
|
@ -1810,7 +1833,7 @@ public:
|
|||
qs.addObjCLifetime(lifetime);
|
||||
return getQualifiedType(type, qs);
|
||||
}
|
||||
|
||||
|
||||
/// getUnqualifiedObjCPointerType - Returns version of
|
||||
/// Objective-C pointer type with lifetime qualifier removed.
|
||||
QualType getUnqualifiedObjCPointerType(QualType type) const {
|
||||
|
@ -1821,7 +1844,7 @@ public:
|
|||
Qs.removeObjCLifetime();
|
||||
return getQualifiedType(type.getUnqualifiedType(), Qs);
|
||||
}
|
||||
|
||||
|
||||
DeclarationNameInfo getNameForTemplate(TemplateName Name,
|
||||
SourceLocation NameLoc) const;
|
||||
|
||||
|
@ -1840,7 +1863,7 @@ public:
|
|||
TemplateName replacement) const;
|
||||
TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
|
||||
const TemplateArgument &ArgPack) const;
|
||||
|
||||
|
||||
enum GetBuiltinTypeError {
|
||||
GE_None, ///< No error
|
||||
GE_Missing_stdio, ///< Missing a type from <stdio.h>
|
||||
|
@ -1905,7 +1928,7 @@ public:
|
|||
uint64_t getCharWidth() const {
|
||||
return getTypeSize(CharTy);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Convert a size in bits to a size in characters.
|
||||
CharUnits toCharUnitsFromBits(int64_t BitSize) const;
|
||||
|
||||
|
@ -1927,11 +1950,11 @@ public:
|
|||
/// example, from alignment attributes).
|
||||
unsigned getTypeAlignIfKnown(QualType T) const;
|
||||
|
||||
/// \brief Return the ABI-specified alignment of a (complete) type \p T, in
|
||||
/// \brief Return the ABI-specified alignment of a (complete) type \p T, in
|
||||
/// characters.
|
||||
CharUnits getTypeAlignInChars(QualType T) const;
|
||||
CharUnits getTypeAlignInChars(const Type *T) const;
|
||||
|
||||
|
||||
// getTypeInfoDataSizeInChars - Return the size of a type, in chars. If the
|
||||
// type is a record, its data size is returned.
|
||||
std::pair<CharUnits, CharUnits> getTypeInfoDataSizeInChars(QualType T) const;
|
||||
|
@ -2031,15 +2054,20 @@ public:
|
|||
/// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
|
||||
uint64_t getFieldOffset(const ValueDecl *FD) const;
|
||||
|
||||
/// Get the offset of an ObjCIvarDecl in bits.
|
||||
uint64_t lookupFieldBitOffset(const ObjCInterfaceDecl *OID,
|
||||
const ObjCImplementationDecl *ID,
|
||||
const ObjCIvarDecl *Ivar) const;
|
||||
|
||||
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
|
||||
|
||||
VTableContextBase *getVTableContext();
|
||||
|
||||
MangleContext *createMangleContext();
|
||||
|
||||
|
||||
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
|
||||
SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
|
||||
|
||||
|
||||
unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const;
|
||||
void CollectInheritedProtocols(const Decl *CDecl,
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
|
||||
|
@ -2115,7 +2143,7 @@ public:
|
|||
*SubTnullability == NullabilityKind::Unspecified ||
|
||||
*SuperTnullability == NullabilityKind::Unspecified)
|
||||
return true;
|
||||
|
||||
|
||||
if (IsParam) {
|
||||
// Ok for the superclass method parameter to be "nonnull" and the subclass
|
||||
// method parameter to be "nullable"
|
||||
|
@ -2134,9 +2162,9 @@ public:
|
|||
|
||||
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
|
||||
const ObjCMethodDecl *MethodImp);
|
||||
|
||||
|
||||
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
|
||||
|
||||
|
||||
/// \brief Retrieves the "canonical" nested name specifier for a
|
||||
/// given nested name specifier.
|
||||
///
|
||||
|
@ -2190,7 +2218,7 @@ public:
|
|||
/// \brief Determine whether the given template names refer to the same
|
||||
/// template.
|
||||
bool hasSameTemplateName(TemplateName X, TemplateName Y);
|
||||
|
||||
|
||||
/// \brief Retrieve the "canonical" template argument.
|
||||
///
|
||||
/// The canonical template argument is the simplest template argument
|
||||
|
@ -2217,7 +2245,7 @@ public:
|
|||
const {
|
||||
return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T));
|
||||
}
|
||||
|
||||
|
||||
/// \brief Return the innermost element type of an array type.
|
||||
///
|
||||
/// For example, will return "int" for int[m][n]
|
||||
|
@ -2236,14 +2264,14 @@ public:
|
|||
/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
|
||||
/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
|
||||
QualType getAdjustedParameterType(QualType T) const;
|
||||
|
||||
|
||||
/// \brief Retrieve the parameter type as adjusted for use in the signature
|
||||
/// of a function, decaying array and function types and removing top-level
|
||||
/// cv-qualifiers.
|
||||
QualType getSignatureParameterType(QualType T) const;
|
||||
|
||||
|
||||
QualType getExceptionObjectType(QualType T) const;
|
||||
|
||||
|
||||
/// \brief Return the properly qualified result of decaying the specified
|
||||
/// array type to a pointer.
|
||||
///
|
||||
|
@ -2269,7 +2297,7 @@ public:
|
|||
/// promotion occurs.
|
||||
QualType isPromotableBitField(Expr *E) const;
|
||||
|
||||
/// \brief Return the highest ranked integer type, see C99 6.3.1.8p1.
|
||||
/// \brief Return the highest ranked integer type, see C99 6.3.1.8p1.
|
||||
///
|
||||
/// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If
|
||||
/// \p LHS < \p RHS, return -1.
|
||||
|
@ -2298,21 +2326,14 @@ public:
|
|||
return getTargetAddressSpace(Q.getAddressSpace());
|
||||
}
|
||||
|
||||
unsigned getTargetAddressSpace(unsigned AS) const {
|
||||
if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count)
|
||||
return AS;
|
||||
else
|
||||
return (*AddrSpaceMap)[AS - LangAS::Offset];
|
||||
}
|
||||
unsigned getTargetAddressSpace(unsigned AS) const;
|
||||
|
||||
/// Get target-dependent integer value for null pointer which is used for
|
||||
/// constant folding.
|
||||
uint64_t getTargetNullPointerValue(QualType QT) const;
|
||||
|
||||
bool addressSpaceMapManglingFor(unsigned AS) const {
|
||||
return AddrSpaceMapMangling ||
|
||||
AS < LangAS::Offset ||
|
||||
AS >= LangAS::Offset + LangAS::Count;
|
||||
return AddrSpaceMapMangling || AS >= LangAS::FirstTargetAddressSpace;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -2325,11 +2346,11 @@ public:
|
|||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Compatibility predicates used to check assignment expressions.
|
||||
bool typesAreCompatible(QualType T1, QualType T2,
|
||||
bool typesAreCompatible(QualType T1, QualType T2,
|
||||
bool CompareUnqualified = false); // C99 6.2.7p1
|
||||
|
||||
bool propertyTypesAreCompatible(QualType, QualType);
|
||||
bool typesAreBlockPointerCompatible(QualType, QualType);
|
||||
bool propertyTypesAreCompatible(QualType, QualType);
|
||||
bool typesAreBlockPointerCompatible(QualType, QualType);
|
||||
|
||||
bool isObjCIdType(QualType T) const {
|
||||
return T == getObjCIdType();
|
||||
|
@ -2344,7 +2365,7 @@ public:
|
|||
bool ForCompare);
|
||||
|
||||
bool ObjCQualifiedClassTypesAreCompatible(QualType LHS, QualType RHS);
|
||||
|
||||
|
||||
// Check the safety of assignment from LHS to RHS
|
||||
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
|
||||
const ObjCObjectPointerType *RHSOPT);
|
||||
|
@ -2370,9 +2391,9 @@ public:
|
|||
QualType mergeTransparentUnionType(QualType, QualType,
|
||||
bool OfBlockPointer=false,
|
||||
bool Unqualified = false);
|
||||
|
||||
|
||||
QualType mergeObjCGCQualifiers(QualType, QualType);
|
||||
|
||||
|
||||
bool doFunctionTypesMatchOnExtParameterInfos(
|
||||
const FunctionProtoType *FromFunctionType,
|
||||
const FunctionProtoType *ToFunctionType);
|
||||
|
@ -2442,7 +2463,7 @@ public:
|
|||
/// an Objective-C method/property/ivar etc. that is part of an interface,
|
||||
/// otherwise returns null.
|
||||
const ObjCInterfaceDecl *getObjContainingInterface(const NamedDecl *ND) const;
|
||||
|
||||
|
||||
/// \brief Set the copy inialization expression of a block var decl.
|
||||
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
|
||||
/// \brief Get the copy initialization expression of the VarDecl \p VD, or
|
||||
|
@ -2466,10 +2487,10 @@ public:
|
|||
/// initialized to a given location, which defaults to the empty
|
||||
/// location.
|
||||
TypeSourceInfo *
|
||||
getTrivialTypeSourceInfo(QualType T,
|
||||
getTrivialTypeSourceInfo(QualType T,
|
||||
SourceLocation Loc = SourceLocation()) const;
|
||||
|
||||
/// \brief Add a deallocation callback that will be invoked when the
|
||||
/// \brief Add a deallocation callback that will be invoked when the
|
||||
/// ASTContext is destroyed.
|
||||
///
|
||||
/// \param Callback A callback function that will be invoked on destruction.
|
||||
|
@ -2478,6 +2499,16 @@ public:
|
|||
/// when it is called.
|
||||
void AddDeallocation(void (*Callback)(void*), void *Data);
|
||||
|
||||
/// If T isn't trivially destructible, calls AddDeallocation to register it
|
||||
/// for destruction.
|
||||
template <typename T>
|
||||
void addDestruction(T *Ptr) {
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
auto DestroyPtr = [](void *V) { static_cast<T *>(V)->~T(); };
|
||||
AddDeallocation(DestroyPtr, Ptr);
|
||||
}
|
||||
}
|
||||
|
||||
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
|
||||
GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
|
||||
|
||||
|
@ -2534,15 +2565,15 @@ public:
|
|||
|
||||
/// \brief The number of implicitly-declared default constructors.
|
||||
static unsigned NumImplicitDefaultConstructors;
|
||||
|
||||
/// \brief The number of implicitly-declared default constructors for
|
||||
|
||||
/// \brief The number of implicitly-declared default constructors for
|
||||
/// which declarations were built.
|
||||
static unsigned NumImplicitDefaultConstructorsDeclared;
|
||||
|
||||
/// \brief The number of implicitly-declared copy constructors.
|
||||
static unsigned NumImplicitCopyConstructors;
|
||||
|
||||
/// \brief The number of implicitly-declared copy constructors for
|
||||
|
||||
/// \brief The number of implicitly-declared copy constructors for
|
||||
/// which declarations were built.
|
||||
static unsigned NumImplicitCopyConstructorsDeclared;
|
||||
|
||||
|
@ -2555,25 +2586,25 @@ public:
|
|||
|
||||
/// \brief The number of implicitly-declared copy assignment operators.
|
||||
static unsigned NumImplicitCopyAssignmentOperators;
|
||||
|
||||
/// \brief The number of implicitly-declared copy assignment operators for
|
||||
|
||||
/// \brief The number of implicitly-declared copy assignment operators for
|
||||
/// which declarations were built.
|
||||
static unsigned NumImplicitCopyAssignmentOperatorsDeclared;
|
||||
|
||||
/// \brief The number of implicitly-declared move assignment operators.
|
||||
static unsigned NumImplicitMoveAssignmentOperators;
|
||||
|
||||
/// \brief The number of implicitly-declared move assignment operators for
|
||||
|
||||
/// \brief The number of implicitly-declared move assignment operators for
|
||||
/// which declarations were built.
|
||||
static unsigned NumImplicitMoveAssignmentOperatorsDeclared;
|
||||
|
||||
/// \brief The number of implicitly-declared destructors.
|
||||
static unsigned NumImplicitDestructors;
|
||||
|
||||
/// \brief The number of implicitly-declared destructors for which
|
||||
|
||||
/// \brief The number of implicitly-declared destructors for which
|
||||
/// declarations were built.
|
||||
static unsigned NumImplicitDestructorsDeclared;
|
||||
|
||||
|
||||
public:
|
||||
/// \brief Initialize built-in types.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
//===--- ASTStructuralEquivalence.h - ---------------------------*- 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 StructuralEquivalenceContext class which checks for
|
||||
// structural equivalence between types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
|
||||
#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include <deque>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class DiagnosticBuilder;
|
||||
class QualType;
|
||||
class RecordDecl;
|
||||
class SourceLocation;
|
||||
|
||||
struct StructuralEquivalenceContext {
|
||||
/// AST contexts for which we are checking structural equivalence.
|
||||
ASTContext &FromCtx, &ToCtx;
|
||||
|
||||
/// The set of "tentative" equivalences between two canonical
|
||||
/// declarations, mapping from a declaration in the first context to the
|
||||
/// declaration in the second context that we believe to be equivalent.
|
||||
llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
|
||||
|
||||
/// Queue of declarations in the first context whose equivalence
|
||||
/// with a declaration in the second context still needs to be verified.
|
||||
std::deque<Decl *> DeclsToCheck;
|
||||
|
||||
/// Declaration (from, to) pairs that are known not to be equivalent
|
||||
/// (which we have already complained about).
|
||||
llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls;
|
||||
|
||||
/// Whether we're being strict about the spelling of types when
|
||||
/// unifying two types.
|
||||
bool StrictTypeSpelling;
|
||||
|
||||
/// Whether warn or error on tag type mismatches.
|
||||
bool ErrorOnTagTypeMismatch;
|
||||
|
||||
/// Whether to complain about failures.
|
||||
bool Complain;
|
||||
|
||||
/// \c true if the last diagnostic came from ToCtx.
|
||||
bool LastDiagFromC2;
|
||||
|
||||
StructuralEquivalenceContext(
|
||||
ASTContext &FromCtx, ASTContext &ToCtx,
|
||||
llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls,
|
||||
bool StrictTypeSpelling = false, bool Complain = true,
|
||||
bool ErrorOnTagTypeMismatch = false)
|
||||
: FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
|
||||
StrictTypeSpelling(StrictTypeSpelling),
|
||||
ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
|
||||
LastDiagFromC2(false) {}
|
||||
|
||||
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
|
||||
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
|
||||
|
||||
/// Determine whether the two declarations are structurally
|
||||
/// equivalent.
|
||||
bool IsStructurallyEquivalent(Decl *D1, Decl *D2);
|
||||
|
||||
/// Determine whether the two types are structurally equivalent.
|
||||
bool IsStructurallyEquivalent(QualType T1, QualType T2);
|
||||
|
||||
/// Find the index of the given anonymous struct/union within its
|
||||
/// context.
|
||||
///
|
||||
/// \returns Returns the index of this anonymous struct/union in its context,
|
||||
/// including the next assigned index (if none of them match). Returns an
|
||||
/// empty option if the context is not a record, i.e.. if the anonymous
|
||||
/// struct/union is at namespace or block scope.
|
||||
///
|
||||
/// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
|
||||
/// probably makes more sense in some other common place then here.
|
||||
static llvm::Optional<unsigned>
|
||||
findUntaggedStructOrUnionIndex(RecordDecl *Anon);
|
||||
|
||||
private:
|
||||
/// Finish checking all of the structural equivalences.
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
bool Finish();
|
||||
};
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
|
|
@ -22,6 +22,7 @@
|
|||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
|
|
|
@ -169,9 +169,6 @@ BUILTIN_TYPE(OCLClkEvent, OCLClkEventTy)
|
|||
// OpenCL queue_t.
|
||||
BUILTIN_TYPE(OCLQueue, OCLQueueTy)
|
||||
|
||||
// OpenCL ndrange_t.
|
||||
BUILTIN_TYPE(OCLNDRange, OCLNDRangeTy)
|
||||
|
||||
// OpenCL reserve_id_t.
|
||||
BUILTIN_TYPE(OCLReserveID, OCLReserveIDTy)
|
||||
|
||||
|
|
|
@ -127,7 +127,11 @@ class CXXBasePaths {
|
|||
/// class subobjects for that class type. The key of the map is
|
||||
/// the cv-unqualified canonical type of the base class subobject.
|
||||
llvm::SmallDenseMap<QualType, std::pair<bool, unsigned>, 8> ClassSubobjects;
|
||||
|
||||
|
||||
/// VisitedDependentRecords - Records the dependent records that have been
|
||||
/// already visited.
|
||||
llvm::SmallDenseSet<const CXXRecordDecl *, 4> VisitedDependentRecords;
|
||||
|
||||
/// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
|
||||
/// ambiguous paths while it is looking for a path from a derived
|
||||
/// type to a base type.
|
||||
|
@ -161,7 +165,8 @@ class CXXBasePaths {
|
|||
void ComputeDeclsFound();
|
||||
|
||||
bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record,
|
||||
CXXRecordDecl::BaseMatchesCallback BaseMatches);
|
||||
CXXRecordDecl::BaseMatchesCallback BaseMatches,
|
||||
bool LookupInDependent = false);
|
||||
|
||||
public:
|
||||
typedef std::list<CXXBasePath>::iterator paths_iterator;
|
||||
|
|
|
@ -208,6 +208,10 @@ public:
|
|||
/// \returns \c true if declaration that this comment is attached to declares
|
||||
/// a function pointer.
|
||||
bool isFunctionPointerVarDecl();
|
||||
/// \returns \c true if the declaration that this comment is attached to
|
||||
/// declares a variable or a field whose type is a function or a block
|
||||
/// pointer.
|
||||
bool isFunctionOrBlockPointerVarLikeDecl();
|
||||
bool isFunctionOrMethodVariadic();
|
||||
bool isObjCMethodDecl();
|
||||
bool isObjCPropertyDecl();
|
||||
|
|
|
@ -301,16 +301,6 @@ public:
|
|||
using Decl::isModulePrivate;
|
||||
using Decl::setModulePrivate;
|
||||
|
||||
/// \brief Determine whether this declaration is hidden from name lookup.
|
||||
bool isHidden() const { return Hidden; }
|
||||
|
||||
/// \brief Set whether this declaration is hidden from name lookup.
|
||||
void setHidden(bool Hide) {
|
||||
assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
|
||||
"declaration with no owning module can't be hidden");
|
||||
Hidden = Hide;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration is a C++ class member.
|
||||
bool isCXXClassMember() const {
|
||||
const DeclContext *DC = getDeclContext();
|
||||
|
@ -838,7 +828,7 @@ protected:
|
|||
|
||||
/// Describes the kind of default argument for this parameter. By default
|
||||
/// this is none. If this is normal, then the default argument is stored in
|
||||
/// the \c VarDecl initalizer expression unless we were unble to parse
|
||||
/// the \c VarDecl initializer expression unless we were unable to parse
|
||||
/// (even an invalid) expression for the default argument.
|
||||
unsigned DefaultArgKind : 2;
|
||||
|
||||
|
@ -861,6 +851,7 @@ protected:
|
|||
|
||||
class NonParmVarDeclBitfields {
|
||||
friend class VarDecl;
|
||||
friend class ImplicitParamDecl;
|
||||
friend class ASTDeclReader;
|
||||
|
||||
unsigned : NumVarDeclBits;
|
||||
|
@ -904,6 +895,10 @@ protected:
|
|||
/// declared in the same block scope. This controls whether we should merge
|
||||
/// the type of this declaration with its previous declaration.
|
||||
unsigned PreviousDeclInSameBlockScope : 1;
|
||||
|
||||
/// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or
|
||||
/// something else.
|
||||
unsigned ImplicitParamKind : 3;
|
||||
};
|
||||
|
||||
union {
|
||||
|
@ -966,9 +961,16 @@ public:
|
|||
/// hasLocalStorage - Returns true if a variable with function scope
|
||||
/// is a non-static local variable.
|
||||
bool hasLocalStorage() const {
|
||||
if (getStorageClass() == SC_None)
|
||||
if (getStorageClass() == SC_None) {
|
||||
// OpenCL v1.2 s6.5.3: The __constant or constant address space name is
|
||||
// used to describe variables allocated in global memory and which are
|
||||
// accessed inside a kernel(s) as read-only variables. As such, variables
|
||||
// in constant address space cannot have local storage.
|
||||
if (getType().getAddressSpace() == LangAS::opencl_constant)
|
||||
return false;
|
||||
// Second check is for C++11 [dcl.stc]p4.
|
||||
return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
|
||||
}
|
||||
|
||||
// Global Named Register (GNU extension)
|
||||
if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm())
|
||||
|
@ -1379,20 +1381,50 @@ public:
|
|||
|
||||
class ImplicitParamDecl : public VarDecl {
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
/// Defines the kind of the implicit parameter: is this an implicit parameter
|
||||
/// with pointer to 'this', 'self', '_cmd', virtual table pointers, captured
|
||||
/// context or something else.
|
||||
enum ImplicitParamKind : unsigned {
|
||||
ObjCSelf, /// Parameter for Objective-C 'self' argument
|
||||
ObjCCmd, /// Parameter for Objective-C '_cmd' argument
|
||||
CXXThis, /// Parameter for C++ 'this' argument
|
||||
CXXVTT, /// Parameter for C++ virtual table pointers
|
||||
CapturedContext, /// Parameter for captured context
|
||||
Other, /// Other implicit parameter
|
||||
};
|
||||
|
||||
/// Create implicit parameter.
|
||||
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
QualType T);
|
||||
QualType T, ImplicitParamKind ParamKind);
|
||||
static ImplicitParamDecl *Create(ASTContext &C, QualType T,
|
||||
ImplicitParamKind ParamKind);
|
||||
|
||||
static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, QualType Type)
|
||||
: VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
|
||||
/*tinfo*/ nullptr, SC_None) {
|
||||
IdentifierInfo *Id, QualType Type,
|
||||
ImplicitParamKind ParamKind)
|
||||
: VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
|
||||
/*TInfo=*/nullptr, SC_None) {
|
||||
NonParmVarDeclBits.ImplicitParamKind = ParamKind;
|
||||
setImplicit();
|
||||
}
|
||||
|
||||
ImplicitParamDecl(ASTContext &C, QualType Type, ImplicitParamKind ParamKind)
|
||||
: VarDecl(ImplicitParam, C, /*DC=*/nullptr, SourceLocation(),
|
||||
SourceLocation(), /*Id=*/nullptr, Type,
|
||||
/*TInfo=*/nullptr, SC_None) {
|
||||
NonParmVarDeclBits.ImplicitParamKind = ParamKind;
|
||||
setImplicit();
|
||||
}
|
||||
|
||||
/// Returns the implicit parameter kind.
|
||||
ImplicitParamKind getParameterKind() const {
|
||||
return static_cast<ImplicitParamKind>(NonParmVarDeclBits.ImplicitParamKind);
|
||||
}
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ImplicitParam; }
|
||||
|
@ -1605,9 +1637,14 @@ private:
|
|||
|
||||
// FIXME: This can be packed into the bitfields in DeclContext.
|
||||
// NOTE: VC++ packs bitfields poorly if the types differ.
|
||||
unsigned SClass : 2;
|
||||
unsigned SClass : 3;
|
||||
unsigned IsInline : 1;
|
||||
unsigned IsInlineSpecified : 1;
|
||||
protected:
|
||||
// This is shared by CXXConstructorDecl, CXXConversionDecl, and
|
||||
// CXXDeductionGuideDecl.
|
||||
unsigned IsExplicitSpecified : 1;
|
||||
private:
|
||||
unsigned IsVirtualAsWritten : 1;
|
||||
unsigned IsPure : 1;
|
||||
unsigned HasInheritedPrototype : 1;
|
||||
|
@ -1619,6 +1656,7 @@ private:
|
|||
unsigned HasImplicitReturnZero : 1;
|
||||
unsigned IsLateTemplateParsed : 1;
|
||||
unsigned IsConstexpr : 1;
|
||||
unsigned InstantiationIsPending:1;
|
||||
|
||||
/// \brief Indicates if the function uses __try.
|
||||
unsigned UsesSEHTry : 1;
|
||||
|
@ -1708,11 +1746,13 @@ protected:
|
|||
StartLoc),
|
||||
DeclContext(DK), redeclarable_base(C), ParamInfo(nullptr), Body(),
|
||||
SClass(S), IsInline(isInlineSpecified),
|
||||
IsInlineSpecified(isInlineSpecified), IsVirtualAsWritten(false),
|
||||
IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true),
|
||||
IsInlineSpecified(isInlineSpecified), IsExplicitSpecified(false),
|
||||
IsVirtualAsWritten(false), IsPure(false),
|
||||
HasInheritedPrototype(false), HasWrittenPrototype(true),
|
||||
IsDeleted(false), IsTrivial(false), IsDefaulted(false),
|
||||
IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
|
||||
IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
|
||||
InstantiationIsPending(false),
|
||||
UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false),
|
||||
EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(),
|
||||
DNLoc(NameInfo.getInfo()) {}
|
||||
|
@ -1826,14 +1866,15 @@ public:
|
|||
return getBody(Definition);
|
||||
}
|
||||
|
||||
/// isThisDeclarationADefinition - Returns whether this specific
|
||||
/// declaration of the function is also a definition. This does not
|
||||
/// determine whether the function has been defined (e.g., in a
|
||||
/// previous definition); for that information, use isDefined. Note
|
||||
/// that this returns false for a defaulted function unless that function
|
||||
/// has been implicitly defined (possibly as deleted).
|
||||
/// Returns whether this specific declaration of the function is also a
|
||||
/// definition that does not contain uninstantiated body.
|
||||
///
|
||||
/// This does not determine whether the function has been defined (e.g., in a
|
||||
/// previous definition); for that information, use isDefined.
|
||||
///
|
||||
bool isThisDeclarationADefinition() const {
|
||||
return IsDeleted || Body || IsLateTemplateParsed;
|
||||
return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
|
||||
WillHaveBody || hasDefiningAttr();
|
||||
}
|
||||
|
||||
/// doesThisDeclarationHaveABody - Returns whether this specific
|
||||
|
@ -1904,6 +1945,15 @@ public:
|
|||
bool isConstexpr() const { return IsConstexpr; }
|
||||
void setConstexpr(bool IC) { IsConstexpr = IC; }
|
||||
|
||||
/// \brief Whether the instantiation of this function is pending.
|
||||
/// This bit is set when the decision to instantiate this function is made
|
||||
/// and unset if and when the function body is created. That leaves out
|
||||
/// cases where instantiation did not happen because the template definition
|
||||
/// was not seen in this TU. This bit remains set in those cases, under the
|
||||
/// assumption that the instantiation will happen in some other TU.
|
||||
bool instantiationIsPending() const { return InstantiationIsPending; }
|
||||
void setInstantiationIsPending(bool IC) { InstantiationIsPending = IC; }
|
||||
|
||||
/// \brief Indicates the function uses __try.
|
||||
bool usesSEHTry() const { return UsesSEHTry; }
|
||||
void setUsesSEHTry(bool UST) { UsesSEHTry = UST; }
|
||||
|
@ -1969,7 +2019,10 @@ public:
|
|||
/// 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;
|
||||
///
|
||||
/// If this function is an aligned allocation/deallocation function, return
|
||||
/// true through IsAligned.
|
||||
bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const;
|
||||
|
||||
/// Compute the language linkage.
|
||||
LanguageLinkage getLanguageLinkage() const;
|
||||
|
@ -2076,10 +2129,7 @@ public:
|
|||
const Attr *getUnusedResultAttr() const;
|
||||
|
||||
/// \brief Returns true if this function or its return type has the
|
||||
/// warn_unused_result attribute. If the return type has the attribute and
|
||||
/// this function is a method of the return type's class, then false will be
|
||||
/// returned to avoid spurious warnings on member methods such as assignment
|
||||
/// operators.
|
||||
/// warn_unused_result attribute.
|
||||
bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; }
|
||||
|
||||
/// \brief Returns the storage class as written in the source. For the
|
||||
|
@ -2475,7 +2525,7 @@ public:
|
|||
void setCapturedVLAType(const VariableArrayType *VLAType);
|
||||
|
||||
/// getParent - Returns the parent of this field declaration, which
|
||||
/// is the struct in which this method is defined.
|
||||
/// is the struct in which this field is defined.
|
||||
const RecordDecl *getParent() const {
|
||||
return cast<RecordDecl>(getDeclContext());
|
||||
}
|
||||
|
@ -2635,12 +2685,17 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
|||
typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
|
||||
llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
|
||||
|
||||
// FIXME: This can be packed into the bitfields in Decl.
|
||||
/// If 0, we have not computed IsTransparentTag.
|
||||
/// Otherwise, IsTransparentTag is (CacheIsTransparentTag >> 1).
|
||||
mutable unsigned CacheIsTransparentTag : 2;
|
||||
|
||||
protected:
|
||||
TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, TypeSourceInfo *TInfo)
|
||||
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C),
|
||||
MaybeModedTInfo(TInfo) {}
|
||||
MaybeModedTInfo(TInfo), CacheIsTransparentTag(0) {}
|
||||
|
||||
typedef Redeclarable<TypedefNameDecl> redeclarable_base;
|
||||
TypedefNameDecl *getNextRedeclarationImpl() override {
|
||||
|
@ -2693,11 +2748,22 @@ public:
|
|||
/// this typedef declaration.
|
||||
TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const;
|
||||
|
||||
/// Determines if this typedef shares a name and spelling location with its
|
||||
/// underlying tag type, as is the case with the NS_ENUM macro.
|
||||
bool isTransparentTag() const {
|
||||
if (CacheIsTransparentTag)
|
||||
return CacheIsTransparentTag & 0x2;
|
||||
return isTransparentTagSlow();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstTypedefName && K <= lastTypedefName;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isTransparentTagSlow() const;
|
||||
};
|
||||
|
||||
/// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef'
|
||||
|
@ -3229,6 +3295,18 @@ public:
|
|||
return isCompleteDefinition() || isFixed();
|
||||
}
|
||||
|
||||
/// Returns true if this enum is either annotated with
|
||||
/// enum_extensibility(closed) or isn't annotated with enum_extensibility.
|
||||
bool isClosed() const;
|
||||
|
||||
/// Returns true if this enum is annotated with flag_enum and isn't annotated
|
||||
/// with enum_extensibility(open).
|
||||
bool isClosedFlag() const;
|
||||
|
||||
/// Returns true if this enum is annotated with neither flag_enum nor
|
||||
/// enum_extensibility(open).
|
||||
bool isClosedNonFlag() const;
|
||||
|
||||
/// \brief Retrieve the enum definition from which this enumeration could
|
||||
/// be instantiated, if it is an instantiation (rather than a non-template).
|
||||
EnumDecl *getTemplateInstantiationPattern() const;
|
||||
|
|
|
@ -34,6 +34,7 @@ class DeclarationName;
|
|||
class DependentDiagnostic;
|
||||
class EnumDecl;
|
||||
class ExportDecl;
|
||||
class ExternalSourceSymbolAttr;
|
||||
class FunctionDecl;
|
||||
class FunctionType;
|
||||
enum Linkage : unsigned char;
|
||||
|
@ -201,26 +202,33 @@ public:
|
|||
OBJC_TQ_CSNullability = 0x40
|
||||
};
|
||||
|
||||
protected:
|
||||
// Enumeration values used in the bits stored in NextInContextAndBits.
|
||||
enum {
|
||||
/// \brief Whether this declaration is a top-level declaration (function,
|
||||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
TopLevelDeclInObjCContainerFlag = 0x01,
|
||||
|
||||
/// \brief Whether this declaration is private to the module in which it was
|
||||
/// defined.
|
||||
ModulePrivateFlag = 0x02
|
||||
/// The kind of ownership a declaration has, for visibility purposes.
|
||||
/// This enumeration is designed such that higher values represent higher
|
||||
/// levels of name hiding.
|
||||
enum class ModuleOwnershipKind : unsigned {
|
||||
/// This declaration is not owned by a module.
|
||||
Unowned,
|
||||
/// This declaration has an owning module, but is globally visible
|
||||
/// (typically because its owning module is visible and we know that
|
||||
/// modules cannot later become hidden in this compilation).
|
||||
/// After serialization and deserialization, this will be converted
|
||||
/// to VisibleWhenImported.
|
||||
Visible,
|
||||
/// This declaration has an owning module, and is visible when that
|
||||
/// module is imported.
|
||||
VisibleWhenImported,
|
||||
/// This declaration has an owning module, but is only visible to
|
||||
/// lookups that occur within that module.
|
||||
ModulePrivate
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
/// \brief The next declaration within the same lexical
|
||||
/// DeclContext. These pointers form the linked list that is
|
||||
/// traversed via DeclContext's decls_begin()/decls_end().
|
||||
///
|
||||
/// The extra two bits are used for the TopLevelDeclInObjCContainer and
|
||||
/// ModulePrivate bits.
|
||||
llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits;
|
||||
/// The extra two bits are used for the ModuleOwnershipKind.
|
||||
llvm::PointerIntPair<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits;
|
||||
|
||||
private:
|
||||
friend class DeclContext;
|
||||
|
@ -281,6 +289,11 @@ private:
|
|||
/// are regarded as "referenced" but not "used".
|
||||
unsigned Referenced : 1;
|
||||
|
||||
/// \brief Whether this declaration is a top-level declaration (function,
|
||||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
unsigned TopLevelDeclInObjCContainer : 1;
|
||||
|
||||
/// \brief Whether statistic collection is enabled.
|
||||
static bool StatisticsEnabled;
|
||||
|
||||
|
@ -293,11 +306,6 @@ protected:
|
|||
/// \brief Whether this declaration was loaded from an AST file.
|
||||
unsigned FromASTFile : 1;
|
||||
|
||||
/// \brief Whether this declaration is hidden from normal name lookup, e.g.,
|
||||
/// because it is was loaded from an AST file is either module-private or
|
||||
/// because its submodule has not been made visible.
|
||||
unsigned Hidden : 1;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 13;
|
||||
|
||||
|
@ -331,26 +339,38 @@ protected:
|
|||
private:
|
||||
bool AccessDeclContextSanity() const;
|
||||
|
||||
protected:
|
||||
/// Get the module ownership kind to use for a local lexical child of \p DC,
|
||||
/// which may be either a local or (rarely) an imported declaration.
|
||||
static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) {
|
||||
if (DC) {
|
||||
auto *D = cast<Decl>(DC);
|
||||
auto MOK = D->getModuleOwnershipKind();
|
||||
if (MOK != ModuleOwnershipKind::Unowned &&
|
||||
(!D->isFromASTFile() || D->hasLocalOwningModuleStorage()))
|
||||
return MOK;
|
||||
// If D is not local and we have no local module storage, then we don't
|
||||
// need to track module ownership at all.
|
||||
}
|
||||
return ModuleOwnershipKind::Unowned;
|
||||
}
|
||||
|
||||
protected:
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextInContextAndBits(), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), Hidden(DC && cast<Decl>(DC)->Hidden),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0)
|
||||
{
|
||||
: NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
|
||||
DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
|
||||
Implicit(false), Used(false), Referenced(false),
|
||||
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0) {
|
||||
if (StatisticsEnabled) add(DK);
|
||||
}
|
||||
|
||||
Decl(Kind DK, EmptyShell Empty)
|
||||
: NextInContextAndBits(), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0)
|
||||
{
|
||||
: NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
|
||||
Implicit(false), Used(false), Referenced(false),
|
||||
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0) {
|
||||
if (StatisticsEnabled) add(DK);
|
||||
}
|
||||
|
||||
|
@ -550,22 +570,21 @@ public:
|
|||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
bool isTopLevelDeclInObjCContainer() const {
|
||||
return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag;
|
||||
return TopLevelDeclInObjCContainer;
|
||||
}
|
||||
|
||||
void setTopLevelDeclInObjCContainer(bool V = true) {
|
||||
unsigned Bits = NextInContextAndBits.getInt();
|
||||
if (V)
|
||||
Bits |= TopLevelDeclInObjCContainerFlag;
|
||||
else
|
||||
Bits &= ~TopLevelDeclInObjCContainerFlag;
|
||||
NextInContextAndBits.setInt(Bits);
|
||||
TopLevelDeclInObjCContainer = V;
|
||||
}
|
||||
|
||||
/// \brief Looks on this and related declarations for an applicable
|
||||
/// external source symbol attribute.
|
||||
ExternalSourceSymbolAttr *getExternalSourceSymbolAttr() const;
|
||||
|
||||
/// \brief Whether this declaration was marked as being private to the
|
||||
/// module in which it was defined.
|
||||
bool isModulePrivate() const {
|
||||
return NextInContextAndBits.getInt() & ModulePrivateFlag;
|
||||
return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate;
|
||||
}
|
||||
|
||||
/// \brief Whether this declaration is exported (by virtue of being lexically
|
||||
|
@ -580,15 +599,14 @@ public:
|
|||
const Attr *getDefiningAttr() const;
|
||||
|
||||
protected:
|
||||
/// \brief Specify whether this declaration was marked as being private
|
||||
/// \brief Specify that this declaration was marked as being private
|
||||
/// to the module in which it was defined.
|
||||
void setModulePrivate(bool MP = true) {
|
||||
unsigned Bits = NextInContextAndBits.getInt();
|
||||
if (MP)
|
||||
Bits |= ModulePrivateFlag;
|
||||
else
|
||||
Bits &= ~ModulePrivateFlag;
|
||||
NextInContextAndBits.setInt(Bits);
|
||||
void setModulePrivate() {
|
||||
// The module-private specifier has no effect on unowned declarations.
|
||||
// FIXME: We should track this in some way for source fidelity.
|
||||
if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned)
|
||||
return;
|
||||
setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate);
|
||||
}
|
||||
|
||||
/// \brief Set the owning module ID.
|
||||
|
@ -616,6 +634,14 @@ public:
|
|||
getAvailability(std::string *Message = nullptr,
|
||||
VersionTuple EnclosingVersion = VersionTuple()) const;
|
||||
|
||||
/// \brief Retrieve the version of the target platform in which this
|
||||
/// declaration was introduced.
|
||||
///
|
||||
/// \returns An empty version tuple if this declaration has no 'introduced'
|
||||
/// availability attributes, or the version tuple that's specified in the
|
||||
/// attribute otherwise.
|
||||
VersionTuple getVersionIntroduced() const;
|
||||
|
||||
/// \brief Determine whether this declaration is marked 'deprecated'.
|
||||
///
|
||||
/// \param Message If non-NULL and the declaration is deprecated,
|
||||
|
@ -654,20 +680,19 @@ public:
|
|||
/// a precompiled header or module) rather than having been parsed.
|
||||
bool isFromASTFile() const { return FromASTFile; }
|
||||
|
||||
/// \brief Retrieve the global declaration ID associated with this
|
||||
/// declaration, which specifies where in the
|
||||
unsigned getGlobalID() const {
|
||||
/// \brief Retrieve the global declaration ID associated with this
|
||||
/// declaration, which specifies where this Decl was loaded from.
|
||||
unsigned getGlobalID() const {
|
||||
if (isFromASTFile())
|
||||
return *((const unsigned*)this - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the global ID of the module that owns this particular
|
||||
/// declaration.
|
||||
unsigned getOwningModuleID() const {
|
||||
if (isFromASTFile())
|
||||
return *((const unsigned*)this - 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -680,7 +705,7 @@ public:
|
|||
/// \brief Get the imported owning module, if this decl is from an imported
|
||||
/// (non-local) module.
|
||||
Module *getImportedOwningModule() const {
|
||||
if (!isFromASTFile())
|
||||
if (!isFromASTFile() || !hasOwningModule())
|
||||
return nullptr;
|
||||
|
||||
return getOwningModuleSlow();
|
||||
|
@ -689,16 +714,59 @@ public:
|
|||
/// \brief Get the local owning module, if known. Returns nullptr if owner is
|
||||
/// not yet known or declaration is not from a module.
|
||||
Module *getLocalOwningModule() const {
|
||||
if (isFromASTFile() || !Hidden)
|
||||
if (isFromASTFile() || !hasOwningModule())
|
||||
return nullptr;
|
||||
|
||||
assert(hasLocalOwningModuleStorage() &&
|
||||
"owned local decl but no local module storage");
|
||||
return reinterpret_cast<Module *const *>(this)[-1];
|
||||
}
|
||||
void setLocalOwningModule(Module *M) {
|
||||
assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() &&
|
||||
assert(!isFromASTFile() && hasOwningModule() &&
|
||||
hasLocalOwningModuleStorage() &&
|
||||
"should not have a cached owning module");
|
||||
reinterpret_cast<Module **>(this)[-1] = M;
|
||||
}
|
||||
|
||||
/// Is this declaration owned by some module?
|
||||
bool hasOwningModule() const {
|
||||
return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned;
|
||||
}
|
||||
|
||||
/// Get the module that owns this declaration.
|
||||
Module *getOwningModule() const {
|
||||
return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration might be hidden from name
|
||||
/// lookup. Note that the declaration might be visible even if this returns
|
||||
/// \c false, if the owning module is visible within the query context.
|
||||
// FIXME: Rename this to make it clearer what it does.
|
||||
bool isHidden() const {
|
||||
return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible;
|
||||
}
|
||||
|
||||
/// Set that this declaration is globally visible, even if it came from a
|
||||
/// module that is not visible.
|
||||
void setVisibleDespiteOwningModule() {
|
||||
if (isHidden())
|
||||
setModuleOwnershipKind(ModuleOwnershipKind::Visible);
|
||||
}
|
||||
|
||||
/// \brief Get the kind of module ownership for this declaration.
|
||||
ModuleOwnershipKind getModuleOwnershipKind() const {
|
||||
return NextInContextAndBits.getInt();
|
||||
}
|
||||
|
||||
/// \brief Set whether this declaration is hidden from name lookup.
|
||||
void setModuleOwnershipKind(ModuleOwnershipKind MOK) {
|
||||
assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned &&
|
||||
MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() &&
|
||||
!hasLocalOwningModuleStorage()) &&
|
||||
"no storage available for owning module for this declaration");
|
||||
NextInContextAndBits.setInt(MOK);
|
||||
}
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
|
@ -1030,7 +1098,7 @@ public:
|
|||
void dump() const;
|
||||
// Same as dump(), but forces color printing.
|
||||
void dumpColor() const;
|
||||
void dump(raw_ostream &Out) const;
|
||||
void dump(raw_ostream &Out, bool Deserialize = false) const;
|
||||
|
||||
/// \brief Looks through the Decl's underlying type to extract a FunctionType
|
||||
/// when possible. Will return null if the type underlying the Decl does not
|
||||
|
@ -1811,7 +1879,8 @@ public:
|
|||
|
||||
void dumpDeclContext() const;
|
||||
void dumpLookups() const;
|
||||
void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false) const;
|
||||
void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false,
|
||||
bool Deserialize = false) const;
|
||||
|
||||
private:
|
||||
void reconcileExternalVisibleStorage() const;
|
||||
|
|
|
@ -203,6 +203,11 @@ public:
|
|||
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
|
||||
|
||||
/// \brief Get the location at which the base class type was written.
|
||||
SourceLocation getBaseTypeLoc() const LLVM_READONLY {
|
||||
return BaseTypeInfo->getTypeLoc().getLocStart();
|
||||
}
|
||||
|
||||
/// \brief Determines whether the base class is a virtual base class (or not).
|
||||
bool isVirtual() const { return Virtual; }
|
||||
|
||||
|
@ -436,9 +441,10 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// either by the user or implicitly.
|
||||
unsigned DeclaredSpecialMembers : 6;
|
||||
|
||||
/// \brief Whether an implicit copy constructor would have a const-qualified
|
||||
/// parameter.
|
||||
unsigned ImplicitCopyConstructorHasConstParam : 1;
|
||||
/// \brief Whether an implicit copy constructor could have a const-qualified
|
||||
/// parameter, for initializing virtual bases and for other subobjects.
|
||||
unsigned ImplicitCopyConstructorCanHaveConstParamForVBase : 1;
|
||||
unsigned ImplicitCopyConstructorCanHaveConstParamForNonVBase : 1;
|
||||
|
||||
/// \brief Whether an implicit copy assignment operator would have a
|
||||
/// const-qualified parameter.
|
||||
|
@ -458,6 +464,11 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// \brief Whether we are currently parsing base specifiers.
|
||||
unsigned IsParsingBaseSpecifiers : 1;
|
||||
|
||||
unsigned HasODRHash : 1;
|
||||
|
||||
/// \brief A hash of parts of the class to help in ODR checking.
|
||||
unsigned ODRHash;
|
||||
|
||||
/// \brief The number of base class specifiers in Bases.
|
||||
unsigned NumBases;
|
||||
|
||||
|
@ -703,6 +714,8 @@ public:
|
|||
return data().IsParsingBaseSpecifiers;
|
||||
}
|
||||
|
||||
unsigned getODRHash() const;
|
||||
|
||||
/// \brief Sets the base classes of this struct or class.
|
||||
void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
|
||||
|
||||
|
@ -871,7 +884,9 @@ public:
|
|||
/// \brief Determine whether an implicit copy constructor for this type
|
||||
/// would have a parameter with a const-qualified reference type.
|
||||
bool implicitCopyConstructorHasConstParam() const {
|
||||
return data().ImplicitCopyConstructorHasConstParam;
|
||||
return data().ImplicitCopyConstructorCanHaveConstParamForNonVBase &&
|
||||
(isAbstract() ||
|
||||
data().ImplicitCopyConstructorCanHaveConstParamForVBase);
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a copy constructor with
|
||||
|
@ -1548,10 +1563,13 @@ public:
|
|||
/// \param Paths used to record the paths from this class to its base class
|
||||
/// subobjects that match the search criteria.
|
||||
///
|
||||
/// \param LookupInDependent can be set to true to extend the search to
|
||||
/// dependent base classes.
|
||||
///
|
||||
/// \returns true if there exists any path from this class to a base class
|
||||
/// subobject that matches the search criteria.
|
||||
bool lookupInBases(BaseMatchesCallback BaseMatches,
|
||||
CXXBasePaths &Paths) const;
|
||||
bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths,
|
||||
bool LookupInDependent = false) const;
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether the given
|
||||
/// base class specifier refers to a specific class declaration.
|
||||
|
@ -1592,6 +1610,16 @@ public:
|
|||
static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path, DeclarationName Name);
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether there exists
|
||||
/// a member with the given name.
|
||||
///
|
||||
/// This callback can be used with \c lookupInBases() to find members
|
||||
/// of the given name within a C++ class hierarchy, including dependent
|
||||
/// classes.
|
||||
static bool
|
||||
FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path, DeclarationName Name);
|
||||
|
||||
/// \brief Base-class lookup callback that determines whether there exists
|
||||
/// an OpenMP declare reduction member with the given name.
|
||||
///
|
||||
|
@ -1618,6 +1646,14 @@ public:
|
|||
/// \brief Get the indirect primary bases for this class.
|
||||
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const;
|
||||
|
||||
/// Performs an imprecise lookup of a dependent name in this class.
|
||||
///
|
||||
/// This function does not follow strict semantic rules and should be used
|
||||
/// only when lookup rules can be relaxed, e.g. indexing.
|
||||
std::vector<const NamedDecl *>
|
||||
lookupDependentName(const DeclarationName &Name,
|
||||
llvm::function_ref<bool(const NamedDecl *ND)> Filter);
|
||||
|
||||
/// Renders and displays an inheritance diagram
|
||||
/// for this C++ class and all of its base classes (transitively) using
|
||||
/// GraphViz.
|
||||
|
@ -1738,6 +1774,58 @@ public:
|
|||
friend class ASTWriter;
|
||||
};
|
||||
|
||||
/// \brief Represents a C++ deduction guide declaration.
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T> struct A { A(); A(T); };
|
||||
/// A() -> A<int>;
|
||||
/// \endcode
|
||||
///
|
||||
/// In this example, there will be an explicit deduction guide from the
|
||||
/// second line, and implicit deduction guide templates synthesized from
|
||||
/// the constructors of \c A.
|
||||
class CXXDeductionGuideDecl : public FunctionDecl {
|
||||
void anchor() override;
|
||||
private:
|
||||
CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
|
||||
bool IsExplicit, const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
SourceLocation EndLocation)
|
||||
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, false, false) {
|
||||
if (EndLocation.isValid())
|
||||
setRangeEnd(EndLocation);
|
||||
IsExplicitSpecified = IsExplicit;
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXDeductionGuideDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, bool IsExplicit,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
SourceLocation EndLocation);
|
||||
|
||||
static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
/// Whether this deduction guide is explicit.
|
||||
bool isExplicit() const { return IsExplicitSpecified; }
|
||||
|
||||
/// Whether this deduction guide was declared with the 'explicit' specifier.
|
||||
bool isExplicitSpecified() const { return IsExplicitSpecified; }
|
||||
|
||||
/// Get the template for which this guide performs deduction.
|
||||
TemplateDecl *getDeducedTemplate() const {
|
||||
return getDeclName().getCXXDeductionGuideTemplate();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == CXXDeductionGuide; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// \brief Represents a static or instance method of a struct/union/class.
|
||||
///
|
||||
/// In the terminology of the C++ Standard, these are the (static and
|
||||
|
@ -1798,6 +1886,19 @@ public:
|
|||
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
|
||||
}
|
||||
|
||||
/// If it's possible to devirtualize a call to this method, return the called
|
||||
/// function. Otherwise, return null.
|
||||
|
||||
/// \param Base The object on which this virtual function is called.
|
||||
/// \param IsAppleKext True if we are compiling for Apple kext.
|
||||
CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, bool IsAppleKext);
|
||||
|
||||
const CXXMethodDecl *getDevirtualizedMethod(const Expr *Base,
|
||||
bool IsAppleKext) const {
|
||||
return const_cast<CXXMethodDecl *>(this)->getDevirtualizedMethod(
|
||||
Base, IsAppleKext);
|
||||
}
|
||||
|
||||
/// \brief Determine whether this is a usual deallocation function
|
||||
/// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
|
||||
/// delete or delete[] operator with a particular signature.
|
||||
|
@ -2161,13 +2262,9 @@ class CXXConstructorDecl final
|
|||
/// \{
|
||||
/// \brief The arguments used to initialize the base or member.
|
||||
LazyCXXCtorInitializersPtr CtorInitializers;
|
||||
unsigned NumCtorInitializers : 30;
|
||||
unsigned NumCtorInitializers : 31;
|
||||
/// \}
|
||||
|
||||
/// \brief Whether this constructor declaration has the \c explicit keyword
|
||||
/// specified.
|
||||
unsigned IsExplicitSpecified : 1;
|
||||
|
||||
/// \brief Whether this constructor declaration is an implicitly-declared
|
||||
/// inheriting constructor.
|
||||
unsigned IsInheritingConstructor : 1;
|
||||
|
@ -2181,11 +2278,11 @@ class CXXConstructorDecl final
|
|||
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, isInline, isConstexpr, SourceLocation()),
|
||||
CtorInitializers(nullptr), NumCtorInitializers(0),
|
||||
IsExplicitSpecified(isExplicitSpecified),
|
||||
IsInheritingConstructor((bool)Inherited) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
if (Inherited)
|
||||
*getTrailingObjects<InheritedConstructor>() = Inherited;
|
||||
IsExplicitSpecified = isExplicitSpecified;
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -2198,15 +2295,6 @@ public:
|
|||
bool isConstexpr,
|
||||
InheritedConstructor Inherited = InheritedConstructor());
|
||||
|
||||
/// \brief Determine whether this constructor declaration has the
|
||||
/// \c explicit keyword specified.
|
||||
bool isExplicitSpecified() const { return IsExplicitSpecified; }
|
||||
|
||||
/// \brief Determine whether this constructor was marked "explicit" or not.
|
||||
bool isExplicit() const {
|
||||
return cast<CXXConstructorDecl>(getFirstDecl())->isExplicitSpecified();
|
||||
}
|
||||
|
||||
/// \brief Iterates through the member/base initializer list.
|
||||
typedef CXXCtorInitializer **init_iterator;
|
||||
|
||||
|
@ -2270,6 +2358,14 @@ public:
|
|||
CtorInitializers = Initializers;
|
||||
}
|
||||
|
||||
/// Whether this function is marked as explicit explicitly.
|
||||
bool isExplicitSpecified() const { return IsExplicitSpecified; }
|
||||
|
||||
/// Whether this function is explicit.
|
||||
bool isExplicit() const {
|
||||
return getCanonicalDecl()->isExplicitSpecified();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this constructor is a delegating constructor.
|
||||
bool isDelegatingConstructor() const {
|
||||
return (getNumCtorInitializers() == 1) &&
|
||||
|
@ -2405,7 +2501,14 @@ public:
|
|||
|
||||
void setOperatorDelete(FunctionDecl *OD);
|
||||
const FunctionDecl *getOperatorDelete() const {
|
||||
return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete;
|
||||
return getCanonicalDecl()->OperatorDelete;
|
||||
}
|
||||
|
||||
CXXDestructorDecl *getCanonicalDecl() override {
|
||||
return cast<CXXDestructorDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
const CXXDestructorDecl *getCanonicalDecl() const {
|
||||
return const_cast<CXXDestructorDecl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
@ -2428,19 +2531,16 @@ public:
|
|||
/// \endcode
|
||||
class CXXConversionDecl : public CXXMethodDecl {
|
||||
void anchor() override;
|
||||
/// Whether this conversion function declaration is marked
|
||||
/// "explicit", meaning that it can only be applied when the user
|
||||
/// explicitly wrote a cast. This is a C++11 feature.
|
||||
bool IsExplicitSpecified : 1;
|
||||
|
||||
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isInline, bool isExplicitSpecified,
|
||||
bool isConstexpr, SourceLocation EndLocation)
|
||||
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, isInline, isConstexpr, EndLocation),
|
||||
IsExplicitSpecified(isExplicitSpecified) { }
|
||||
const DeclarationNameInfo &NameInfo, QualType T,
|
||||
TypeSourceInfo *TInfo, bool isInline,
|
||||
bool isExplicitSpecified, bool isConstexpr,
|
||||
SourceLocation EndLocation)
|
||||
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, isInline, isConstexpr, EndLocation) {
|
||||
IsExplicitSpecified = isExplicitSpecified;
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
|
@ -2452,17 +2552,12 @@ public:
|
|||
SourceLocation EndLocation);
|
||||
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
/// Whether this conversion function declaration is marked
|
||||
/// "explicit", meaning that it can only be used for direct initialization
|
||||
/// (including explitly written casts). This is a C++11 feature.
|
||||
/// Whether this function is marked as explicit explicitly.
|
||||
bool isExplicitSpecified() const { return IsExplicitSpecified; }
|
||||
|
||||
/// \brief Whether this is an explicit conversion operator (C++11 and later).
|
||||
///
|
||||
/// Explicit conversion operators are only considered for direct
|
||||
/// initialization, e.g., when the user has explicitly written a cast.
|
||||
/// Whether this function is explicit.
|
||||
bool isExplicit() const {
|
||||
return cast<CXXConversionDecl>(getFirstDecl())->isExplicitSpecified();
|
||||
return getCanonicalDecl()->isExplicitSpecified();
|
||||
}
|
||||
|
||||
/// \brief Returns the type that this conversion function is converting to.
|
||||
|
@ -2474,6 +2569,13 @@ public:
|
|||
/// a lambda closure type to a block pointer.
|
||||
bool isLambdaToBlockPointerConversion() const;
|
||||
|
||||
CXXConversionDecl *getCanonicalDecl() override {
|
||||
return cast<CXXConversionDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
const CXXConversionDecl *getCanonicalDecl() const {
|
||||
return const_cast<CXXConversionDecl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == CXXConversion; }
|
||||
|
|
|
@ -131,7 +131,7 @@ public:
|
|||
} else {
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
|
||||
std::mem_fun(&Decl::isFromASTFile)),
|
||||
[](Decl *D) { return D->isFromASTFile(); }),
|
||||
Vec.end());
|
||||
// Don't have any external decls any more.
|
||||
Data = DeclsAndHasExternalTy(&Vec, false);
|
||||
|
|
|
@ -381,15 +381,17 @@ public:
|
|||
ArrayRef<SourceLocation> SelLocs = llvm::None);
|
||||
|
||||
// Iterator access to parameter types.
|
||||
typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun;
|
||||
typedef llvm::mapped_iterator<param_const_iterator, deref_fun>
|
||||
param_type_iterator;
|
||||
struct GetTypeFn {
|
||||
QualType operator()(const ParmVarDecl *PD) const { return PD->getType(); }
|
||||
};
|
||||
typedef llvm::mapped_iterator<param_const_iterator, GetTypeFn>
|
||||
param_type_iterator;
|
||||
|
||||
param_type_iterator param_type_begin() const {
|
||||
return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType));
|
||||
return llvm::map_iterator(param_begin(), GetTypeFn());
|
||||
}
|
||||
param_type_iterator param_type_end() const {
|
||||
return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType));
|
||||
return llvm::map_iterator(param_end(), GetTypeFn());
|
||||
}
|
||||
|
||||
/// createImplicitParams - Used to lazily create the self and cmd
|
||||
|
@ -743,6 +745,8 @@ private:
|
|||
|
||||
Selector GetterName; // getter name of NULL if no getter
|
||||
Selector SetterName; // setter name of NULL if no setter
|
||||
SourceLocation GetterNameLoc; // location of the getter attribute's value
|
||||
SourceLocation SetterNameLoc; // location of the setter attribute's value
|
||||
|
||||
ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method
|
||||
ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method
|
||||
|
@ -855,10 +859,18 @@ public:
|
|||
}
|
||||
|
||||
Selector getGetterName() const { return GetterName; }
|
||||
void setGetterName(Selector Sel) { GetterName = Sel; }
|
||||
SourceLocation getGetterNameLoc() const { return GetterNameLoc; }
|
||||
void setGetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
|
||||
GetterName = Sel;
|
||||
GetterNameLoc = Loc;
|
||||
}
|
||||
|
||||
Selector getSetterName() const { return SetterName; }
|
||||
void setSetterName(Selector Sel) { SetterName = Sel; }
|
||||
SourceLocation getSetterNameLoc() const { return SetterNameLoc; }
|
||||
void setSetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
|
||||
SetterName = Sel;
|
||||
SetterNameLoc = Loc;
|
||||
}
|
||||
|
||||
ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
|
||||
void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; }
|
||||
|
@ -1027,10 +1039,9 @@ public:
|
|||
typedef llvm::DenseMap<std::pair<IdentifierInfo*,
|
||||
unsigned/*isClassProperty*/>,
|
||||
ObjCPropertyDecl*> PropertyMap;
|
||||
|
||||
typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
|
||||
ProtocolPropertyMap;
|
||||
|
||||
|
||||
typedef llvm::SmallDenseSet<const ObjCProtocolDecl *, 8> ProtocolPropertySet;
|
||||
|
||||
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
|
||||
|
||||
/// This routine collects list of properties to be implemented in the class.
|
||||
|
@ -2147,7 +2158,8 @@ public:
|
|||
PropertyDeclOrder &PO) const override;
|
||||
|
||||
void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
|
||||
ProtocolPropertyMap &PM) const;
|
||||
ProtocolPropertySet &PS,
|
||||
PropertyDeclOrder &PO) const;
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ObjCProtocol; }
|
||||
|
@ -2320,11 +2332,9 @@ class ObjCImplDecl : public ObjCContainerDecl {
|
|||
protected:
|
||||
ObjCImplDecl(Kind DK, DeclContext *DC,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
IdentifierInfo *Id,
|
||||
SourceLocation nameLoc, SourceLocation atStartLoc)
|
||||
: ObjCContainerDecl(DK, DC,
|
||||
classInterface? classInterface->getIdentifier()
|
||||
: nullptr,
|
||||
nameLoc, atStartLoc),
|
||||
: ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc),
|
||||
ClassInterface(classInterface) {}
|
||||
|
||||
public:
|
||||
|
@ -2386,9 +2396,6 @@ public:
|
|||
class ObjCCategoryImplDecl : public ObjCImplDecl {
|
||||
void anchor() override;
|
||||
|
||||
// Category name
|
||||
IdentifierInfo *Id;
|
||||
|
||||
// Category name location
|
||||
SourceLocation CategoryNameLoc;
|
||||
|
||||
|
@ -2396,8 +2403,9 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
|
|||
ObjCInterfaceDecl *classInterface,
|
||||
SourceLocation nameLoc, SourceLocation atStartLoc,
|
||||
SourceLocation CategoryNameLoc)
|
||||
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc),
|
||||
Id(Id), CategoryNameLoc(CategoryNameLoc) {}
|
||||
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id,
|
||||
nameLoc, atStartLoc),
|
||||
CategoryNameLoc(CategoryNameLoc) {}
|
||||
public:
|
||||
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
IdentifierInfo *Id,
|
||||
|
@ -2407,37 +2415,10 @@ public:
|
|||
SourceLocation CategoryNameLoc);
|
||||
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
/// getIdentifier - Get the identifier that names the category
|
||||
/// interface associated with this implementation.
|
||||
/// FIXME: This is a bad API, we are hiding NamedDecl::getIdentifier()
|
||||
/// with a different meaning. For example:
|
||||
/// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier()
|
||||
/// returns the class interface name, whereas
|
||||
/// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier()
|
||||
/// returns the category name.
|
||||
IdentifierInfo *getIdentifier() const {
|
||||
return Id;
|
||||
}
|
||||
void setIdentifier(IdentifierInfo *II) { Id = II; }
|
||||
|
||||
ObjCCategoryDecl *getCategoryDecl() const;
|
||||
|
||||
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
|
||||
|
||||
/// getName - Get the name of identifier for the class interface associated
|
||||
/// with this implementation as a StringRef.
|
||||
//
|
||||
// FIXME: This is a bad API, we are hiding NamedDecl::getName with a different
|
||||
// meaning.
|
||||
StringRef getName() const { return Id ? Id->getName() : StringRef(); }
|
||||
|
||||
/// @brief Get the name of the class associated with this interface.
|
||||
//
|
||||
// FIXME: Deprecated, move clients to getName().
|
||||
std::string getNameAsString() const {
|
||||
return getName();
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
|
||||
|
||||
|
@ -2493,7 +2474,10 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
|||
SourceLocation superLoc = SourceLocation(),
|
||||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||
SourceLocation IvarRBraceLoc=SourceLocation())
|
||||
: ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc),
|
||||
: ObjCImplDecl(ObjCImplementation, DC, classInterface,
|
||||
classInterface ? classInterface->getIdentifier()
|
||||
: nullptr,
|
||||
nameLoc, atStartLoc),
|
||||
SuperClass(superDecl), SuperLoc(superLoc), IvarLBraceLoc(IvarLBraceLoc),
|
||||
IvarRBraceLoc(IvarRBraceLoc),
|
||||
IvarInitializers(nullptr), NumIvarInitializers(0),
|
||||
|
|
|
@ -344,6 +344,32 @@ public:
|
|||
// Kinds of Templates
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Stores the template parameter list and associated constraints for
|
||||
/// \c TemplateDecl objects that track associated constraints.
|
||||
class ConstrainedTemplateDeclInfo {
|
||||
friend TemplateDecl;
|
||||
|
||||
public:
|
||||
ConstrainedTemplateDeclInfo() : TemplateParams(), AssociatedConstraints() {}
|
||||
|
||||
TemplateParameterList *getTemplateParameters() const {
|
||||
return TemplateParams;
|
||||
}
|
||||
|
||||
Expr *getAssociatedConstraints() const { return AssociatedConstraints; }
|
||||
|
||||
protected:
|
||||
void setTemplateParameters(TemplateParameterList *TParams) {
|
||||
TemplateParams = TParams;
|
||||
}
|
||||
|
||||
void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; }
|
||||
|
||||
TemplateParameterList *TemplateParams;
|
||||
Expr *AssociatedConstraints;
|
||||
};
|
||||
|
||||
|
||||
/// \brief The base class of all kinds of template declarations (e.g.,
|
||||
/// class, function, etc.).
|
||||
///
|
||||
|
@ -352,33 +378,53 @@ public:
|
|||
class TemplateDecl : public NamedDecl {
|
||||
void anchor() override;
|
||||
protected:
|
||||
// This is probably never used.
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
|
||||
TemplateParams(nullptr) {}
|
||||
|
||||
// Construct a template decl with the given name and parameters.
|
||||
// Used when there is not templated element (tt-params).
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
// Used when there is no templated element (e.g., for tt-params).
|
||||
TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
|
||||
SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
|
||||
TemplateParams(Params) {}
|
||||
TemplateParams(CTDI) {
|
||||
this->setTemplateParameters(Params);
|
||||
}
|
||||
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params)
|
||||
: TemplateDecl(nullptr, DK, DC, L, Name, Params) {}
|
||||
|
||||
// Construct a template decl with name, parameters, and templated element.
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
|
||||
SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false),
|
||||
TemplateParams(Params) {}
|
||||
TemplateParams(CTDI) {
|
||||
this->setTemplateParameters(Params);
|
||||
}
|
||||
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: TemplateDecl(nullptr, DK, DC, L, Name, Params, Decl) {}
|
||||
|
||||
public:
|
||||
/// Get the list of template parameters
|
||||
TemplateParameterList *getTemplateParameters() const {
|
||||
return TemplateParams;
|
||||
const auto *const CTDI =
|
||||
TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
|
||||
return CTDI ? CTDI->getTemplateParameters()
|
||||
: TemplateParams.get<TemplateParameterList *>();
|
||||
}
|
||||
|
||||
/// Get the constraint-expression from the associated requires-clause (if any)
|
||||
const Expr *getRequiresClause() const {
|
||||
return TemplateParams ? TemplateParams->getRequiresClause() : nullptr;
|
||||
const TemplateParameterList *const TP = getTemplateParameters();
|
||||
return TP ? TP->getRequiresClause() : nullptr;
|
||||
}
|
||||
|
||||
Expr *getAssociatedConstraints() const {
|
||||
const TemplateDecl *const C = cast<TemplateDecl>(getCanonicalDecl());
|
||||
const auto *const CTDI =
|
||||
C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
|
||||
return CTDI ? CTDI->getAssociatedConstraints() : nullptr;
|
||||
}
|
||||
|
||||
/// Get the underlying, templated declaration.
|
||||
|
@ -391,7 +437,7 @@ public:
|
|||
}
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(TemplateParams->getTemplateLoc(),
|
||||
return SourceRange(getTemplateParameters()->getTemplateLoc(),
|
||||
TemplatedDecl.getPointer()->getSourceRange().getEnd());
|
||||
}
|
||||
|
||||
|
@ -407,7 +453,29 @@ protected:
|
|||
/// (function or variable) is a concept.
|
||||
llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl;
|
||||
|
||||
TemplateParameterList* TemplateParams;
|
||||
/// \brief The template parameter list and optional requires-clause
|
||||
/// associated with this declaration; alternatively, a
|
||||
/// \c ConstrainedTemplateDeclInfo if the associated constraints of the
|
||||
/// template are being tracked by this particular declaration.
|
||||
llvm::PointerUnion<TemplateParameterList *,
|
||||
ConstrainedTemplateDeclInfo *>
|
||||
TemplateParams;
|
||||
|
||||
void setTemplateParameters(TemplateParameterList *TParams) {
|
||||
if (auto *const CTDI =
|
||||
TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>()) {
|
||||
CTDI->setTemplateParameters(TParams);
|
||||
} else {
|
||||
TemplateParams = TParams;
|
||||
}
|
||||
}
|
||||
|
||||
void setAssociatedConstraints(Expr *AC) {
|
||||
assert(isCanonicalDecl() &&
|
||||
"Attaching associated constraints to non-canonical Decl");
|
||||
TemplateParams.get<ConstrainedTemplateDeclInfo *>()
|
||||
->setAssociatedConstraints(AC);
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Initialize the underlying templated declaration and
|
||||
|
@ -737,11 +805,17 @@ protected:
|
|||
virtual CommonBase *newCommon(ASTContext &C) const = 0;
|
||||
|
||||
// Construct a template decl with name, parameters, and templated element.
|
||||
RedeclarableTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK,
|
||||
ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params,
|
||||
NamedDecl *Decl)
|
||||
: TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C),
|
||||
Common() {}
|
||||
|
||||
RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C),
|
||||
Common() {}
|
||||
: RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {}
|
||||
|
||||
public:
|
||||
template <class decl_type> friend class RedeclarableTemplate;
|
||||
|
@ -863,8 +937,6 @@ SpecEntryTraits<FunctionTemplateSpecializationInfo> {
|
|||
|
||||
/// Declaration of a template function.
|
||||
class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
static void DeallocateCommon(void *Ptr);
|
||||
|
||||
protected:
|
||||
/// \brief Data that is common to all of the declarations of a given
|
||||
/// function template.
|
||||
|
@ -1407,7 +1479,9 @@ public:
|
|||
unsigned NumExpansions);
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::setDepth;
|
||||
using TemplateParmPosition::getPosition;
|
||||
using TemplateParmPosition::setPosition;
|
||||
using TemplateParmPosition::getIndex;
|
||||
|
||||
/// \brief Whether this template template parameter is a template
|
||||
|
@ -1960,8 +2034,6 @@ public:
|
|||
|
||||
/// Declaration of a class template.
|
||||
class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
static void DeallocateCommon(void *Ptr);
|
||||
|
||||
protected:
|
||||
/// \brief Data that is common to all of the declarations of a given
|
||||
/// class template.
|
||||
|
@ -1997,10 +2069,16 @@ protected:
|
|||
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
|
||||
getPartialSpecializations();
|
||||
|
||||
ClassTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, ASTContext &C,
|
||||
DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(CTDI, ClassTemplate, C, DC, L, Name, Params,
|
||||
Decl) {}
|
||||
|
||||
ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params,
|
||||
NamedDecl *Decl)
|
||||
: RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
|
||||
: ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {}
|
||||
|
||||
CommonBase *newCommon(ASTContext &C) const override;
|
||||
|
||||
|
@ -2023,12 +2101,14 @@ public:
|
|||
return getTemplatedDecl()->isThisDeclarationADefinition();
|
||||
}
|
||||
|
||||
// FIXME: remove default argument for AssociatedConstraints
|
||||
/// \brief Create a class template node.
|
||||
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
DeclarationName Name,
|
||||
TemplateParameterList *Params,
|
||||
NamedDecl *Decl);
|
||||
NamedDecl *Decl,
|
||||
Expr *AssociatedConstraints = nullptr);
|
||||
|
||||
/// \brief Create an empty class template node.
|
||||
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
@ -2247,8 +2327,6 @@ public:
|
|||
/// template \<typename T> using V = std::map<T*, int, MyCompare<T>>;
|
||||
/// \endcode
|
||||
class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
static void DeallocateCommon(void *Ptr);
|
||||
|
||||
protected:
|
||||
typedef CommonBase Common;
|
||||
|
||||
|
@ -2773,8 +2851,6 @@ public:
|
|||
|
||||
/// 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.
|
||||
|
@ -2946,6 +3022,16 @@ inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
|
|||
return P.get<TemplateTemplateParmDecl*>();
|
||||
}
|
||||
|
||||
inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
|
||||
auto *TD = dyn_cast<TemplateDecl>(D);
|
||||
return TD && (isa<ClassTemplateDecl>(TD) ||
|
||||
isa<ClassTemplatePartialSpecializationDecl>(TD) ||
|
||||
isa<TypeAliasTemplateDecl>(TD) ||
|
||||
isa<TemplateTemplateParmDecl>(TD))
|
||||
? TD
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
} /* end of namespace clang */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace llvm {
|
|||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class CXXDeductionGuideNameExtra;
|
||||
class CXXLiteralOperatorIdName;
|
||||
class CXXOperatorIdName;
|
||||
class CXXSpecialName;
|
||||
|
@ -32,6 +33,7 @@ namespace clang {
|
|||
enum OverloadedOperatorKind : int;
|
||||
struct PrintingPolicy;
|
||||
class QualType;
|
||||
class TemplateDecl;
|
||||
class Type;
|
||||
class TypeSourceInfo;
|
||||
class UsingDirectiveDecl;
|
||||
|
@ -56,6 +58,7 @@ public:
|
|||
CXXConstructorName,
|
||||
CXXDestructorName,
|
||||
CXXConversionFunctionName,
|
||||
CXXDeductionGuideName,
|
||||
CXXOperatorName,
|
||||
CXXLiteralOperatorName,
|
||||
CXXUsingDirective
|
||||
|
@ -118,42 +121,36 @@ private:
|
|||
CXXSpecialName *getAsCXXSpecialName() const {
|
||||
NameKind Kind = getNameKind();
|
||||
if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
|
||||
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
|
||||
return reinterpret_cast<CXXSpecialName *>(getExtra());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// If the stored pointer is actually a CXXDeductionGuideNameExtra, returns a
|
||||
/// pointer to it. Otherwise, returns a NULL pointer.
|
||||
CXXDeductionGuideNameExtra *getAsCXXDeductionGuideNameExtra() const {
|
||||
if (getNameKind() == CXXDeductionGuideName)
|
||||
return reinterpret_cast<CXXDeductionGuideNameExtra *>(getExtra());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getAsCXXOperatorIdName
|
||||
CXXOperatorIdName *getAsCXXOperatorIdName() const {
|
||||
if (getNameKind() == CXXOperatorName)
|
||||
return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
|
||||
return reinterpret_cast<CXXOperatorIdName *>(getExtra());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const {
|
||||
if (getNameKind() == CXXLiteralOperatorName)
|
||||
return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask);
|
||||
return reinterpret_cast<CXXLiteralOperatorIdName *>(getExtra());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ constructor,
|
||||
// destructor, or conversion function.
|
||||
DeclarationName(CXXSpecialName *Name)
|
||||
DeclarationName(DeclarationNameExtra *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ overloaded
|
||||
// operator.
|
||||
DeclarationName(CXXOperatorIdName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
DeclarationName(CXXLiteralOperatorIdName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId");
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
|
@ -252,6 +249,10 @@ public:
|
|||
/// type associated with that name.
|
||||
QualType getCXXNameType() const;
|
||||
|
||||
/// If this name is the name of a C++ deduction guide, return the
|
||||
/// template associated with that name.
|
||||
TemplateDecl *getCXXDeductionGuideTemplate() const;
|
||||
|
||||
/// getCXXOverloadedOperator - If this name is the name of an
|
||||
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
|
||||
/// kind of overloaded operator.
|
||||
|
@ -346,6 +347,7 @@ class DeclarationNameTable {
|
|||
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
|
||||
void *CXXDeductionGuideNames; // FoldingSet<CXXDeductionGuideNameExtra> *
|
||||
|
||||
DeclarationNameTable(const DeclarationNameTable&) = delete;
|
||||
void operator=(const DeclarationNameTable&) = delete;
|
||||
|
@ -368,6 +370,9 @@ public:
|
|||
/// for the given Type.
|
||||
DeclarationName getCXXDestructorName(CanQualType Ty);
|
||||
|
||||
/// Returns the name of a C++ deduction guide for the given template.
|
||||
DeclarationName getCXXDeductionGuideName(TemplateDecl *TD);
|
||||
|
||||
/// getCXXConversionFunctionName - Returns the name of a C++
|
||||
/// conversion function for the given Type.
|
||||
DeclarationName getCXXConversionFunctionName(CanQualType Ty);
|
||||
|
|
|
@ -115,6 +115,7 @@ protected:
|
|||
ExprBits.InstantiationDependent = ID;
|
||||
ExprBits.ValueKind = VK;
|
||||
ExprBits.ObjectKind = OK;
|
||||
assert(ExprBits.ObjectKind == OK && "truncated kind");
|
||||
ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
|
||||
setType(T);
|
||||
}
|
||||
|
@ -907,6 +908,10 @@ public:
|
|||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
/// The source expression of an opaque value expression is the
|
||||
/// expression which originally generated the value. This is
|
||||
/// provided as a convenience for analyses that don't wish to
|
||||
|
@ -1167,6 +1172,10 @@ public:
|
|||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
friend TrailingObjects;
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
|
@ -1222,6 +1231,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&FnName, &FnName + 1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&FnName, &FnName + 1);
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
@ -1315,6 +1327,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
class CharacterLiteral : public Expr {
|
||||
|
@ -1365,6 +1380,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
class FloatingLiteral : public Expr, private APFloatStorage {
|
||||
|
@ -1429,6 +1447,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// ImaginaryLiteral - We support imaginary integer and floating point literals,
|
||||
|
@ -1461,6 +1482,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Val, &Val + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// StringLiteral - This represents a string literal expression, e.g. "foo"
|
||||
|
@ -1628,6 +1652,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
|
||||
|
@ -1669,6 +1696,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Val, &Val + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// UnaryOperator - This represents the unary-expression's (except sizeof and
|
||||
|
@ -1778,6 +1808,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Val, &Val + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// Helper class for OffsetOfExpr.
|
||||
|
@ -1981,6 +2014,11 @@ public:
|
|||
Stmt **begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
|
||||
return child_range(begin, begin + NumExprs);
|
||||
}
|
||||
const_child_range children() const {
|
||||
Stmt *const *begin =
|
||||
reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
|
||||
return const_child_range(begin, begin + NumExprs);
|
||||
}
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
||||
|
@ -2069,6 +2107,7 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children();
|
||||
const_child_range children() const;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -2153,6 +2192,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
|
||||
}
|
||||
};
|
||||
|
||||
/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
|
||||
|
@ -2313,6 +2355,11 @@ public:
|
|||
return child_range(&SubExprs[0],
|
||||
&SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START);
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SubExprs[0], &SubExprs[0] + NumArgs +
|
||||
getNumPreArgs() + PREARGS_START);
|
||||
}
|
||||
};
|
||||
|
||||
/// Extra data stored in some MemberExpr objects.
|
||||
|
@ -2567,6 +2614,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Base, &Base + 1);
|
||||
}
|
||||
|
||||
friend TrailingObjects;
|
||||
friend class ASTReader;
|
||||
|
@ -2639,6 +2689,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Init, &Init+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Init, &Init + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// CastExpr - Base class for type casts, including both implicit
|
||||
|
@ -2725,6 +2778,7 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Op, &Op+1); }
|
||||
const_child_range children() const { return const_child_range(&Op, &Op + 1); }
|
||||
};
|
||||
|
||||
/// ImplicitCastExpr - Allows us to explicitly represent implicit type
|
||||
|
@ -2917,11 +2971,9 @@ public:
|
|||
private:
|
||||
unsigned Opc : 6;
|
||||
|
||||
// Records the FP_CONTRACT pragma status at the point that this binary
|
||||
// operator was parsed. This bit is only meaningful for operations on
|
||||
// floating point types. For all other types it should default to
|
||||
// false.
|
||||
unsigned FPContractable : 1;
|
||||
// This is only meaningful for operations on floating point types and 0
|
||||
// otherwise.
|
||||
unsigned FPFeatures : 2;
|
||||
SourceLocation OpLoc;
|
||||
|
||||
enum { LHS, RHS, END_EXPR };
|
||||
|
@ -2930,7 +2982,7 @@ public:
|
|||
|
||||
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation opLoc, bool fpContractable)
|
||||
SourceLocation opLoc, FPOptions FPFeatures)
|
||||
: Expr(BinaryOperatorClass, ResTy, VK, OK,
|
||||
lhs->isTypeDependent() || rhs->isTypeDependent(),
|
||||
lhs->isValueDependent() || rhs->isValueDependent(),
|
||||
|
@ -2938,7 +2990,7 @@ public:
|
|||
rhs->isInstantiationDependent()),
|
||||
(lhs->containsUnexpandedParameterPack() ||
|
||||
rhs->containsUnexpandedParameterPack())),
|
||||
Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
|
||||
Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
|
||||
SubExprs[LHS] = lhs;
|
||||
SubExprs[RHS] = rhs;
|
||||
assert(!isCompoundAssignmentOp() &&
|
||||
|
@ -3070,19 +3122,26 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
|
||||
}
|
||||
|
||||
// Set the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
void setFPContractable(bool FPC) { FPContractable = FPC; }
|
||||
void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); }
|
||||
|
||||
FPOptions getFPFeatures() const { return FPOptions(FPFeatures); }
|
||||
|
||||
// Get the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
bool isFPContractable() const { return FPContractable; }
|
||||
bool isFPContractableWithinStatement() const {
|
||||
return FPOptions(FPFeatures).allowFPContractWithinStatement();
|
||||
}
|
||||
|
||||
protected:
|
||||
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation opLoc, bool fpContractable, bool dead2)
|
||||
SourceLocation opLoc, FPOptions FPFeatures, bool dead2)
|
||||
: Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
|
||||
lhs->isTypeDependent() || rhs->isTypeDependent(),
|
||||
lhs->isValueDependent() || rhs->isValueDependent(),
|
||||
|
@ -3090,7 +3149,7 @@ protected:
|
|||
rhs->isInstantiationDependent()),
|
||||
(lhs->containsUnexpandedParameterPack() ||
|
||||
rhs->containsUnexpandedParameterPack())),
|
||||
Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
|
||||
Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
|
||||
SubExprs[LHS] = lhs;
|
||||
SubExprs[RHS] = rhs;
|
||||
}
|
||||
|
@ -3112,8 +3171,8 @@ public:
|
|||
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
QualType CompLHSType, QualType CompResultType,
|
||||
SourceLocation OpLoc, bool fpContractable)
|
||||
: BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
|
||||
SourceLocation OpLoc, FPOptions FPFeatures)
|
||||
: BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures,
|
||||
true),
|
||||
ComputationLHSType(CompLHSType),
|
||||
ComputationResultType(CompResultType) {
|
||||
|
@ -3246,6 +3305,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
|
||||
}
|
||||
};
|
||||
|
||||
/// BinaryConditionalOperator - The GNU extension to the conditional
|
||||
|
@ -3331,6 +3393,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(SubExprs, SubExprs + NUM_SUBEXPRS);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(SubExprs, SubExprs + NUM_SUBEXPRS);
|
||||
}
|
||||
};
|
||||
|
||||
inline Expr *AbstractConditionalOperator::getCond() const {
|
||||
|
@ -3385,6 +3450,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
|
||||
|
@ -3427,6 +3495,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SubStmt, &SubStmt + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// ShuffleVectorExpr - clang-specific builtin-in function
|
||||
|
@ -3495,6 +3566,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+NumExprs);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SubExprs[0], &SubExprs[0] + NumExprs);
|
||||
}
|
||||
};
|
||||
|
||||
/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
|
||||
|
@ -3549,6 +3623,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SrcExpr, &SrcExpr + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
|
||||
|
@ -3629,6 +3706,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
|
||||
}
|
||||
};
|
||||
|
||||
/// GNUNullExpr - Implements the GNU __null extension, which is a name
|
||||
|
@ -3665,6 +3745,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a call to the builtin function \c __builtin_va_arg.
|
||||
|
@ -3712,6 +3795,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Val, &Val + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Describes an C or C++ initializer list.
|
||||
|
@ -3936,10 +4022,16 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
const_child_range CCR = const_cast<const InitListExpr *>(this)->children();
|
||||
return child_range(cast_away_const(CCR.begin()),
|
||||
cast_away_const(CCR.end()));
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
// FIXME: This does not include the array filler expression.
|
||||
if (InitExprs.empty())
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
return const_child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
|
||||
}
|
||||
|
||||
typedef InitExprsTy::iterator iterator;
|
||||
|
@ -4192,6 +4284,9 @@ public:
|
|||
}
|
||||
|
||||
Designator *getDesignator(unsigned Idx) { return &designators()[Idx]; }
|
||||
const Designator *getDesignator(unsigned Idx) const {
|
||||
return &designators()[Idx];
|
||||
}
|
||||
|
||||
void setDesignators(const ASTContext &C, const Designator *Desigs,
|
||||
unsigned NumDesigs);
|
||||
|
@ -4254,6 +4349,10 @@ public:
|
|||
Stmt **begin = getTrailingObjects<Stmt *>();
|
||||
return child_range(begin, begin + NumSubExprs);
|
||||
}
|
||||
const_child_range children() const {
|
||||
Stmt * const *begin = getTrailingObjects<Stmt *>();
|
||||
return const_child_range(begin, begin + NumSubExprs);
|
||||
}
|
||||
|
||||
friend TrailingObjects;
|
||||
};
|
||||
|
@ -4287,6 +4386,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
// In cases like:
|
||||
|
@ -4332,6 +4434,10 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(&BaseAndUpdaterExprs[0],
|
||||
&BaseAndUpdaterExprs[0] + 2);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a loop initializing the elements of an array.
|
||||
|
@ -4393,6 +4499,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(SubExprs, SubExprs + 2);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(SubExprs, SubExprs + 2);
|
||||
}
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTStmtReader;
|
||||
|
@ -4421,6 +4530,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTStmtReader;
|
||||
|
@ -4455,6 +4567,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
class ParenListExpr : public Expr {
|
||||
|
@ -4501,6 +4616,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&Exprs[0], &Exprs[0]+NumExprs);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Exprs[0], &Exprs[0] + NumExprs);
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
|
@ -4621,7 +4739,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
return const_child_range(SubExprs, SubExprs + END_EXPR + NumAssocs);
|
||||
}
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
|
@ -4690,6 +4810,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&Base, &Base + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
|
||||
|
@ -4731,6 +4854,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
};
|
||||
|
||||
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
|
||||
|
@ -4776,6 +4902,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
|
||||
const_child_range children() const {
|
||||
return const_child_range(&SrcExpr, &SrcExpr + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// PseudoObjectExpr - An expression which accesses a pseudo-object
|
||||
|
@ -4914,8 +5043,15 @@ public:
|
|||
}
|
||||
|
||||
child_range children() {
|
||||
Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer());
|
||||
return child_range(cs, cs + getNumSubExprs());
|
||||
const_child_range CCR =
|
||||
const_cast<const PseudoObjectExpr *>(this)->children();
|
||||
return child_range(cast_away_const(CCR.begin()),
|
||||
cast_away_const(CCR.end()));
|
||||
}
|
||||
const_child_range children() const {
|
||||
Stmt *const *cs = const_cast<Stmt *const *>(
|
||||
reinterpret_cast<const Stmt *const *>(getSubExprsBuffer()));
|
||||
return const_child_range(cs, cs + getNumSubExprs());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
|
@ -5021,6 +5157,9 @@ public:
|
|||
child_range children() {
|
||||
return child_range(SubExprs, SubExprs+NumSubExprs);
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(SubExprs, SubExprs + NumSubExprs);
|
||||
}
|
||||
};
|
||||
|
||||
/// TypoExpr - Internal placeholder for expressions where typo correction
|
||||
|
@ -5039,6 +5178,10 @@ public:
|
|||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
|
||||
|
||||
|
|
|
@ -54,18 +54,16 @@ class CXXOperatorCallExpr : public CallExpr {
|
|||
OverloadedOperatorKind Operator;
|
||||
SourceRange Range;
|
||||
|
||||
// Record the FP_CONTRACT state that applies to this operator call. Only
|
||||
// meaningful for floating point types. For other types this value can be
|
||||
// set to false.
|
||||
unsigned FPContractable : 1;
|
||||
// Only meaningful for floating point types.
|
||||
FPOptions FPFeatures;
|
||||
|
||||
SourceRange getSourceRangeImpl() const LLVM_READONLY;
|
||||
public:
|
||||
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
|
||||
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
|
||||
SourceLocation operatorloc, bool fpContractable)
|
||||
SourceLocation operatorloc, FPOptions FPFeatures)
|
||||
: CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
|
||||
Operator(Op), FPContractable(fpContractable) {
|
||||
Operator(Op), FPFeatures(FPFeatures) {
|
||||
Range = getSourceRangeImpl();
|
||||
}
|
||||
explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
|
||||
|
@ -113,11 +111,15 @@ public:
|
|||
|
||||
// Set the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
void setFPContractable(bool FPC) { FPContractable = FPC; }
|
||||
void setFPFeatures(FPOptions F) { FPFeatures = F; }
|
||||
|
||||
FPOptions getFPFeatures() const { return FPFeatures; }
|
||||
|
||||
// Get the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
bool isFPContractable() const { return FPContractable; }
|
||||
bool isFPContractableWithinStatement() const {
|
||||
return FPFeatures.allowFPContractWithinStatement();
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
|
@ -1470,7 +1472,8 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
|
|||
public:
|
||||
CXXTemporaryObjectExpr(const ASTContext &C,
|
||||
CXXConstructorDecl *Cons,
|
||||
TypeSourceInfo *Type,
|
||||
QualType Type,
|
||||
TypeSourceInfo *TSI,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceRange ParenOrBraceRange,
|
||||
bool HadMultipleCandidates,
|
||||
|
@ -4122,16 +4125,18 @@ class CoroutineSuspendExpr : public Expr {
|
|||
|
||||
enum SubExpr { Common, Ready, Suspend, Resume, Count };
|
||||
Stmt *SubExprs[SubExpr::Count];
|
||||
OpaqueValueExpr *OpaqueValue = nullptr;
|
||||
|
||||
friend class ASTStmtReader;
|
||||
public:
|
||||
CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Common,
|
||||
Expr *Ready, Expr *Suspend, Expr *Resume)
|
||||
Expr *Ready, Expr *Suspend, Expr *Resume,
|
||||
OpaqueValueExpr *OpaqueValue)
|
||||
: Expr(SC, Resume->getType(), Resume->getValueKind(),
|
||||
Resume->getObjectKind(), Resume->isTypeDependent(),
|
||||
Resume->isValueDependent(), Common->isInstantiationDependent(),
|
||||
Common->containsUnexpandedParameterPack()),
|
||||
KeywordLoc(KeywordLoc) {
|
||||
KeywordLoc(KeywordLoc), OpaqueValue(OpaqueValue) {
|
||||
SubExprs[SubExpr::Common] = Common;
|
||||
SubExprs[SubExpr::Ready] = Ready;
|
||||
SubExprs[SubExpr::Suspend] = Suspend;
|
||||
|
@ -4160,6 +4165,8 @@ public:
|
|||
Expr *getCommonExpr() const {
|
||||
return static_cast<Expr*>(SubExprs[SubExpr::Common]);
|
||||
}
|
||||
/// \brief getOpaqueValue - Return the opaque value placeholder.
|
||||
OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; }
|
||||
|
||||
Expr *getReadyExpr() const {
|
||||
return static_cast<Expr*>(SubExprs[SubExpr::Ready]);
|
||||
|
@ -4193,11 +4200,17 @@ class CoawaitExpr : public CoroutineSuspendExpr {
|
|||
friend class ASTStmtReader;
|
||||
public:
|
||||
CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready,
|
||||
Expr *Suspend, Expr *Resume)
|
||||
Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue,
|
||||
bool IsImplicit = false)
|
||||
: CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Operand, Ready,
|
||||
Suspend, Resume) {}
|
||||
CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand)
|
||||
: CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {}
|
||||
Suspend, Resume, OpaqueValue) {
|
||||
CoawaitBits.IsImplicit = IsImplicit;
|
||||
}
|
||||
CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand,
|
||||
bool IsImplicit = false)
|
||||
: CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {
|
||||
CoawaitBits.IsImplicit = IsImplicit;
|
||||
}
|
||||
CoawaitExpr(EmptyShell Empty)
|
||||
: CoroutineSuspendExpr(CoawaitExprClass, Empty) {}
|
||||
|
||||
|
@ -4206,19 +4219,67 @@ public:
|
|||
return getCommonExpr();
|
||||
}
|
||||
|
||||
bool isImplicit() const { return CoawaitBits.IsImplicit; }
|
||||
void setIsImplicit(bool value = true) { CoawaitBits.IsImplicit = value; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CoawaitExprClass;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a 'co_await' expression while the type of the promise
|
||||
/// is dependent.
|
||||
class DependentCoawaitExpr : public Expr {
|
||||
SourceLocation KeywordLoc;
|
||||
Stmt *SubExprs[2];
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
DependentCoawaitExpr(SourceLocation KeywordLoc, QualType Ty, Expr *Op,
|
||||
UnresolvedLookupExpr *OpCoawait)
|
||||
: Expr(DependentCoawaitExprClass, Ty, VK_RValue, OK_Ordinary,
|
||||
/*TypeDependent*/ true, /*ValueDependent*/ true,
|
||||
/*InstantiationDependent*/ true,
|
||||
Op->containsUnexpandedParameterPack()),
|
||||
KeywordLoc(KeywordLoc) {
|
||||
// NOTE: A co_await expression is dependent on the coroutines promise
|
||||
// type and may be dependent even when the `Op` expression is not.
|
||||
assert(Ty->isDependentType() &&
|
||||
"wrong constructor for non-dependent co_await/co_yield expression");
|
||||
SubExprs[0] = Op;
|
||||
SubExprs[1] = OpCoawait;
|
||||
}
|
||||
|
||||
DependentCoawaitExpr(EmptyShell Empty)
|
||||
: Expr(DependentCoawaitExprClass, Empty) {}
|
||||
|
||||
Expr *getOperand() const { return cast<Expr>(SubExprs[0]); }
|
||||
UnresolvedLookupExpr *getOperatorCoawaitLookup() const {
|
||||
return cast<UnresolvedLookupExpr>(SubExprs[1]);
|
||||
}
|
||||
SourceLocation getKeywordLoc() const { return KeywordLoc; }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
return getOperand()->getLocEnd();
|
||||
}
|
||||
|
||||
child_range children() { return child_range(SubExprs, SubExprs + 2); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DependentCoawaitExprClass;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a 'co_yield' expression.
|
||||
class CoyieldExpr : public CoroutineSuspendExpr {
|
||||
friend class ASTStmtReader;
|
||||
public:
|
||||
CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Ready,
|
||||
Expr *Suspend, Expr *Resume)
|
||||
Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue)
|
||||
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Operand, Ready,
|
||||
Suspend, Resume) {}
|
||||
Suspend, Resume, OpaqueValue) {}
|
||||
CoyieldExpr(SourceLocation CoyieldLoc, QualType Ty, Expr *Operand)
|
||||
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Ty, Operand) {}
|
||||
CoyieldExpr(EmptyShell Empty)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
//===--- ExternalASTMerger.h - Merging External AST Interface ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the ExternalASTMerger, which vends a combination of ASTs
|
||||
// from several different ASTContext/FileManager pairs
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H
|
||||
#define LLVM_CLANG_AST_EXTERNALASTMERGER_H
|
||||
|
||||
#include "clang/AST/ASTImporter.h"
|
||||
#include "clang/AST/ExternalASTSource.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ExternalASTMerger : public ExternalASTSource {
|
||||
public:
|
||||
struct ImporterPair {
|
||||
std::unique_ptr<ASTImporter> Forward;
|
||||
std::unique_ptr<ASTImporter> Reverse;
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<ImporterPair> Importers;
|
||||
|
||||
public:
|
||||
struct ImporterEndpoint {
|
||||
ASTContext &AST;
|
||||
FileManager &FM;
|
||||
};
|
||||
ExternalASTMerger(const ImporterEndpoint &Target,
|
||||
llvm::ArrayRef<ImporterEndpoint> Sources);
|
||||
|
||||
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
|
||||
DeclarationName Name) override;
|
||||
|
||||
void
|
||||
FindExternalLexicalDecls(const DeclContext *DC,
|
||||
llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
|
||||
SmallVectorImpl<Decl *> &Result) override;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/Basic/Module.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
@ -149,26 +150,30 @@ public:
|
|||
StringRef PCHModuleName;
|
||||
StringRef Path;
|
||||
StringRef ASTFile;
|
||||
uint64_t Signature = 0;
|
||||
ASTFileSignature Signature;
|
||||
const Module *ClangModule = nullptr;
|
||||
|
||||
public:
|
||||
ASTSourceDescriptor(){};
|
||||
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
|
||||
uint64_t Signature)
|
||||
ASTFileSignature Signature)
|
||||
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
|
||||
ASTFile(std::move(ASTFile)), Signature(Signature){};
|
||||
ASTSourceDescriptor(const Module &M);
|
||||
std::string getModuleName() const;
|
||||
StringRef getPath() const { return Path; }
|
||||
StringRef getASTFile() const { return ASTFile; }
|
||||
uint64_t getSignature() const { return Signature; }
|
||||
ASTFileSignature getSignature() const { return Signature; }
|
||||
const Module *getModuleOrNull() const { return ClangModule; }
|
||||
};
|
||||
|
||||
/// Return a descriptor for the corresponding module, if one exists.
|
||||
virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
|
||||
|
||||
enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
|
||||
|
||||
virtual ExtKind hasExternalDefinitions(const Decl *D);
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext, after applying an optional filter predicate.
|
||||
///
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
NSStr_initWithString,
|
||||
NSStr_initWithUTF8String
|
||||
};
|
||||
static const unsigned NumNSStringMethods = 5;
|
||||
static const unsigned NumNSStringMethods = 6;
|
||||
|
||||
IdentifierInfo *getNSClassId(NSClassIdKindKind K) const;
|
||||
|
||||
|
@ -112,7 +112,7 @@ public:
|
|||
NSMutableDict_setObjectForKeyedSubscript,
|
||||
NSMutableDict_setValueForKey
|
||||
};
|
||||
static const unsigned NumNSDictionaryMethods = 14;
|
||||
static const unsigned NumNSDictionaryMethods = 13;
|
||||
|
||||
/// \brief The Objective-C NSDictionary selectors.
|
||||
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
//===-- ODRHash.h - Hashing to diagnose ODR failures ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file contains the declaration of the ODRHash class, which calculates
|
||||
/// a hash based on AST nodes, which is stable across different runs.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Decl;
|
||||
class IdentifierInfo;
|
||||
class NestedNameSpecifier;
|
||||
class Stmt;
|
||||
class TemplateParameterList;
|
||||
|
||||
// ODRHash is used to calculate a hash based on AST node contents that
|
||||
// does not rely on pointer addresses. This allows the hash to not vary
|
||||
// between runs and is usable to detect ODR problems in modules. To use,
|
||||
// construct an ODRHash object, then call Add* methods over the nodes that
|
||||
// need to be hashed. Then call CalculateHash to get the hash value.
|
||||
// Typically, only one Add* call is needed. clear can be called to reuse the
|
||||
// object.
|
||||
class ODRHash {
|
||||
// Use DenseMaps to convert between Decl and Type pointers and an index value.
|
||||
llvm::DenseMap<const Decl*, unsigned> DeclMap;
|
||||
llvm::DenseMap<const Type*, unsigned> TypeMap;
|
||||
|
||||
// Save space by processing bools at the end.
|
||||
llvm::SmallVector<bool, 128> Bools;
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
|
||||
public:
|
||||
ODRHash() {}
|
||||
|
||||
// Use this for ODR checking classes between modules. This method compares
|
||||
// more information than the AddDecl class.
|
||||
void AddCXXRecordDecl(const CXXRecordDecl *Record);
|
||||
|
||||
// Process SubDecls of the main Decl. This method calls the DeclVisitor
|
||||
// while AddDecl does not.
|
||||
void AddSubDecl(const Decl *D);
|
||||
|
||||
// Reset the object for reuse.
|
||||
void clear();
|
||||
|
||||
// Add booleans to ID and uses it to calculate the hash.
|
||||
unsigned CalculateHash();
|
||||
|
||||
// Add AST nodes that need to be processed.
|
||||
void AddDecl(const Decl *D);
|
||||
void AddType(const Type *T);
|
||||
void AddQualType(QualType T);
|
||||
void AddStmt(const Stmt *S);
|
||||
void AddIdentifierInfo(const IdentifierInfo *II);
|
||||
void AddNestedNameSpecifier(const NestedNameSpecifier *NNS);
|
||||
void AddTemplateName(TemplateName Name);
|
||||
void AddDeclarationName(DeclarationName Name);
|
||||
void AddTemplateArgument(TemplateArgument TA);
|
||||
void AddTemplateParameterList(const TemplateParameterList *TPL);
|
||||
|
||||
// Save booleans until the end to lower the size of data to process.
|
||||
void AddBoolean(bool value);
|
||||
|
||||
static bool isWhitelistedDecl(const Decl* D, const CXXRecordDecl *Record);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
|
@ -20,6 +20,7 @@
|
|||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Basic/OpenMPKinds.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
@ -76,10 +77,17 @@ class OMPClauseWithPreInit {
|
|||
friend class OMPClauseReader;
|
||||
/// Pre-initialization statement for the clause.
|
||||
Stmt *PreInit;
|
||||
/// Region that captures the associated stmt.
|
||||
OpenMPDirectiveKind CaptureRegion;
|
||||
|
||||
protected:
|
||||
/// Set pre-initialization statement for the clause.
|
||||
void setPreInitStmt(Stmt *S) { PreInit = S; }
|
||||
OMPClauseWithPreInit(const OMPClause *This) : PreInit(nullptr) {
|
||||
void setPreInitStmt(Stmt *S, OpenMPDirectiveKind ThisRegion = OMPD_unknown) {
|
||||
PreInit = S;
|
||||
CaptureRegion = ThisRegion;
|
||||
}
|
||||
OMPClauseWithPreInit(const OMPClause *This)
|
||||
: PreInit(nullptr), CaptureRegion(OMPD_unknown) {
|
||||
assert(get(This) && "get is not tuned for pre-init.");
|
||||
}
|
||||
|
||||
|
@ -88,6 +96,8 @@ public:
|
|||
const Stmt *getPreInitStmt() const { return PreInit; }
|
||||
/// Get pre-initialization statement for the clause.
|
||||
Stmt *getPreInitStmt() { return PreInit; }
|
||||
/// Get capture region for the stmt in the clause.
|
||||
OpenMPDirectiveKind getCaptureRegion() { return CaptureRegion; }
|
||||
static OMPClauseWithPreInit *get(OMPClause *C);
|
||||
static const OMPClauseWithPreInit *get(const OMPClause *C);
|
||||
};
|
||||
|
@ -194,7 +204,7 @@ public:
|
|||
/// In this example directive '#pragma omp parallel' has simple 'if' clause with
|
||||
/// condition 'a > 5' and directive name modifier 'parallel'.
|
||||
///
|
||||
class OMPIfClause : public OMPClause {
|
||||
class OMPIfClause : public OMPClause, public OMPClauseWithPreInit {
|
||||
friend class OMPClauseReader;
|
||||
/// \brief Location of '('.
|
||||
SourceLocation LParenLoc;
|
||||
|
@ -225,26 +235,31 @@ public:
|
|||
///
|
||||
/// \param NameModifier [OpenMP 4.1] Directive name modifier of clause.
|
||||
/// \param Cond Condition of the clause.
|
||||
/// \param HelperCond Helper condition for the clause.
|
||||
/// \param CaptureRegion Innermost OpenMP region where expressions in this
|
||||
/// clause must be captured.
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param NameModifierLoc Location of directive name modifier.
|
||||
/// \param ColonLoc [OpenMP 4.1] Location of ':'.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
///
|
||||
OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond,
|
||||
SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation NameModifierLoc, SourceLocation ColonLoc,
|
||||
SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_if, StartLoc, EndLoc), LParenLoc(LParenLoc),
|
||||
Condition(Cond), ColonLoc(ColonLoc), NameModifier(NameModifier),
|
||||
NameModifierLoc(NameModifierLoc) {}
|
||||
OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond, Stmt *HelperCond,
|
||||
OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation NameModifierLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_if, StartLoc, EndLoc), OMPClauseWithPreInit(this),
|
||||
LParenLoc(LParenLoc), Condition(Cond), ColonLoc(ColonLoc),
|
||||
NameModifier(NameModifier), NameModifierLoc(NameModifierLoc) {
|
||||
setPreInitStmt(HelperCond, CaptureRegion);
|
||||
}
|
||||
|
||||
/// \brief Build an empty clause.
|
||||
///
|
||||
OMPIfClause()
|
||||
: OMPClause(OMPC_if, SourceLocation(), SourceLocation()), LParenLoc(),
|
||||
Condition(nullptr), ColonLoc(), NameModifier(OMPD_unknown),
|
||||
NameModifierLoc() {}
|
||||
: OMPClause(OMPC_if, SourceLocation(), SourceLocation()),
|
||||
OMPClauseWithPreInit(this), LParenLoc(), Condition(nullptr), ColonLoc(),
|
||||
NameModifier(OMPD_unknown), NameModifierLoc() {}
|
||||
|
||||
/// \brief Sets the location of '('.
|
||||
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
|
||||
|
@ -331,7 +346,7 @@ public:
|
|||
/// In this example directive '#pragma omp parallel' has simple 'num_threads'
|
||||
/// clause with number of threads '6'.
|
||||
///
|
||||
class OMPNumThreadsClause : public OMPClause {
|
||||
class OMPNumThreadsClause : public OMPClause, public OMPClauseWithPreInit {
|
||||
friend class OMPClauseReader;
|
||||
/// \brief Location of '('.
|
||||
SourceLocation LParenLoc;
|
||||
|
@ -346,20 +361,29 @@ public:
|
|||
/// \brief Build 'num_threads' clause with condition \a NumThreads.
|
||||
///
|
||||
/// \param NumThreads Number of threads for the construct.
|
||||
/// \param HelperNumThreads Helper Number of threads for the construct.
|
||||
/// \param CaptureRegion Innermost OpenMP region where expressions in this
|
||||
/// clause must be captured.
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
///
|
||||
OMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_num_threads, StartLoc, EndLoc), LParenLoc(LParenLoc),
|
||||
NumThreads(NumThreads) {}
|
||||
OMPNumThreadsClause(Expr *NumThreads, Stmt *HelperNumThreads,
|
||||
OpenMPDirectiveKind CaptureRegion,
|
||||
SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_num_threads, StartLoc, EndLoc),
|
||||
OMPClauseWithPreInit(this), LParenLoc(LParenLoc),
|
||||
NumThreads(NumThreads) {
|
||||
setPreInitStmt(HelperNumThreads, CaptureRegion);
|
||||
}
|
||||
|
||||
/// \brief Build an empty clause.
|
||||
///
|
||||
OMPNumThreadsClause()
|
||||
: OMPClause(OMPC_num_threads, SourceLocation(), SourceLocation()),
|
||||
LParenLoc(SourceLocation()), NumThreads(nullptr) {}
|
||||
OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
|
||||
NumThreads(nullptr) {}
|
||||
|
||||
/// \brief Sets the location of '('.
|
||||
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
|
||||
|
@ -1866,6 +1890,217 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// This represents clause 'task_reduction' in the '#pragma omp taskgroup'
|
||||
/// directives.
|
||||
///
|
||||
/// \code
|
||||
/// #pragma omp taskgroup task_reduction(+:a,b)
|
||||
/// \endcode
|
||||
/// In this example directive '#pragma omp taskgroup' has clause
|
||||
/// 'task_reduction' with operator '+' and the variables 'a' and 'b'.
|
||||
///
|
||||
class OMPTaskReductionClause final
|
||||
: public OMPVarListClause<OMPTaskReductionClause>,
|
||||
public OMPClauseWithPostUpdate,
|
||||
private llvm::TrailingObjects<OMPTaskReductionClause, Expr *> {
|
||||
friend TrailingObjects;
|
||||
friend OMPVarListClause;
|
||||
friend class OMPClauseReader;
|
||||
/// Location of ':'.
|
||||
SourceLocation ColonLoc;
|
||||
/// Nested name specifier for C++.
|
||||
NestedNameSpecifierLoc QualifierLoc;
|
||||
/// Name of custom operator.
|
||||
DeclarationNameInfo NameInfo;
|
||||
|
||||
/// Build clause with number of variables \a N.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param ColonLoc Location of ':'.
|
||||
/// \param N Number of the variables in the clause.
|
||||
/// \param QualifierLoc The nested-name qualifier with location information
|
||||
/// \param NameInfo The full name info for reduction identifier.
|
||||
///
|
||||
OMPTaskReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc,
|
||||
unsigned N, NestedNameSpecifierLoc QualifierLoc,
|
||||
const DeclarationNameInfo &NameInfo)
|
||||
: OMPVarListClause<OMPTaskReductionClause>(OMPC_task_reduction, StartLoc,
|
||||
LParenLoc, EndLoc, N),
|
||||
OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc),
|
||||
QualifierLoc(QualifierLoc), NameInfo(NameInfo) {}
|
||||
|
||||
/// Build an empty clause.
|
||||
///
|
||||
/// \param N Number of variables.
|
||||
///
|
||||
explicit OMPTaskReductionClause(unsigned N)
|
||||
: OMPVarListClause<OMPTaskReductionClause>(
|
||||
OMPC_task_reduction, SourceLocation(), SourceLocation(),
|
||||
SourceLocation(), N),
|
||||
OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {}
|
||||
|
||||
/// Sets location of ':' symbol in clause.
|
||||
void setColonLoc(SourceLocation CL) { ColonLoc = CL; }
|
||||
/// Sets the name info for specified reduction identifier.
|
||||
void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; }
|
||||
/// Sets the nested name specifier.
|
||||
void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
|
||||
|
||||
/// Set list of helper expressions, required for proper codegen of the clause.
|
||||
/// These expressions represent private copy of the reduction variable.
|
||||
void setPrivates(ArrayRef<Expr *> Privates);
|
||||
|
||||
/// Get the list of helper privates.
|
||||
MutableArrayRef<Expr *> getPrivates() {
|
||||
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getPrivates() const {
|
||||
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||
}
|
||||
|
||||
/// Set list of helper expressions, required for proper codegen of the clause.
|
||||
/// These expressions represent LHS expression in the final reduction
|
||||
/// expression performed by the reduction clause.
|
||||
void setLHSExprs(ArrayRef<Expr *> LHSExprs);
|
||||
|
||||
/// Get the list of helper LHS expressions.
|
||||
MutableArrayRef<Expr *> getLHSExprs() {
|
||||
return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getLHSExprs() const {
|
||||
return llvm::makeArrayRef(getPrivates().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// Set list of helper expressions, required for proper codegen of the clause.
|
||||
/// These expressions represent RHS expression in the final reduction
|
||||
/// expression performed by the reduction clause. Also, variables in these
|
||||
/// expressions are used for proper initialization of reduction copies.
|
||||
void setRHSExprs(ArrayRef<Expr *> RHSExprs);
|
||||
|
||||
/// Get the list of helper destination expressions.
|
||||
MutableArrayRef<Expr *> getRHSExprs() {
|
||||
return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getRHSExprs() const {
|
||||
return llvm::makeArrayRef(getLHSExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// Set list of helper reduction expressions, required for proper
|
||||
/// codegen of the clause. These expressions are binary expressions or
|
||||
/// operator/custom reduction call that calculates new value from source
|
||||
/// helper expressions to destination helper expressions.
|
||||
void setReductionOps(ArrayRef<Expr *> ReductionOps);
|
||||
|
||||
/// Get the list of helper reduction expressions.
|
||||
MutableArrayRef<Expr *> getReductionOps() {
|
||||
return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getReductionOps() const {
|
||||
return llvm::makeArrayRef(getRHSExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
public:
|
||||
/// Creates clause with a list of variables \a VL.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param ColonLoc Location of ':'.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param VL The variables in the clause.
|
||||
/// \param QualifierLoc The nested-name qualifier with location information
|
||||
/// \param NameInfo The full name info for reduction identifier.
|
||||
/// \param Privates List of helper expressions for proper generation of
|
||||
/// private copies.
|
||||
/// \param LHSExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyprivate clause. This list represents
|
||||
/// LHSs of the reduction expressions.
|
||||
/// \param RHSExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyprivate clause. This list represents
|
||||
/// RHSs of the reduction expressions.
|
||||
/// Also, variables in these expressions are used for proper initialization of
|
||||
/// reduction copies.
|
||||
/// \param ReductionOps List of helper expressions that represents reduction
|
||||
/// expressions:
|
||||
/// \code
|
||||
/// LHSExprs binop RHSExprs;
|
||||
/// operator binop(LHSExpr, RHSExpr);
|
||||
/// <CutomReduction>(LHSExpr, RHSExpr);
|
||||
/// \endcode
|
||||
/// Required for proper codegen of final reduction operation performed by the
|
||||
/// reduction clause.
|
||||
/// \param PreInit Statement that must be executed before entering the OpenMP
|
||||
/// region with this clause.
|
||||
/// \param PostUpdate Expression that must be executed after exit from the
|
||||
/// OpenMP region with this clause.
|
||||
///
|
||||
static OMPTaskReductionClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates,
|
||||
ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs,
|
||||
ArrayRef<Expr *> ReductionOps, Stmt *PreInit, Expr *PostUpdate);
|
||||
|
||||
/// Creates an empty clause with the place for \a N variables.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param N The number of variables.
|
||||
///
|
||||
static OMPTaskReductionClause *CreateEmpty(const ASTContext &C, unsigned N);
|
||||
|
||||
/// Gets location of ':' symbol in clause.
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
/// Gets the name info for specified reduction identifier.
|
||||
const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
|
||||
/// Gets the nested name specifier.
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
|
||||
typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
|
||||
typedef llvm::iterator_range<helper_expr_const_iterator>
|
||||
helper_expr_const_range;
|
||||
|
||||
helper_expr_const_range privates() const {
|
||||
return helper_expr_const_range(getPrivates().begin(), getPrivates().end());
|
||||
}
|
||||
helper_expr_range privates() {
|
||||
return helper_expr_range(getPrivates().begin(), getPrivates().end());
|
||||
}
|
||||
helper_expr_const_range lhs_exprs() const {
|
||||
return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
|
||||
}
|
||||
helper_expr_range lhs_exprs() {
|
||||
return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end());
|
||||
}
|
||||
helper_expr_const_range rhs_exprs() const {
|
||||
return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end());
|
||||
}
|
||||
helper_expr_range rhs_exprs() {
|
||||
return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end());
|
||||
}
|
||||
helper_expr_const_range reduction_ops() const {
|
||||
return helper_expr_const_range(getReductionOps().begin(),
|
||||
getReductionOps().end());
|
||||
}
|
||||
helper_expr_range reduction_ops() {
|
||||
return helper_expr_range(getReductionOps().begin(),
|
||||
getReductionOps().end());
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
return T->getClauseKind() == OMPC_task_reduction;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This represents clause 'linear' in the '#pragma omp ...'
|
||||
/// directives.
|
||||
///
|
||||
|
@ -2978,7 +3213,7 @@ protected:
|
|||
// Organize the components by declaration and retrieve the original
|
||||
// expression. Original expressions are always the first component of the
|
||||
// mappable component list.
|
||||
llvm::DenseMap<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>>
|
||||
llvm::MapVector<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>>
|
||||
ComponentListMap;
|
||||
{
|
||||
auto CI = ComponentLists.begin();
|
||||
|
@ -3456,7 +3691,7 @@ public:
|
|||
/// In this example directive '#pragma omp teams' has clause 'num_teams'
|
||||
/// with single expression 'n'.
|
||||
///
|
||||
class OMPNumTeamsClause : public OMPClause {
|
||||
class OMPNumTeamsClause : public OMPClause, public OMPClauseWithPreInit {
|
||||
friend class OMPClauseReader;
|
||||
/// \brief Location of '('.
|
||||
SourceLocation LParenLoc;
|
||||
|
@ -3472,20 +3707,27 @@ public:
|
|||
/// \brief Build 'num_teams' clause.
|
||||
///
|
||||
/// \param E Expression associated with this clause.
|
||||
/// \param HelperE Helper Expression associated with this clause.
|
||||
/// \param CaptureRegion Innermost OpenMP region where expressions in this
|
||||
/// clause must be captured.
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
///
|
||||
OMPNumTeamsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
OMPNumTeamsClause(Expr *E, Stmt *HelperE, OpenMPDirectiveKind CaptureRegion,
|
||||
SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_num_teams, StartLoc, EndLoc), LParenLoc(LParenLoc),
|
||||
NumTeams(E) {}
|
||||
: OMPClause(OMPC_num_teams, StartLoc, EndLoc), OMPClauseWithPreInit(this),
|
||||
LParenLoc(LParenLoc), NumTeams(E) {
|
||||
setPreInitStmt(HelperE, CaptureRegion);
|
||||
}
|
||||
|
||||
/// \brief Build an empty clause.
|
||||
///
|
||||
OMPNumTeamsClause()
|
||||
: OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()),
|
||||
LParenLoc(SourceLocation()), NumTeams(nullptr) {}
|
||||
: OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()),
|
||||
OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
|
||||
NumTeams(nullptr) {}
|
||||
/// \brief Sets the location of '('.
|
||||
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
|
||||
/// \brief Returns the location of '('.
|
||||
|
@ -3511,7 +3753,7 @@ public:
|
|||
/// In this example directive '#pragma omp teams' has clause 'thread_limit'
|
||||
/// with single expression 'n'.
|
||||
///
|
||||
class OMPThreadLimitClause : public OMPClause {
|
||||
class OMPThreadLimitClause : public OMPClause, public OMPClauseWithPreInit {
|
||||
friend class OMPClauseReader;
|
||||
/// \brief Location of '('.
|
||||
SourceLocation LParenLoc;
|
||||
|
@ -3527,20 +3769,28 @@ public:
|
|||
/// \brief Build 'thread_limit' clause.
|
||||
///
|
||||
/// \param E Expression associated with this clause.
|
||||
/// \param HelperE Helper Expression associated with this clause.
|
||||
/// \param CaptureRegion Innermost OpenMP region where expressions in this
|
||||
/// clause must be captured.
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
///
|
||||
OMPThreadLimitClause(Expr *E, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_thread_limit, StartLoc, EndLoc), LParenLoc(LParenLoc),
|
||||
ThreadLimit(E) {}
|
||||
OMPThreadLimitClause(Expr *E, Stmt *HelperE,
|
||||
OpenMPDirectiveKind CaptureRegion,
|
||||
SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_thread_limit, StartLoc, EndLoc),
|
||||
OMPClauseWithPreInit(this), LParenLoc(LParenLoc), ThreadLimit(E) {
|
||||
setPreInitStmt(HelperE, CaptureRegion);
|
||||
}
|
||||
|
||||
/// \brief Build an empty clause.
|
||||
///
|
||||
OMPThreadLimitClause()
|
||||
: OMPClause(OMPC_thread_limit, SourceLocation(), SourceLocation()),
|
||||
LParenLoc(SourceLocation()), ThreadLimit(nullptr) {}
|
||||
OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
|
||||
ThreadLimit(nullptr) {}
|
||||
/// \brief Sets the location of '('.
|
||||
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
|
||||
/// \brief Returns the location of '('.
|
||||
|
|
|
@ -593,6 +593,16 @@ bool RecursiveASTVisitor<Derived>::PostVisitStmt(Stmt *S) {
|
|||
#define STMT(CLASS, PARENT) \
|
||||
case Stmt::CLASS##Class: \
|
||||
TRY_TO(WalkUpFrom##CLASS(static_cast<CLASS *>(S))); break;
|
||||
#define INITLISTEXPR(CLASS, PARENT) \
|
||||
case Stmt::CLASS##Class: \
|
||||
{ \
|
||||
auto ILE = static_cast<CLASS *>(S); \
|
||||
if (auto Syn = ILE->isSemanticForm() ? ILE->getSyntacticForm() : ILE) \
|
||||
TRY_TO(WalkUpFrom##CLASS(Syn)); \
|
||||
if (auto Sem = ILE->isSemanticForm() ? ILE : ILE->getSemanticForm()) \
|
||||
TRY_TO(WalkUpFrom##CLASS(Sem)); \
|
||||
break; \
|
||||
}
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
}
|
||||
|
||||
|
@ -774,6 +784,11 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
|
|||
TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
|
||||
break;
|
||||
|
||||
case DeclarationName::CXXDeductionGuideName:
|
||||
TRY_TO(TraverseTemplateName(
|
||||
TemplateName(NameInfo.getName().getCXXDeductionGuideTemplate())));
|
||||
break;
|
||||
|
||||
case DeclarationName::Identifier:
|
||||
case DeclarationName::ObjCZeroArgSelector:
|
||||
case DeclarationName::ObjCOneArgSelector:
|
||||
|
@ -1008,12 +1023,20 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
|
|||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
|
||||
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(RecordType, {})
|
||||
DEF_TRAVERSE_TYPE(EnumType, {})
|
||||
DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
|
||||
TRY_TO(TraverseType(T->getReplacementType()));
|
||||
})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
|
||||
TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
|
@ -1232,11 +1255,20 @@ DEF_TRAVERSE_TYPELOC(AutoType, {
|
|||
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(RecordType, {})
|
||||
DEF_TRAVERSE_TYPELOC(EnumType, {})
|
||||
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {})
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
|
||||
})
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
|
||||
TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
|
||||
})
|
||||
|
||||
// FIXME: use the loc for the template name?
|
||||
DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
|
||||
|
@ -1767,6 +1799,7 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
|
|||
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
|
||||
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
|
||||
\
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); \
|
||||
if (!getDerived().shouldVisitTemplateInstantiations() && \
|
||||
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \
|
||||
/* Returning from here skips traversing the \
|
||||
|
@ -1932,6 +1965,13 @@ DEF_TRAVERSE_DECL(FunctionDecl, {
|
|||
ReturnValue = TraverseFunctionHelper(D);
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(CXXDeductionGuideDecl, {
|
||||
// We skip decls_begin/decls_end, which are already covered by
|
||||
// TraverseFunctionHelper().
|
||||
ShouldVisitChildren = false;
|
||||
ReturnValue = TraverseFunctionHelper(D);
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(CXXMethodDecl, {
|
||||
// We skip decls_begin/decls_end, which are already covered by
|
||||
// TraverseFunctionHelper().
|
||||
|
@ -2191,13 +2231,15 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
|
|||
// the syntactic and the semantic form.
|
||||
//
|
||||
// There is no guarantee about which form \p S takes when this method is called.
|
||||
DEF_TRAVERSE_STMT(InitListExpr, {
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
|
||||
InitListExpr *S, DataRecursionQueue *Queue) {
|
||||
TRY_TO(TraverseSynOrSemInitListExpr(
|
||||
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
|
||||
TRY_TO(TraverseSynOrSemInitListExpr(
|
||||
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
|
||||
ShouldVisitChildren = false;
|
||||
})
|
||||
return true;
|
||||
}
|
||||
|
||||
// GenericSelectionExpr is a special case because the types and expressions
|
||||
// are interleaved. We also need to watch out for null types (default
|
||||
|
@ -2305,7 +2347,7 @@ DEF_TRAVERSE_STMT(LambdaExpr, {
|
|||
}
|
||||
|
||||
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
|
||||
FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
|
||||
FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
|
||||
|
||||
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
|
||||
// Visit the whole type.
|
||||
|
@ -2495,6 +2537,12 @@ DEF_TRAVERSE_STMT(CoawaitExpr, {
|
|||
ShouldVisitChildren = false;
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_STMT(DependentCoawaitExpr, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
|
||||
ShouldVisitChildren = false;
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_STMT(CoyieldExpr, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
|
||||
|
@ -2711,6 +2759,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPClauseWithPostUpdate(
|
|||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPIfClause(OMPIfClause *C) {
|
||||
TRY_TO(VisitOMPClauseWithPreInit(C));
|
||||
TRY_TO(TraverseStmt(C->getCondition()));
|
||||
return true;
|
||||
}
|
||||
|
@ -2724,6 +2773,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPFinalClause(OMPFinalClause *C) {
|
|||
template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
|
||||
TRY_TO(VisitOMPClauseWithPreInit(C));
|
||||
TRY_TO(TraverseStmt(C->getNumThreads()));
|
||||
return true;
|
||||
}
|
||||
|
@ -2966,6 +3016,28 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPTaskReductionClause(
|
||||
OMPTaskReductionClause *C) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
TRY_TO(VisitOMPClauseWithPostUpdate(C));
|
||||
for (auto *E : C->privates()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->lhs_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->rhs_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->reduction_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
|
@ -2993,6 +3065,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
|
|||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
|
||||
OMPNumTeamsClause *C) {
|
||||
TRY_TO(VisitOMPClauseWithPreInit(C));
|
||||
TRY_TO(TraverseStmt(C->getNumTeams()));
|
||||
return true;
|
||||
}
|
||||
|
@ -3000,6 +3073,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
|
|||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause(
|
||||
OMPThreadLimitClause *C) {
|
||||
TRY_TO(VisitOMPClauseWithPreInit(C));
|
||||
TRY_TO(TraverseStmt(C->getThreadLimit()));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,60 @@
|
|||
namespace clang {
|
||||
class ASTContext;
|
||||
|
||||
// Some notes on redeclarables:
|
||||
//
|
||||
// - Every redeclarable is on a circular linked list.
|
||||
//
|
||||
// - Every decl has a pointer to the first element of the chain _and_ a
|
||||
// DeclLink that may point to one of 3 possible states:
|
||||
// - the "previous" (temporal) element in the chain
|
||||
// - the "latest" (temporal) element in the chain
|
||||
// - the an "uninitialized-latest" value (when newly-constructed)
|
||||
//
|
||||
// - The first element is also often called the canonical element. Every
|
||||
// element has a pointer to it so that "getCanonical" can be fast.
|
||||
//
|
||||
// - Most links in the chain point to previous, except the link out of
|
||||
// the first; it points to latest.
|
||||
//
|
||||
// - Elements are called "first", "previous", "latest" or
|
||||
// "most-recent" when referring to temporal order: order of addition
|
||||
// to the chain.
|
||||
//
|
||||
// - To make matters confusing, the DeclLink type uses the term "next"
|
||||
// for its pointer-storage internally (thus functions like
|
||||
// NextIsPrevious). It's easiest to just ignore the implementation of
|
||||
// DeclLink when making sense of the redeclaration chain.
|
||||
//
|
||||
// - There's also a "definition" link for several types of
|
||||
// redeclarable, where only one definition should exist at any given
|
||||
// time (and the defn pointer is stored in the decl's "data" which
|
||||
// is copied to every element on the chain when it's changed).
|
||||
//
|
||||
// Here is some ASCII art:
|
||||
//
|
||||
// "first" "latest"
|
||||
// "canonical" "most recent"
|
||||
// +------------+ first +--------------+
|
||||
// | | <--------------------------- | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | +--------------+ | |
|
||||
// | | first | | | |
|
||||
// | | <---- | | | |
|
||||
// | | | | | |
|
||||
// | @class A | link | @interface A | link | @class A |
|
||||
// | seen first | <---- | seen second | <---- | seen third |
|
||||
// | | | | | |
|
||||
// +------------+ +--------------+ +--------------+
|
||||
// | data | defn | data | defn | data |
|
||||
// | | ----> | | <---- | |
|
||||
// +------------+ +--------------+ +--------------+
|
||||
// | | ^ ^
|
||||
// | |defn | |
|
||||
// | link +-----+ |
|
||||
// +-->-------------------------------------------+
|
||||
|
||||
/// \brief Provides common interface for the Decls that can be redeclared.
|
||||
template<typename decl_type>
|
||||
class Redeclarable {
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace clang {
|
|||
class Expr;
|
||||
class IdentifierInfo;
|
||||
class LabelDecl;
|
||||
class ODRHash;
|
||||
class ParmVarDecl;
|
||||
class PrinterHelper;
|
||||
struct PrintingPolicy;
|
||||
|
@ -126,13 +127,13 @@ protected:
|
|||
unsigned : NumStmtBits;
|
||||
|
||||
unsigned ValueKind : 2;
|
||||
unsigned ObjectKind : 2;
|
||||
unsigned ObjectKind : 3;
|
||||
unsigned TypeDependent : 1;
|
||||
unsigned ValueDependent : 1;
|
||||
unsigned InstantiationDependent : 1;
|
||||
unsigned ContainsUnexpandedParameterPack : 1;
|
||||
};
|
||||
enum { NumExprBits = 16 };
|
||||
enum { NumExprBits = 17 };
|
||||
|
||||
class CharacterLiteralBitfields {
|
||||
friend class CharacterLiteral;
|
||||
|
@ -252,6 +253,14 @@ protected:
|
|||
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
|
||||
};
|
||||
|
||||
class CoawaitExprBitfields {
|
||||
friend class CoawaitExpr;
|
||||
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned IsImplicit : 1;
|
||||
};
|
||||
|
||||
union {
|
||||
StmtBitfields StmtBits;
|
||||
CompoundStmtBitfields CompoundStmtBits;
|
||||
|
@ -268,6 +277,7 @@ protected:
|
|||
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
|
||||
InitListExprBitfields InitListExprBits;
|
||||
TypeTraitExprBitfields TypeTraitExprBits;
|
||||
CoawaitExprBitfields CoawaitBits;
|
||||
};
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
@ -340,6 +350,8 @@ protected:
|
|||
|
||||
public:
|
||||
Stmt(StmtClass SC) {
|
||||
static_assert(sizeof(*this) == sizeof(void *),
|
||||
"changing bitfields changed sizeof(Stmt)");
|
||||
static_assert(sizeof(*this) % alignof(void *) == 0,
|
||||
"Insufficient alignment!");
|
||||
StmtBits.sClass = SC;
|
||||
|
@ -436,6 +448,15 @@ public:
|
|||
/// written in the source.
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
|
||||
bool Canonical) const;
|
||||
|
||||
/// \brief Calculate a unique representation for a statement that is
|
||||
/// stable across compiler invocations.
|
||||
///
|
||||
/// \param ID profile information will be stored in ID.
|
||||
///
|
||||
/// \param Hash an ODRHash object which will be called where pointers would
|
||||
/// have been used in the Profile function.
|
||||
void ProcessODRHash(llvm::FoldingSetNodeID &ID, ODRHash& Hash) const;
|
||||
};
|
||||
|
||||
/// DeclStmt - Adaptor class for mixing declarations with statements and
|
||||
|
|
|
@ -296,7 +296,9 @@ public:
|
|||
/// \brief Represents the body of a coroutine. This wraps the normal function
|
||||
/// body and holds the additional semantic context required to set up and tear
|
||||
/// down the coroutine frame.
|
||||
class CoroutineBodyStmt : public Stmt {
|
||||
class CoroutineBodyStmt final
|
||||
: public Stmt,
|
||||
private llvm::TrailingObjects<CoroutineBodyStmt, Stmt *> {
|
||||
enum SubStmt {
|
||||
Body, ///< The body of the coroutine.
|
||||
Promise, ///< The promise statement.
|
||||
|
@ -306,66 +308,106 @@ class CoroutineBodyStmt : public Stmt {
|
|||
OnFallthrough, ///< Handler for control flow falling off the body.
|
||||
Allocate, ///< Coroutine frame memory allocation.
|
||||
Deallocate, ///< Coroutine frame memory deallocation.
|
||||
ReturnValue, ///< Return value for thunk function.
|
||||
ReturnValue, ///< Return value for thunk function: p.get_return_object().
|
||||
ResultDecl, ///< Declaration holding the result of get_return_object.
|
||||
ReturnStmt, ///< Return statement for the thunk function.
|
||||
ReturnStmtOnAllocFailure, ///< Return statement if allocation failed.
|
||||
FirstParamMove ///< First offset for move construction of parameter copies.
|
||||
};
|
||||
Stmt *SubStmts[SubStmt::FirstParamMove];
|
||||
unsigned NumParams;
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); }
|
||||
|
||||
Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); }
|
||||
|
||||
public:
|
||||
CoroutineBodyStmt(Stmt *Body, Stmt *Promise, Stmt *InitSuspend,
|
||||
Stmt *FinalSuspend, Stmt *OnException, Stmt *OnFallthrough,
|
||||
Expr *Allocate, Stmt *Deallocate,
|
||||
Expr *ReturnValue, ArrayRef<Expr *> ParamMoves)
|
||||
: Stmt(CoroutineBodyStmtClass) {
|
||||
SubStmts[CoroutineBodyStmt::Body] = Body;
|
||||
SubStmts[CoroutineBodyStmt::Promise] = Promise;
|
||||
SubStmts[CoroutineBodyStmt::InitSuspend] = InitSuspend;
|
||||
SubStmts[CoroutineBodyStmt::FinalSuspend] = FinalSuspend;
|
||||
SubStmts[CoroutineBodyStmt::OnException] = OnException;
|
||||
SubStmts[CoroutineBodyStmt::OnFallthrough] = OnFallthrough;
|
||||
SubStmts[CoroutineBodyStmt::Allocate] = Allocate;
|
||||
SubStmts[CoroutineBodyStmt::Deallocate] = Deallocate;
|
||||
SubStmts[CoroutineBodyStmt::ReturnValue] = ReturnValue;
|
||||
// FIXME: Tail-allocate space for parameter move expressions and store them.
|
||||
assert(ParamMoves.empty() && "not implemented yet");
|
||||
|
||||
struct CtorArgs {
|
||||
Stmt *Body = nullptr;
|
||||
Stmt *Promise = nullptr;
|
||||
Expr *InitialSuspend = nullptr;
|
||||
Expr *FinalSuspend = nullptr;
|
||||
Stmt *OnException = nullptr;
|
||||
Stmt *OnFallthrough = nullptr;
|
||||
Expr *Allocate = nullptr;
|
||||
Expr *Deallocate = nullptr;
|
||||
Expr *ReturnValue = nullptr;
|
||||
Stmt *ResultDecl = nullptr;
|
||||
Stmt *ReturnStmt = nullptr;
|
||||
Stmt *ReturnStmtOnAllocFailure = nullptr;
|
||||
ArrayRef<Stmt *> ParamMoves;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
CoroutineBodyStmt(CtorArgs const& Args);
|
||||
|
||||
public:
|
||||
static CoroutineBodyStmt *Create(const ASTContext &C, CtorArgs const &Args);
|
||||
|
||||
bool hasDependentPromiseType() const {
|
||||
return getPromiseDecl()->getType()->isDependentType();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the body of the coroutine as written. This will be either
|
||||
/// a CompoundStmt or a TryStmt.
|
||||
Stmt *getBody() const {
|
||||
return SubStmts[SubStmt::Body];
|
||||
return getStoredStmts()[SubStmt::Body];
|
||||
}
|
||||
|
||||
Stmt *getPromiseDeclStmt() const { return SubStmts[SubStmt::Promise]; }
|
||||
Stmt *getPromiseDeclStmt() const {
|
||||
return getStoredStmts()[SubStmt::Promise];
|
||||
}
|
||||
VarDecl *getPromiseDecl() const {
|
||||
return cast<VarDecl>(cast<DeclStmt>(getPromiseDeclStmt())->getSingleDecl());
|
||||
}
|
||||
|
||||
Stmt *getInitSuspendStmt() const { return SubStmts[SubStmt::InitSuspend]; }
|
||||
Stmt *getFinalSuspendStmt() const { return SubStmts[SubStmt::FinalSuspend]; }
|
||||
|
||||
Stmt *getExceptionHandler() const { return SubStmts[SubStmt::OnException]; }
|
||||
Stmt *getFallthroughHandler() const {
|
||||
return SubStmts[SubStmt::OnFallthrough];
|
||||
Stmt *getInitSuspendStmt() const {
|
||||
return getStoredStmts()[SubStmt::InitSuspend];
|
||||
}
|
||||
Stmt *getFinalSuspendStmt() const {
|
||||
return getStoredStmts()[SubStmt::FinalSuspend];
|
||||
}
|
||||
|
||||
Expr *getAllocate() const { return cast<Expr>(SubStmts[SubStmt::Allocate]); }
|
||||
Stmt *getDeallocate() const { return SubStmts[SubStmt::Deallocate]; }
|
||||
Stmt *getExceptionHandler() const {
|
||||
return getStoredStmts()[SubStmt::OnException];
|
||||
}
|
||||
Stmt *getFallthroughHandler() const {
|
||||
return getStoredStmts()[SubStmt::OnFallthrough];
|
||||
}
|
||||
|
||||
Expr *getAllocate() const {
|
||||
return cast_or_null<Expr>(getStoredStmts()[SubStmt::Allocate]);
|
||||
}
|
||||
Expr *getDeallocate() const {
|
||||
return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]);
|
||||
}
|
||||
Expr *getReturnValueInit() const {
|
||||
return cast<Expr>(SubStmts[SubStmt::ReturnValue]);
|
||||
return cast<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
|
||||
}
|
||||
Stmt *getResultDecl() const { return getStoredStmts()[SubStmt::ResultDecl]; }
|
||||
Stmt *getReturnStmt() const { return getStoredStmts()[SubStmt::ReturnStmt]; }
|
||||
Stmt *getReturnStmtOnAllocFailure() const {
|
||||
return getStoredStmts()[SubStmt::ReturnStmtOnAllocFailure];
|
||||
}
|
||||
ArrayRef<Stmt const *> getParamMoves() const {
|
||||
return {getStoredStmts() + SubStmt::FirstParamMove, NumParams};
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return getBody()->getLocStart();
|
||||
return getBody() ? getBody()->getLocStart()
|
||||
: getPromiseDecl()->getLocStart();
|
||||
}
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
return getBody()->getLocEnd();
|
||||
return getBody() ? getBody()->getLocEnd() : getPromiseDecl()->getLocEnd();
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(SubStmts, SubStmts + SubStmt::FirstParamMove);
|
||||
return child_range(getStoredStmts(),
|
||||
getStoredStmts() + SubStmt::FirstParamMove + NumParams);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
|
@ -390,10 +432,14 @@ class CoreturnStmt : public Stmt {
|
|||
enum SubStmt { Operand, PromiseCall, Count };
|
||||
Stmt *SubStmts[SubStmt::Count];
|
||||
|
||||
bool IsImplicit : 1;
|
||||
|
||||
friend class ASTStmtReader;
|
||||
public:
|
||||
CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall)
|
||||
: Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc) {
|
||||
CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall,
|
||||
bool IsImplicit = false)
|
||||
: Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc),
|
||||
IsImplicit(IsImplicit) {
|
||||
SubStmts[SubStmt::Operand] = Operand;
|
||||
SubStmts[SubStmt::PromiseCall] = PromiseCall;
|
||||
}
|
||||
|
@ -411,6 +457,9 @@ public:
|
|||
return static_cast<Expr*>(SubStmts[PromiseCall]);
|
||||
}
|
||||
|
||||
bool isImplicit() const { return IsImplicit; }
|
||||
void setIsImplicit(bool value = true) { IsImplicit = value; }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
return getOperand() ? getOperand()->getLocEnd() : getLocStart();
|
||||
|
|
|
@ -118,6 +118,8 @@ public:
|
|||
REFERENCE operator->() const { return operator*(); }
|
||||
};
|
||||
|
||||
struct ConstStmtIterator;
|
||||
|
||||
struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
||||
explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
|
||||
|
||||
|
@ -128,6 +130,13 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
|||
|
||||
StmtIterator(const VariableArrayType *t)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||
|
||||
private:
|
||||
StmtIterator(const StmtIteratorBase &RHS)
|
||||
: StmtIteratorImpl<StmtIterator, Stmt *&>(RHS) {}
|
||||
|
||||
inline friend StmtIterator
|
||||
cast_away_const(const ConstStmtIterator &RHS);
|
||||
};
|
||||
|
||||
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||
|
@ -137,8 +146,15 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
|||
|
||||
ConstStmtIterator(const StmtIterator& RHS) :
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
|
||||
|
||||
ConstStmtIterator(Stmt * const *S)
|
||||
: StmtIteratorImpl<ConstStmtIterator, const Stmt *>(
|
||||
const_cast<Stmt **>(S)) {}
|
||||
};
|
||||
|
||||
inline StmtIterator cast_away_const(const ConstStmtIterator &RHS) {
|
||||
return RHS;
|
||||
}
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -198,6 +198,26 @@ public:
|
|||
return const_cast<Stmt *>(*child_begin());
|
||||
}
|
||||
|
||||
/// \brief Returns the captured statement associated with the
|
||||
/// component region within the (combined) directive.
|
||||
//
|
||||
// \param RegionKind Component region kind.
|
||||
CapturedStmt *getCapturedStmt(OpenMPDirectiveKind RegionKind) const {
|
||||
SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
|
||||
getOpenMPCaptureRegions(CaptureRegions, getDirectiveKind());
|
||||
assert(std::any_of(
|
||||
CaptureRegions.begin(), CaptureRegions.end(),
|
||||
[=](const OpenMPDirectiveKind K) { return K == RegionKind; }) &&
|
||||
"RegionKind not found in OpenMP CaptureRegions.");
|
||||
auto *CS = cast<CapturedStmt>(getAssociatedStmt());
|
||||
for (auto ThisCaptureRegion : CaptureRegions) {
|
||||
if (ThisCaptureRegion == RegionKind)
|
||||
return CS;
|
||||
CS = cast<CapturedStmt>(CS->getCapturedStmt());
|
||||
}
|
||||
llvm_unreachable("Incorrect RegionKind specified for directive.");
|
||||
}
|
||||
|
||||
OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
|
||||
|
||||
static bool classof(const Stmt *S) {
|
||||
|
@ -298,12 +318,18 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
|||
/// \brief Offsets to the stored exprs.
|
||||
/// This enumeration contains offsets to all the pointers to children
|
||||
/// expressions stored in OMPLoopDirective.
|
||||
/// The first 9 children are nesessary for all the loop directives, and
|
||||
/// the next 10 are specific to the worksharing ones.
|
||||
/// The first 9 children are necessary for all the loop directives,
|
||||
/// the next 8 are specific to the worksharing ones, and the next 11 are
|
||||
/// used for combined constructs containing two pragmas associated to loops.
|
||||
/// After the fixed children, three arrays of length CollapsedNum are
|
||||
/// allocated: loop counters, their updates and final values.
|
||||
/// PrevLowerBound and PrevUpperBound are used to communicate blocking
|
||||
/// information in composite constructs which require loop blocking
|
||||
/// DistInc is used to generate the increment expression for the distribute
|
||||
/// loop when combined with a further nested loop
|
||||
/// PrevEnsureUpperBound is used as the EnsureUpperBound expression for the
|
||||
/// for loop when combined with a previous distribute loop in the same pragma
|
||||
/// (e.g. 'distribute parallel for')
|
||||
///
|
||||
enum {
|
||||
AssociatedStmtOffset = 0,
|
||||
|
@ -319,7 +345,7 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
|||
// specify the offset to the end (and start of the following counters/
|
||||
// updates/finals arrays).
|
||||
DefaultEnd = 9,
|
||||
// The following 7 exprs are used by worksharing loops only.
|
||||
// The following 8 exprs are used by worksharing and distribute loops only.
|
||||
IsLastIterVariableOffset = 9,
|
||||
LowerBoundVariableOffset = 10,
|
||||
UpperBoundVariableOffset = 11,
|
||||
|
@ -328,11 +354,22 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
|||
NextLowerBoundOffset = 14,
|
||||
NextUpperBoundOffset = 15,
|
||||
NumIterationsOffset = 16,
|
||||
// Offset to the end for worksharing loop directives.
|
||||
WorksharingEnd = 17,
|
||||
PrevLowerBoundVariableOffset = 17,
|
||||
PrevUpperBoundVariableOffset = 18,
|
||||
DistIncOffset = 19,
|
||||
PrevEnsureUpperBoundOffset = 20,
|
||||
CombinedLowerBoundVariableOffset = 21,
|
||||
CombinedUpperBoundVariableOffset = 22,
|
||||
CombinedEnsureUpperBoundOffset = 23,
|
||||
CombinedInitOffset = 24,
|
||||
CombinedConditionOffset = 25,
|
||||
CombinedNextLowerBoundOffset = 26,
|
||||
CombinedNextUpperBoundOffset = 27,
|
||||
// Offset to the end (and start of the following counters/updates/finals
|
||||
// arrays) for worksharing loop directives.
|
||||
WorksharingEnd = 19,
|
||||
// arrays) for combined distribute loop directives.
|
||||
CombinedDistributeEnd = 28,
|
||||
};
|
||||
|
||||
/// \brief Get the counters storage.
|
||||
|
@ -396,11 +433,12 @@ protected:
|
|||
|
||||
/// \brief Offset to the start of children expression arrays.
|
||||
static unsigned getArraysOffset(OpenMPDirectiveKind Kind) {
|
||||
return (isOpenMPWorksharingDirective(Kind) ||
|
||||
isOpenMPTaskLoopDirective(Kind) ||
|
||||
isOpenMPDistributeDirective(Kind))
|
||||
? WorksharingEnd
|
||||
: DefaultEnd;
|
||||
if (isOpenMPLoopBoundSharingDirective(Kind))
|
||||
return CombinedDistributeEnd;
|
||||
if (isOpenMPWorksharingDirective(Kind) || isOpenMPTaskLoopDirective(Kind) ||
|
||||
isOpenMPDistributeDirective(Kind))
|
||||
return WorksharingEnd;
|
||||
return DefaultEnd;
|
||||
}
|
||||
|
||||
/// \brief Children number.
|
||||
|
@ -488,19 +526,60 @@ protected:
|
|||
*std::next(child_begin(), NumIterationsOffset) = NI;
|
||||
}
|
||||
void setPrevLowerBoundVariable(Expr *PrevLB) {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), PrevLowerBoundVariableOffset) = PrevLB;
|
||||
}
|
||||
void setPrevUpperBoundVariable(Expr *PrevUB) {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), PrevUpperBoundVariableOffset) = PrevUB;
|
||||
}
|
||||
void setDistInc(Expr *DistInc) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), DistIncOffset) = DistInc;
|
||||
}
|
||||
void setPrevEnsureUpperBound(Expr *PrevEUB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), PrevEnsureUpperBoundOffset) = PrevEUB;
|
||||
}
|
||||
void setCombinedLowerBoundVariable(Expr *CombLB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedLowerBoundVariableOffset) = CombLB;
|
||||
}
|
||||
void setCombinedUpperBoundVariable(Expr *CombUB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedUpperBoundVariableOffset) = CombUB;
|
||||
}
|
||||
void setCombinedEnsureUpperBound(Expr *CombEUB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedEnsureUpperBoundOffset) = CombEUB;
|
||||
}
|
||||
void setCombinedInit(Expr *CombInit) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedInitOffset) = CombInit;
|
||||
}
|
||||
void setCombinedCond(Expr *CombCond) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedConditionOffset) = CombCond;
|
||||
}
|
||||
void setCombinedNextLowerBound(Expr *CombNLB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedNextLowerBoundOffset) = CombNLB;
|
||||
}
|
||||
void setCombinedNextUpperBound(Expr *CombNUB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB;
|
||||
}
|
||||
void setCounters(ArrayRef<Expr *> A);
|
||||
void setPrivateCounters(ArrayRef<Expr *> A);
|
||||
void setInits(ArrayRef<Expr *> A);
|
||||
|
@ -508,6 +587,33 @@ protected:
|
|||
void setFinals(ArrayRef<Expr *> A);
|
||||
|
||||
public:
|
||||
/// The expressions built to support OpenMP loops in combined/composite
|
||||
/// pragmas (e.g. pragma omp distribute parallel for)
|
||||
struct DistCombinedHelperExprs {
|
||||
/// DistributeLowerBound - used when composing 'omp distribute' with
|
||||
/// 'omp for' in a same construct.
|
||||
Expr *LB;
|
||||
/// DistributeUpperBound - used when composing 'omp distribute' with
|
||||
/// 'omp for' in a same construct.
|
||||
Expr *UB;
|
||||
/// DistributeEnsureUpperBound - used when composing 'omp distribute'
|
||||
/// with 'omp for' in a same construct, EUB depends on DistUB
|
||||
Expr *EUB;
|
||||
/// Distribute loop iteration variable init used when composing 'omp
|
||||
/// distribute'
|
||||
/// with 'omp for' in a same construct
|
||||
Expr *Init;
|
||||
/// Distribute Loop condition used when composing 'omp distribute'
|
||||
/// with 'omp for' in a same construct
|
||||
Expr *Cond;
|
||||
/// Update of LowerBound for statically sheduled omp loops for
|
||||
/// outer loop in combined constructs (e.g. 'distribute parallel for')
|
||||
Expr *NLB;
|
||||
/// Update of UpperBound for statically sheduled omp loops for
|
||||
/// outer loop in combined constructs (e.g. 'distribute parallel for')
|
||||
Expr *NUB;
|
||||
};
|
||||
|
||||
/// \brief The expressions built for the OpenMP loop CodeGen for the
|
||||
/// whole collapsed loop nest.
|
||||
struct HelperExprs {
|
||||
|
@ -535,7 +641,7 @@ public:
|
|||
Expr *UB;
|
||||
/// \brief Stride - local variable passed to runtime.
|
||||
Expr *ST;
|
||||
/// \brief EnsureUpperBound -- expression LB = min(LB, NumIterations).
|
||||
/// \brief EnsureUpperBound -- expression UB = min(UB, NumIterations).
|
||||
Expr *EUB;
|
||||
/// \brief Update of LowerBound for statically sheduled 'omp for' loops.
|
||||
Expr *NLB;
|
||||
|
@ -547,6 +653,16 @@ public:
|
|||
/// \brief PreviousUpperBound - local variable passed to runtime in the
|
||||
/// enclosing schedule or null if that does not apply.
|
||||
Expr *PrevUB;
|
||||
/// \brief DistInc - increment expression for distribute loop when found
|
||||
/// combined with a further loop level (e.g. in 'distribute parallel for')
|
||||
/// expression IV = IV + ST
|
||||
Expr *DistInc;
|
||||
/// \brief PrevEUB - expression similar to EUB but to be used when loop
|
||||
/// scheduling uses PrevLB and PrevUB (e.g. in 'distribute parallel for'
|
||||
/// when ensuring that the UB is either the calculated UB by the runtime or
|
||||
/// the end of the assigned distribute chunk)
|
||||
/// expression UB = min (UB, PrevUB)
|
||||
Expr *PrevEUB;
|
||||
/// \brief Counters Loop counters.
|
||||
SmallVector<Expr *, 4> Counters;
|
||||
/// \brief PrivateCounters Loop counters.
|
||||
|
@ -560,6 +676,9 @@ public:
|
|||
/// Init statement for all captured expressions.
|
||||
Stmt *PreInits;
|
||||
|
||||
/// Expressions used when combining OpenMP loop pragmas
|
||||
DistCombinedHelperExprs DistCombinedFields;
|
||||
|
||||
/// \brief Check if all the expressions are built (does not check the
|
||||
/// worksharing ones).
|
||||
bool builtAll() {
|
||||
|
@ -588,6 +707,8 @@ public:
|
|||
NumIterations = nullptr;
|
||||
PrevLB = nullptr;
|
||||
PrevUB = nullptr;
|
||||
DistInc = nullptr;
|
||||
PrevEUB = nullptr;
|
||||
Counters.resize(Size);
|
||||
PrivateCounters.resize(Size);
|
||||
Inits.resize(Size);
|
||||
|
@ -601,6 +722,13 @@ public:
|
|||
Finals[i] = nullptr;
|
||||
}
|
||||
PreInits = nullptr;
|
||||
DistCombinedFields.LB = nullptr;
|
||||
DistCombinedFields.UB = nullptr;
|
||||
DistCombinedFields.EUB = nullptr;
|
||||
DistCombinedFields.Init = nullptr;
|
||||
DistCombinedFields.Cond = nullptr;
|
||||
DistCombinedFields.NLB = nullptr;
|
||||
DistCombinedFields.NUB = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -704,21 +832,71 @@ public:
|
|||
*std::next(child_begin(), NumIterationsOffset)));
|
||||
}
|
||||
Expr *getPrevLowerBoundVariable() const {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), PrevLowerBoundVariableOffset)));
|
||||
}
|
||||
Expr *getPrevUpperBoundVariable() const {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), PrevUpperBoundVariableOffset)));
|
||||
}
|
||||
Expr *getDistInc() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), DistIncOffset)));
|
||||
}
|
||||
Expr *getPrevEnsureUpperBound() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), PrevEnsureUpperBoundOffset)));
|
||||
}
|
||||
Expr *getCombinedLowerBoundVariable() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedLowerBoundVariableOffset)));
|
||||
}
|
||||
Expr *getCombinedUpperBoundVariable() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedUpperBoundVariableOffset)));
|
||||
}
|
||||
Expr *getCombinedEnsureUpperBound() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedEnsureUpperBoundOffset)));
|
||||
}
|
||||
Expr *getCombinedInit() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedInitOffset)));
|
||||
}
|
||||
Expr *getCombinedCond() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedConditionOffset)));
|
||||
}
|
||||
Expr *getCombinedNextLowerBound() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedNextLowerBoundOffset)));
|
||||
}
|
||||
Expr *getCombinedNextUpperBound() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedNextUpperBoundOffset)));
|
||||
}
|
||||
const Stmt *getBody() const {
|
||||
// This relies on the loop form is already checked by Sema.
|
||||
Stmt *Body = getAssociatedStmt()->IgnoreContainers(true);
|
||||
|
@ -1717,7 +1895,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief This represents '#pragma omp taskgroup' directive.
|
||||
/// This represents '#pragma omp taskgroup' directive.
|
||||
///
|
||||
/// \code
|
||||
/// #pragma omp taskgroup
|
||||
|
@ -1725,39 +1903,45 @@ public:
|
|||
///
|
||||
class OMPTaskgroupDirective : public OMPExecutableDirective {
|
||||
friend class ASTStmtReader;
|
||||
/// \brief Build directive with the given start and end location.
|
||||
/// Build directive with the given start and end location.
|
||||
///
|
||||
/// \param StartLoc Starting location of the directive kind.
|
||||
/// \param EndLoc Ending location of the directive.
|
||||
/// \param NumClauses Number of clauses.
|
||||
///
|
||||
OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc)
|
||||
OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
unsigned NumClauses)
|
||||
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
|
||||
StartLoc, EndLoc, 0, 1) {}
|
||||
StartLoc, EndLoc, NumClauses, 1) {}
|
||||
|
||||
/// \brief Build an empty directive.
|
||||
/// Build an empty directive.
|
||||
/// \param NumClauses Number of clauses.
|
||||
///
|
||||
explicit OMPTaskgroupDirective()
|
||||
explicit OMPTaskgroupDirective(unsigned NumClauses)
|
||||
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
|
||||
SourceLocation(), SourceLocation(), 0, 1) {}
|
||||
SourceLocation(), SourceLocation(), NumClauses,
|
||||
1) {}
|
||||
|
||||
public:
|
||||
/// \brief Creates directive.
|
||||
/// Creates directive.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param StartLoc Starting location of the directive kind.
|
||||
/// \param EndLoc Ending Location of the directive.
|
||||
/// \param Clauses List of clauses.
|
||||
/// \param AssociatedStmt Statement, associated with the directive.
|
||||
///
|
||||
static OMPTaskgroupDirective *Create(const ASTContext &C,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation EndLoc,
|
||||
Stmt *AssociatedStmt);
|
||||
static OMPTaskgroupDirective *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt);
|
||||
|
||||
/// \brief Creates an empty directive.
|
||||
/// Creates an empty directive.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param NumClauses Number of clauses.
|
||||
///
|
||||
static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, EmptyShell);
|
||||
static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C,
|
||||
unsigned NumClauses, EmptyShell);
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == OMPTaskgroupDirectiveClass;
|
||||
|
|
|
@ -119,10 +119,7 @@ private:
|
|||
|
||||
public:
|
||||
/// \brief Construct an empty, invalid template argument.
|
||||
TemplateArgument() {
|
||||
TypeOrValue.Kind = Null;
|
||||
TypeOrValue.V = 0;
|
||||
}
|
||||
constexpr TemplateArgument() : TypeOrValue({Null, 0}) {}
|
||||
|
||||
/// \brief Construct a template type argument.
|
||||
TemplateArgument(QualType T, bool isNullPtr = false) {
|
||||
|
@ -388,8 +385,8 @@ private:
|
|||
};
|
||||
|
||||
public:
|
||||
TemplateArgumentLocInfo();
|
||||
|
||||
constexpr TemplateArgumentLocInfo() : Template({nullptr, nullptr, 0, 0}) {}
|
||||
|
||||
TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {}
|
||||
|
||||
TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
|
||||
|
@ -433,7 +430,7 @@ class TemplateArgumentLoc {
|
|||
TemplateArgumentLocInfo LocInfo;
|
||||
|
||||
public:
|
||||
TemplateArgumentLoc() {}
|
||||
constexpr TemplateArgumentLoc() {}
|
||||
|
||||
TemplateArgumentLoc(const TemplateArgument &Argument,
|
||||
TemplateArgumentLocInfo Opaque)
|
||||
|
@ -578,6 +575,7 @@ struct ASTTemplateArgumentListInfo final
|
|||
TemplateArgumentLoc> {
|
||||
private:
|
||||
friend TrailingObjects;
|
||||
friend class ASTNodeImporter;
|
||||
|
||||
ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
|
||||
|
||||
|
|
|
@ -333,6 +333,23 @@ public:
|
|||
|
||||
bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
|
||||
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
|
||||
bool hasTargetSpecificAddressSpace() const {
|
||||
return getAddressSpace() >= LangAS::FirstTargetAddressSpace;
|
||||
}
|
||||
/// Get the address space attribute value to be printed by diagnostics.
|
||||
unsigned getAddressSpaceAttributePrintValue() const {
|
||||
auto Addr = getAddressSpace();
|
||||
// This function is not supposed to be used with language specific
|
||||
// address spaces. If that happens, the diagnostic message should consider
|
||||
// printing the QualType instead of the address space value.
|
||||
assert(Addr == 0 || hasTargetSpecificAddressSpace());
|
||||
if (Addr)
|
||||
return Addr - LangAS::FirstTargetAddressSpace;
|
||||
// TODO: The diagnostic messages where Addr may be 0 should be fixed
|
||||
// since it cannot differentiate the situation where 0 denotes the default
|
||||
// address space or user specified __attribute__((address_space(0))).
|
||||
return 0;
|
||||
}
|
||||
void setAddressSpace(unsigned space) {
|
||||
assert(space <= MaxAddressSpace);
|
||||
Mask = (Mask & ~AddressSpaceMask)
|
||||
|
@ -1020,6 +1037,9 @@ public:
|
|||
return getQualifiers().hasStrongOrWeakObjCLifetime();
|
||||
}
|
||||
|
||||
// true when Type is objc's weak and weak is enabled but ARC isn't.
|
||||
bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const;
|
||||
|
||||
enum DestructionKind {
|
||||
DK_none,
|
||||
DK_cxx_destructor,
|
||||
|
@ -1379,7 +1399,7 @@ protected:
|
|||
|
||||
/// Extra information which affects how the function is called, like
|
||||
/// regparm and the calling convention.
|
||||
unsigned ExtInfo : 10;
|
||||
unsigned ExtInfo : 11;
|
||||
|
||||
/// Used only by FunctionProtoType, put here to pack with the
|
||||
/// other bitfields.
|
||||
|
@ -1732,6 +1752,7 @@ public:
|
|||
bool isTemplateTypeParmType() const; // C++ template type parameter
|
||||
bool isNullPtrType() const; // C++11 std::nullptr_t
|
||||
bool isAlignValT() const; // C++17 std::align_val_t
|
||||
bool isStdByteType() const; // C++17 std::byte
|
||||
bool isAtomicType() const; // C11 _Atomic()
|
||||
|
||||
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
|
||||
|
@ -1744,7 +1765,6 @@ public:
|
|||
bool isEventT() const; // OpenCL event_t
|
||||
bool isClkEventT() const; // OpenCL clk_event_t
|
||||
bool isQueueT() const; // OpenCL queue_t
|
||||
bool isNDRangeT() const; // OpenCL ndrange_t
|
||||
bool isReserveIDT() const; // OpenCL reserve_id_t
|
||||
|
||||
bool isPipeType() const; // OpenCL pipe type
|
||||
|
@ -1785,7 +1805,8 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Determine whether this type is an undeduced type, meaning that
|
||||
/// it somehow involves a C++11 'auto' type which has not yet been deduced.
|
||||
/// it somehow involves a C++11 'auto' type or similar which has not yet been
|
||||
/// deduced.
|
||||
bool isUndeducedType() const;
|
||||
|
||||
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
|
||||
|
@ -1862,10 +1883,22 @@ public:
|
|||
/// not refer to a CXXRecordDecl, returns NULL.
|
||||
const CXXRecordDecl *getPointeeCXXRecordDecl() const;
|
||||
|
||||
/// Get the DeducedType whose type will be deduced for a variable with
|
||||
/// an initializer of this type. This looks through declarators like pointer
|
||||
/// types, but not through decltype or typedefs.
|
||||
DeducedType *getContainedDeducedType() const;
|
||||
|
||||
/// Get the AutoType whose type will be deduced for a variable with
|
||||
/// an initializer of this type. This looks through declarators like pointer
|
||||
/// types, but not through decltype or typedefs.
|
||||
AutoType *getContainedAutoType() const;
|
||||
AutoType *getContainedAutoType() const {
|
||||
return dyn_cast_or_null<AutoType>(getContainedDeducedType());
|
||||
}
|
||||
|
||||
/// Determine whether this type was written with a leading 'auto'
|
||||
/// corresponding to a trailing return type (possibly for a nested
|
||||
/// function type within a pointer to function type or similar).
|
||||
bool hasAutoForTrailingReturnType() const;
|
||||
|
||||
/// Member-template getAs<specific type>'. Look through sugar for
|
||||
/// an instance of \<specific type>. This scheme will eventually
|
||||
|
@ -1875,6 +1908,13 @@ public:
|
|||
/// immediately following this class.
|
||||
template <typename T> const T *getAs() const;
|
||||
|
||||
/// Member-template getAsAdjusted<specific type>. Look through specific kinds
|
||||
/// of sugar (parens, attributes, etc) for an instance of \<specific type>.
|
||||
/// This is used when you need to walk over sugar nodes that represent some
|
||||
/// kind of type adjustment from a type that was written as a \<specific type>
|
||||
/// to another type that is still canonically a \<specific type>.
|
||||
template <typename T> const T *getAsAdjusted() const;
|
||||
|
||||
/// A variant of getAs<> for array types which silently discards
|
||||
/// qualifiers from the outermost type.
|
||||
const ArrayType *getAsArrayTypeUnsafe() const;
|
||||
|
@ -1972,10 +2012,11 @@ public:
|
|||
Optional<NullabilityKind> getNullability(const ASTContext &context) const;
|
||||
|
||||
/// Determine whether the given type can have a nullability
|
||||
/// specifier applied to it, i.e., if it is any kind of pointer type
|
||||
/// or a dependent type that could instantiate to any kind of
|
||||
/// pointer type.
|
||||
bool canHaveNullability() const;
|
||||
/// specifier applied to it, i.e., if it is any kind of pointer type.
|
||||
///
|
||||
/// \param ResultIfUnknown The value to return if we don't yet know whether
|
||||
/// this type can have nullability because it is dependent.
|
||||
bool canHaveNullability(bool ResultIfUnknown = true) const;
|
||||
|
||||
/// Retrieve the set of substitutions required when accessing a member
|
||||
/// of the Objective-C receiver type that is declared in the given context.
|
||||
|
@ -2057,7 +2098,7 @@ public:
|
|||
: Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
|
||||
/*InstantiationDependent=*/(K == Dependent),
|
||||
/*VariablyModified=*/false,
|
||||
/*Unexpanded paramter pack=*/false) {
|
||||
/*Unexpanded parameter pack=*/false) {
|
||||
BuiltinTypeBits.Kind = K;
|
||||
}
|
||||
|
||||
|
@ -2905,19 +2946,23 @@ class FunctionType : public Type {
|
|||
// * AST read and write
|
||||
// * Codegen
|
||||
class ExtInfo {
|
||||
// Feel free to rearrange or add bits, but if you go over 10,
|
||||
// Feel free to rearrange or add bits, but if you go over 11,
|
||||
// you'll need to adjust both the Bits field below and
|
||||
// Type::FunctionTypeBitfields.
|
||||
|
||||
// | CC |noreturn|produces|regparm|
|
||||
// |0 .. 4| 5 | 6 | 7 .. 9|
|
||||
// | CC |noreturn|produces|nocallersavedregs|regparm|
|
||||
// |0 .. 4| 5 | 6 | 7 |8 .. 10|
|
||||
//
|
||||
// regparm is either 0 (no regparm attribute) or the regparm value+1.
|
||||
enum { CallConvMask = 0x1F };
|
||||
enum { NoReturnMask = 0x20 };
|
||||
enum { ProducesResultMask = 0x40 };
|
||||
enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
|
||||
RegParmOffset = 7 }; // Assumed to be the last field
|
||||
enum { NoCallerSavedRegsMask = 0x80 };
|
||||
enum {
|
||||
RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask |
|
||||
NoCallerSavedRegsMask),
|
||||
RegParmOffset = 8
|
||||
}; // Assumed to be the last field
|
||||
|
||||
uint16_t Bits;
|
||||
|
||||
|
@ -2928,13 +2973,13 @@ class FunctionType : public Type {
|
|||
public:
|
||||
// Constructor with no defaults. Use this when you know that you
|
||||
// have all the elements (when reading an AST file for example).
|
||||
ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
|
||||
bool producesResult) {
|
||||
assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
|
||||
Bits = ((unsigned) cc) |
|
||||
(noReturn ? NoReturnMask : 0) |
|
||||
(producesResult ? ProducesResultMask : 0) |
|
||||
(hasRegParm ? ((regParm + 1) << RegParmOffset) : 0);
|
||||
ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
|
||||
bool producesResult, bool noCallerSavedRegs) {
|
||||
assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
|
||||
Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) |
|
||||
(producesResult ? ProducesResultMask : 0) |
|
||||
(noCallerSavedRegs ? NoCallerSavedRegsMask : 0) |
|
||||
(hasRegParm ? ((regParm + 1) << RegParmOffset) : 0);
|
||||
}
|
||||
|
||||
// Constructor with all defaults. Use when for example creating a
|
||||
|
@ -2947,6 +2992,7 @@ class FunctionType : public Type {
|
|||
|
||||
bool getNoReturn() const { return Bits & NoReturnMask; }
|
||||
bool getProducesResult() const { return Bits & ProducesResultMask; }
|
||||
bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; }
|
||||
bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; }
|
||||
unsigned getRegParm() const {
|
||||
unsigned RegParm = Bits >> RegParmOffset;
|
||||
|
@ -2980,6 +3026,13 @@ class FunctionType : public Type {
|
|||
return ExtInfo(Bits & ~ProducesResultMask);
|
||||
}
|
||||
|
||||
ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const {
|
||||
if (noCallerSavedRegs)
|
||||
return ExtInfo(Bits | NoCallerSavedRegsMask);
|
||||
else
|
||||
return ExtInfo(Bits & ~NoCallerSavedRegsMask);
|
||||
}
|
||||
|
||||
ExtInfo withRegParm(unsigned RegParm) const {
|
||||
assert(RegParm < 7 && "Invalid regparm value");
|
||||
return ExtInfo((Bits & ~RegParmMask) |
|
||||
|
@ -3097,9 +3150,11 @@ public:
|
|||
class ExtParameterInfo {
|
||||
enum {
|
||||
ABIMask = 0x0F,
|
||||
IsConsumed = 0x10
|
||||
IsConsumed = 0x10,
|
||||
HasPassObjSize = 0x20,
|
||||
};
|
||||
unsigned char Data;
|
||||
|
||||
public:
|
||||
ExtParameterInfo() : Data(0) {}
|
||||
|
||||
|
@ -3128,6 +3183,15 @@ public:
|
|||
return copy;
|
||||
}
|
||||
|
||||
bool hasPassObjectSize() const {
|
||||
return Data & HasPassObjSize;
|
||||
}
|
||||
ExtParameterInfo withHasPassObjectSize() const {
|
||||
ExtParameterInfo Copy = *this;
|
||||
Copy.Data |= HasPassObjSize;
|
||||
return Copy;
|
||||
}
|
||||
|
||||
unsigned char getOpaqueValue() const { return Data; }
|
||||
static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
|
||||
ExtParameterInfo result;
|
||||
|
@ -3815,6 +3879,7 @@ public:
|
|||
attr_sptr,
|
||||
attr_uptr,
|
||||
attr_nonnull,
|
||||
attr_ns_returns_retained,
|
||||
attr_nullable,
|
||||
attr_null_unspecified,
|
||||
attr_objc_kindof,
|
||||
|
@ -4089,25 +4154,60 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a C++11 auto or C++14 decltype(auto) type.
|
||||
/// \brief Common base class for placeholders for types that get replaced by
|
||||
/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
|
||||
/// class template types, and (eventually) constrained type names from the C++
|
||||
/// Concepts TS.
|
||||
///
|
||||
/// These types are usually a placeholder for a deduced type. However, before
|
||||
/// the initializer is attached, or (usually) if the initializer is
|
||||
/// type-dependent, there is no deduced type and an auto type is canonical. In
|
||||
/// type-dependent, there is no deduced type and the type is canonical. In
|
||||
/// the latter case, it is also a dependent type.
|
||||
class AutoType : public Type, public llvm::FoldingSetNode {
|
||||
AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent)
|
||||
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
|
||||
/*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
|
||||
/*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
|
||||
if (!DeducedType.isNull()) {
|
||||
if (DeducedType->isDependentType())
|
||||
class DeducedType : public Type {
|
||||
protected:
|
||||
DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent,
|
||||
bool IsInstantiationDependent, bool ContainsParameterPack)
|
||||
: Type(TC,
|
||||
// FIXME: Retain the sugared deduced type?
|
||||
DeducedAsType.isNull() ? QualType(this, 0)
|
||||
: DeducedAsType.getCanonicalType(),
|
||||
IsDependent, IsInstantiationDependent,
|
||||
/*VariablyModified=*/false, ContainsParameterPack) {
|
||||
if (!DeducedAsType.isNull()) {
|
||||
if (DeducedAsType->isDependentType())
|
||||
setDependent();
|
||||
if (DeducedType->isInstantiationDependentType())
|
||||
if (DeducedAsType->isInstantiationDependentType())
|
||||
setInstantiationDependent();
|
||||
if (DeducedType->containsUnexpandedParameterPack())
|
||||
if (DeducedAsType->containsUnexpandedParameterPack())
|
||||
setContainsUnexpandedParameterPack();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool isSugared() const { return !isCanonicalUnqualified(); }
|
||||
QualType desugar() const { return getCanonicalTypeInternal(); }
|
||||
|
||||
/// \brief Get the type deduced for this placeholder type, or null if it's
|
||||
/// either not been deduced or was deduced to a dependent type.
|
||||
QualType getDeducedType() const {
|
||||
return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType();
|
||||
}
|
||||
bool isDeduced() const {
|
||||
return !isCanonicalUnqualified() || isDependentType();
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Auto ||
|
||||
T->getTypeClass() == DeducedTemplateSpecialization;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a C++11 auto or C++14 decltype(auto) type.
|
||||
class AutoType : public DeducedType, public llvm::FoldingSetNode {
|
||||
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
|
||||
bool IsDeducedAsDependent)
|
||||
: DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
|
||||
IsDeducedAsDependent, /*ContainsPack=*/false) {
|
||||
AutoTypeBits.Keyword = (unsigned)Keyword;
|
||||
}
|
||||
|
||||
|
@ -4121,18 +4221,6 @@ public:
|
|||
return (AutoTypeKeyword)AutoTypeBits.Keyword;
|
||||
}
|
||||
|
||||
bool isSugared() const { return !isCanonicalUnqualified(); }
|
||||
QualType desugar() const { return getCanonicalTypeInternal(); }
|
||||
|
||||
/// \brief Get the type deduced for this auto type, or null if it's either
|
||||
/// not been deduced or was deduced to a dependent type.
|
||||
QualType getDeducedType() const {
|
||||
return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType();
|
||||
}
|
||||
bool isDeduced() const {
|
||||
return !isCanonicalUnqualified() || isDependentType();
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getDeducedType(), getKeyword(), isDependentType());
|
||||
}
|
||||
|
@ -4149,6 +4237,43 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a C++17 deduced template specialization type.
|
||||
class DeducedTemplateSpecializationType : public DeducedType,
|
||||
public llvm::FoldingSetNode {
|
||||
/// The name of the template whose arguments will be deduced.
|
||||
TemplateName Template;
|
||||
|
||||
DeducedTemplateSpecializationType(TemplateName Template,
|
||||
QualType DeducedAsType,
|
||||
bool IsDeducedAsDependent)
|
||||
: DeducedType(DeducedTemplateSpecialization, DeducedAsType,
|
||||
IsDeducedAsDependent || Template.isDependent(),
|
||||
IsDeducedAsDependent || Template.isInstantiationDependent(),
|
||||
Template.containsUnexpandedParameterPack()),
|
||||
Template(Template) {}
|
||||
|
||||
friend class ASTContext; // ASTContext creates these
|
||||
|
||||
public:
|
||||
/// Retrieve the name of the template that we are deducing.
|
||||
TemplateName getTemplateName() const { return Template;}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getTemplateName(), getDeducedType(), isDependentType());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template,
|
||||
QualType Deduced, bool IsDependent) {
|
||||
Template.Profile(ID);
|
||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||
ID.AddBoolean(IsDependent);
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == DeducedTemplateSpecialization;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a type template specialization; the template
|
||||
/// must be a class template, a type alias template, or a template
|
||||
/// template parameter. A template which cannot be resolved to one of
|
||||
|
@ -4345,6 +4470,9 @@ public:
|
|||
const TemplateSpecializationType *getInjectedTST() const {
|
||||
return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
|
||||
}
|
||||
TemplateName getTemplateName() const {
|
||||
return getInjectedTST()->getTemplateName();
|
||||
}
|
||||
|
||||
CXXRecordDecl *getDecl() const;
|
||||
|
||||
|
@ -5718,10 +5846,6 @@ inline bool Type::isQueueT() const {
|
|||
return isSpecificBuiltinType(BuiltinType::OCLQueue);
|
||||
}
|
||||
|
||||
inline bool Type::isNDRangeT() const {
|
||||
return isSpecificBuiltinType(BuiltinType::OCLNDRange);
|
||||
}
|
||||
|
||||
inline bool Type::isReserveIDT() const {
|
||||
return isSpecificBuiltinType(BuiltinType::OCLReserveID);
|
||||
}
|
||||
|
@ -5739,7 +5863,7 @@ inline bool Type::isPipeType() const {
|
|||
|
||||
inline bool Type::isOpenCLSpecificType() const {
|
||||
return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
|
||||
isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType();
|
||||
isQueueT() || isReserveIDT() || isPipeType();
|
||||
}
|
||||
|
||||
inline bool Type::isTemplateTypeParmType() const {
|
||||
|
@ -5849,8 +5973,8 @@ inline bool Type::isBooleanType() const {
|
|||
}
|
||||
|
||||
inline bool Type::isUndeducedType() const {
|
||||
const AutoType *AT = getContainedAutoType();
|
||||
return AT && !AT->isDeduced();
|
||||
auto *DT = getContainedDeducedType();
|
||||
return DT && !DT->isDeduced();
|
||||
}
|
||||
|
||||
/// \brief Determines whether this is a type for which one can define
|
||||
|
@ -5932,6 +6056,38 @@ template <typename T> const T *Type::getAs() const {
|
|||
return cast<T>(getUnqualifiedDesugaredType());
|
||||
}
|
||||
|
||||
template <typename T> const T *Type::getAsAdjusted() const {
|
||||
static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!");
|
||||
|
||||
// If this is directly a T type, return it.
|
||||
if (const T *Ty = dyn_cast<T>(this))
|
||||
return Ty;
|
||||
|
||||
// If the canonical form of this type isn't the right kind, reject it.
|
||||
if (!isa<T>(CanonicalType))
|
||||
return nullptr;
|
||||
|
||||
// Strip off type adjustments that do not modify the underlying nature of the
|
||||
// type.
|
||||
const Type *Ty = this;
|
||||
while (Ty) {
|
||||
if (const auto *A = dyn_cast<AttributedType>(Ty))
|
||||
Ty = A->getModifiedType().getTypePtr();
|
||||
else if (const auto *E = dyn_cast<ElaboratedType>(Ty))
|
||||
Ty = E->desugar().getTypePtr();
|
||||
else if (const auto *P = dyn_cast<ParenType>(Ty))
|
||||
Ty = P->desugar().getTypePtr();
|
||||
else if (const auto *A = dyn_cast<AdjustedType>(Ty))
|
||||
Ty = A->desugar().getTypePtr();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Just because the canonical type is correct does not mean we can use cast<>,
|
||||
// since we may not have stripped off all the sugar down to the base type.
|
||||
return dyn_cast<T>(Ty);
|
||||
}
|
||||
|
||||
inline const ArrayType *Type::getAsArrayTypeUnsafe() const {
|
||||
// If this is directly an array type, return it.
|
||||
if (const ArrayType *arr = dyn_cast<ArrayType>(this))
|
||||
|
|
|
@ -70,6 +70,13 @@ public:
|
|||
return t;
|
||||
}
|
||||
|
||||
/// \brief Convert to the specified TypeLoc type, returning a null TypeLoc if
|
||||
/// this TypeLock is not of the desired type. It will consider type
|
||||
/// adjustments from a type that wad written as a T to another type that is
|
||||
/// still canonically a T (ignores parens, attributes, elaborated types, etc).
|
||||
template <typename T>
|
||||
T getAsAdjusted() const;
|
||||
|
||||
/// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum,
|
||||
/// except it also defines a Qualified enum that corresponds to the
|
||||
/// QualifiedLoc class.
|
||||
|
@ -1537,7 +1544,11 @@ class DependentSizedArrayTypeLoc :
|
|||
public InheritingConcreteTypeLoc<ArrayTypeLoc,
|
||||
DependentSizedArrayTypeLoc,
|
||||
DependentSizedArrayType> {
|
||||
|
||||
public:
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
ArrayTypeLoc::initializeLocal(Context, Loc);
|
||||
setSizeExpr(getTypePtr()->getSizeExpr());
|
||||
}
|
||||
};
|
||||
|
||||
class VariableArrayTypeLoc :
|
||||
|
@ -1827,9 +1838,25 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
AutoTypeLoc,
|
||||
AutoType> {
|
||||
class DeducedTypeLoc
|
||||
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DeducedTypeLoc,
|
||||
DeducedType> {};
|
||||
|
||||
class AutoTypeLoc
|
||||
: public InheritingConcreteTypeLoc<DeducedTypeLoc, AutoTypeLoc, AutoType> {
|
||||
};
|
||||
|
||||
class DeducedTemplateSpecializationTypeLoc
|
||||
: public InheritingConcreteTypeLoc<DeducedTypeLoc,
|
||||
DeducedTemplateSpecializationTypeLoc,
|
||||
DeducedTemplateSpecializationType> {
|
||||
public:
|
||||
SourceLocation getTemplateNameLoc() const {
|
||||
return getNameLoc();
|
||||
}
|
||||
void setTemplateNameLoc(SourceLocation Loc) {
|
||||
setNameLoc(Loc);
|
||||
}
|
||||
};
|
||||
|
||||
struct ElaboratedLocInfo {
|
||||
|
@ -2172,6 +2199,24 @@ public:
|
|||
|
||||
QualType getInnerType() const { return this->getTypePtr()->getElementType(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T TypeLoc::getAsAdjusted() const {
|
||||
TypeLoc Cur = *this;
|
||||
while (!T::isKind(Cur)) {
|
||||
if (auto PTL = Cur.getAs<ParenTypeLoc>())
|
||||
Cur = PTL.getInnerLoc();
|
||||
else if (auto ATL = Cur.getAs<AttributedTypeLoc>())
|
||||
Cur = ATL.getModifiedLoc();
|
||||
else if (auto ETL = Cur.getAs<ElaboratedTypeLoc>())
|
||||
Cur = ETL.getNamedTypeLoc();
|
||||
else if (auto ATL = Cur.getAs<AdjustedTypeLoc>())
|
||||
Cur = ATL.getOriginalLoc();
|
||||
else
|
||||
break;
|
||||
}
|
||||
return Cur.getAs<T>();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -96,7 +96,9 @@ DEPENDENT_TYPE(TemplateTypeParm, Type)
|
|||
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
|
||||
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
|
||||
TYPE(Auto, Type)
|
||||
ABSTRACT_TYPE(Deduced, Type)
|
||||
TYPE(Auto, DeducedType)
|
||||
TYPE(DeducedTemplateSpecialization, DeducedType)
|
||||
DEPENDENT_TYPE(InjectedClassName, Type)
|
||||
DEPENDENT_TYPE(DependentName, Type)
|
||||
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
namespace clang {
|
||||
|
||||
/// \brief Function object that provides a total ordering on QualType values.
|
||||
struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
|
||||
struct QualTypeOrdering {
|
||||
bool operator()(QualType T1, QualType T2) const {
|
||||
return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
|
||||
}
|
||||
|
|
|
@ -154,6 +154,28 @@ public:
|
|||
|
||||
bool isRTTIKind() const { return isRTTIKind(getKind()); }
|
||||
|
||||
GlobalDecl getGlobalDecl() const {
|
||||
assert(isUsedFunctionPointerKind() &&
|
||||
"GlobalDecl can be created only from virtual function");
|
||||
|
||||
auto *DtorDecl = dyn_cast<CXXDestructorDecl>(getFunctionDecl());
|
||||
switch (getKind()) {
|
||||
case CK_FunctionPointer:
|
||||
return GlobalDecl(getFunctionDecl());
|
||||
case CK_CompleteDtorPointer:
|
||||
return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete);
|
||||
case CK_DeletingDtorPointer:
|
||||
return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting);
|
||||
case CK_VCallOffset:
|
||||
case CK_VBaseOffset:
|
||||
case CK_OffsetToTop:
|
||||
case CK_RTTI:
|
||||
case CK_UnusedFunctionPointer:
|
||||
llvm_unreachable("Only function pointers kinds");
|
||||
}
|
||||
llvm_unreachable("Should already return");
|
||||
}
|
||||
|
||||
private:
|
||||
static bool isFunctionPointerKind(Kind ComponentKind) {
|
||||
return isUsedFunctionPointerKind(ComponentKind) ||
|
||||
|
|
|
@ -180,6 +180,16 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl>
|
|||
/// matches "using Y = int", but not "typedef int X"
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl;
|
||||
|
||||
/// \brief Matches type alias template declarations.
|
||||
///
|
||||
/// typeAliasTemplateDecl() matches
|
||||
/// \code
|
||||
/// template <typename T>
|
||||
/// using Y = X<T>;
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl>
|
||||
typeAliasTemplateDecl;
|
||||
|
||||
/// \brief Matches AST nodes that were expanded within the main-file.
|
||||
///
|
||||
/// Example matches X but not Y
|
||||
|
@ -1118,6 +1128,69 @@ const internal::VariadicDynCastAllOfMatcher<
|
|||
Decl,
|
||||
ObjCInterfaceDecl> objcInterfaceDecl;
|
||||
|
||||
/// \brief Matches Objective-C protocol declarations.
|
||||
///
|
||||
/// Example matches FooDelegate
|
||||
/// \code
|
||||
/// @protocol FooDelegate
|
||||
/// @end
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<
|
||||
Decl,
|
||||
ObjCProtocolDecl> objcProtocolDecl;
|
||||
|
||||
/// \brief Matches Objective-C category declarations.
|
||||
///
|
||||
/// Example matches Foo (Additions)
|
||||
/// \code
|
||||
/// @interface Foo (Additions)
|
||||
/// @end
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<
|
||||
Decl,
|
||||
ObjCCategoryDecl> objcCategoryDecl;
|
||||
|
||||
/// \brief Matches Objective-C method declarations.
|
||||
///
|
||||
/// Example matches both declaration and definition of -[Foo method]
|
||||
/// \code
|
||||
/// @interface Foo
|
||||
/// - (void)method;
|
||||
/// @end
|
||||
///
|
||||
/// @implementation Foo
|
||||
/// - (void)method {}
|
||||
/// @end
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<
|
||||
Decl,
|
||||
ObjCMethodDecl> objcMethodDecl;
|
||||
|
||||
/// \brief Matches Objective-C instance variable declarations.
|
||||
///
|
||||
/// Example matches _enabled
|
||||
/// \code
|
||||
/// @implementation Foo {
|
||||
/// BOOL _enabled;
|
||||
/// }
|
||||
/// @end
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<
|
||||
Decl,
|
||||
ObjCIvarDecl> objcIvarDecl;
|
||||
|
||||
/// \brief Matches Objective-C property declarations.
|
||||
///
|
||||
/// Example matches enabled
|
||||
/// \code
|
||||
/// @interface Foo
|
||||
/// @property BOOL enabled;
|
||||
/// @end
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<
|
||||
Decl,
|
||||
ObjCPropertyDecl> objcPropertyDecl;
|
||||
|
||||
/// \brief Matches expressions that introduce cleanups to be run at the end
|
||||
/// of the sub-expression's evaluation.
|
||||
///
|
||||
|
@ -1150,6 +1223,20 @@ AST_MATCHER_P(InitListExpr, hasSyntacticForm,
|
|||
InnerMatcher.matches(*SyntForm, Finder, Builder));
|
||||
}
|
||||
|
||||
/// \brief Matches C++ initializer list expressions.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
/// std::vector<int> a({ 1, 2, 3 });
|
||||
/// std::vector<int> b = { 4, 5 };
|
||||
/// int c[] = { 6, 7 };
|
||||
/// std::pair<int, int> d = { 8, 9 };
|
||||
/// \endcode
|
||||
/// cxxStdInitializerListExpr()
|
||||
/// matches "{ 1, 2, 3 }" and "{ 4, 5 }"
|
||||
const internal::VariadicDynCastAllOfMatcher<Stmt,
|
||||
CXXStdInitializerListExpr> cxxStdInitializerListExpr;
|
||||
|
||||
/// \brief Matches implicit initializers of init list expressions.
|
||||
///
|
||||
/// Given
|
||||
|
@ -1333,7 +1420,7 @@ const internal::VariadicDynCastAllOfMatcher<
|
|||
///
|
||||
/// Example: Given
|
||||
/// \code
|
||||
/// struct T {void func()};
|
||||
/// struct T {void func();};
|
||||
/// T f();
|
||||
/// void g(T);
|
||||
/// \endcode
|
||||
|
@ -2522,7 +2609,7 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
|
|||
/// \brief Matches on the receiver of an ObjectiveC Message expression.
|
||||
///
|
||||
/// Example
|
||||
/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
|
||||
/// matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
|
||||
/// matches the [webView ...] message invocation.
|
||||
/// \code
|
||||
/// NSString *webViewJavaScript = ...
|
||||
|
@ -3719,14 +3806,30 @@ AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) {
|
|||
return Node.size() == N;
|
||||
}
|
||||
|
||||
/// \brief Matches literals that are equal to the given value.
|
||||
/// \brief Matches literals that are equal to the given value of type ValueT.
|
||||
///
|
||||
/// Example matches true (matcher = cxxBoolLiteral(equals(true)))
|
||||
/// Given
|
||||
/// \code
|
||||
/// true
|
||||
/// f('\0', false, 3.14, 42);
|
||||
/// \endcode
|
||||
/// characterLiteral(equals(0))
|
||||
/// matches '\0'
|
||||
/// cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
|
||||
/// match false
|
||||
/// floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
|
||||
/// match 3.14
|
||||
/// integerLiteral(equals(42))
|
||||
/// matches 42
|
||||
///
|
||||
/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
|
||||
/// Note that you cannot directly match a negative numeric literal because the
|
||||
/// minus sign is not part of the literal: It is a unary operator whose operand
|
||||
/// is the positive numeric literal. Instead, you must use a unaryOperator()
|
||||
/// matcher to match the minus sign:
|
||||
///
|
||||
/// unaryOperator(hasOperatorName("-"),
|
||||
/// hasUnaryOperand(integerLiteral(equals(13))))
|
||||
///
|
||||
/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
|
||||
/// Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
|
||||
template <typename ValueT>
|
||||
internal::PolymorphicMatcherWithParam1<internal::ValueEqualsMatcher, ValueT>
|
||||
|
@ -3736,6 +3839,34 @@ equals(const ValueT &Value) {
|
|||
ValueT>(Value);
|
||||
}
|
||||
|
||||
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
|
||||
CXXBoolLiteralExpr,
|
||||
IntegerLiteral),
|
||||
bool, Value, 0) {
|
||||
return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
|
||||
.matchesNode(Node);
|
||||
}
|
||||
|
||||
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
|
||||
CXXBoolLiteralExpr,
|
||||
IntegerLiteral),
|
||||
unsigned, Value, 1) {
|
||||
return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
|
||||
.matchesNode(Node);
|
||||
}
|
||||
|
||||
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
|
||||
CXXBoolLiteralExpr,
|
||||
FloatingLiteral,
|
||||
IntegerLiteral),
|
||||
double, Value, 2) {
|
||||
return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
|
||||
.matchesNode(Node);
|
||||
}
|
||||
|
||||
/// \brief Matches the operator Name of operator expressions (binary or
|
||||
/// unary).
|
||||
///
|
||||
|
@ -5507,7 +5638,7 @@ AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
|
|||
integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
|
||||
}
|
||||
|
||||
/// \brief Matches declaration of the function the statemenet belongs to
|
||||
/// \brief Matches declaration of the function the statement belongs to
|
||||
///
|
||||
/// Given:
|
||||
/// \code
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
ET_ParserInvalidToken = 106,
|
||||
ET_ParserMalformedBindExpr = 107,
|
||||
ET_ParserTrailingCode = 108,
|
||||
ET_ParserUnsignedError = 109,
|
||||
ET_ParserNumberError = 109,
|
||||
ET_ParserOverloadedType = 110
|
||||
};
|
||||
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
/// \code
|
||||
/// Grammar for the expressions supported:
|
||||
/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression>
|
||||
/// <Literal> := <StringLiteral> | <Unsigned>
|
||||
/// <Literal> := <StringLiteral> | <Boolean> | <Double> | <Unsigned>
|
||||
/// <StringLiteral> := "quoted string"
|
||||
/// <Boolean> := true | false
|
||||
/// <Double> := [0-9]+.[0-9]* | [0-9]+.[0-9]*[eE][-+]?[0-9]+
|
||||
/// <Unsigned> := [0-9]+
|
||||
/// <NamedValue> := <Identifier>
|
||||
/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
|
||||
|
|
|
@ -35,6 +35,8 @@ class ArgKind {
|
|||
public:
|
||||
enum Kind {
|
||||
AK_Matcher,
|
||||
AK_Boolean,
|
||||
AK_Double,
|
||||
AK_Unsigned,
|
||||
AK_String
|
||||
};
|
||||
|
@ -56,7 +58,7 @@ class ArgKind {
|
|||
/// \param To the requested destination type.
|
||||
///
|
||||
/// \param Specificity value corresponding to the "specificity" of the
|
||||
/// convertion.
|
||||
/// conversion.
|
||||
bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
|
||||
|
||||
bool operator<(const ArgKind &Other) const {
|
||||
|
@ -182,7 +184,7 @@ public:
|
|||
/// \param Kind the requested destination type.
|
||||
///
|
||||
/// \param Specificity value corresponding to the "specificity" of the
|
||||
/// convertion.
|
||||
/// conversion.
|
||||
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
|
||||
unsigned *Specificity) const {
|
||||
if (Value)
|
||||
|
@ -241,6 +243,8 @@ struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
|
|||
/// copy/assignment.
|
||||
///
|
||||
/// Supported types:
|
||||
/// - \c bool
|
||||
// - \c double
|
||||
/// - \c unsigned
|
||||
/// - \c llvm::StringRef
|
||||
/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
|
||||
|
@ -253,14 +257,29 @@ public:
|
|||
VariantValue &operator=(const VariantValue &Other);
|
||||
|
||||
/// \brief Specific constructors for each supported type.
|
||||
VariantValue(bool Boolean);
|
||||
VariantValue(double Double);
|
||||
VariantValue(unsigned Unsigned);
|
||||
VariantValue(StringRef String);
|
||||
VariantValue(const VariantMatcher &Matchers);
|
||||
|
||||
/// \brief Constructs an \c unsigned value (disambiguation from bool).
|
||||
VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {}
|
||||
|
||||
/// \brief Returns true iff this is not an empty value.
|
||||
explicit operator bool() const { return hasValue(); }
|
||||
bool hasValue() const { return Type != VT_Nothing; }
|
||||
|
||||
/// \brief Boolean value functions.
|
||||
bool isBoolean() const;
|
||||
bool getBoolean() const;
|
||||
void setBoolean(bool Boolean);
|
||||
|
||||
/// \brief Double value functions.
|
||||
bool isDouble() const;
|
||||
double getDouble() const;
|
||||
void setDouble(double Double);
|
||||
|
||||
/// \brief Unsigned value functions.
|
||||
bool isUnsigned() const;
|
||||
unsigned getUnsigned() const;
|
||||
|
@ -281,7 +300,7 @@ public:
|
|||
/// \param Kind the requested destination type.
|
||||
///
|
||||
/// \param Specificity value corresponding to the "specificity" of the
|
||||
/// convertion.
|
||||
/// conversion.
|
||||
bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
|
||||
|
||||
/// \brief Determines if the contained value can be converted to any kind
|
||||
|
@ -290,7 +309,7 @@ public:
|
|||
/// \param Kinds the requested destination types.
|
||||
///
|
||||
/// \param Specificity value corresponding to the "specificity" of the
|
||||
/// convertion. It is the maximum specificity of all the possible
|
||||
/// conversion. It is the maximum specificity of all the possible
|
||||
/// conversions.
|
||||
bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
|
||||
|
||||
|
@ -303,6 +322,8 @@ private:
|
|||
/// \brief All supported value types.
|
||||
enum ValueType {
|
||||
VT_Nothing,
|
||||
VT_Boolean,
|
||||
VT_Double,
|
||||
VT_Unsigned,
|
||||
VT_String,
|
||||
VT_Matcher
|
||||
|
@ -311,6 +332,8 @@ private:
|
|||
/// \brief All supported value types.
|
||||
union AllValues {
|
||||
unsigned Unsigned;
|
||||
double Double;
|
||||
bool Boolean;
|
||||
std::string *String;
|
||||
VariantMatcher *Matcher;
|
||||
};
|
||||
|
|
|
@ -38,15 +38,15 @@ typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode;
|
|||
class DominatorTree : public ManagedAnalysis {
|
||||
virtual void anchor();
|
||||
public:
|
||||
llvm::DominatorTreeBase<CFGBlock>* DT;
|
||||
llvm::DomTreeBase<CFGBlock>* DT;
|
||||
|
||||
DominatorTree() {
|
||||
DT = new llvm::DominatorTreeBase<CFGBlock>(false);
|
||||
DT = new llvm::DomTreeBase<CFGBlock>();
|
||||
}
|
||||
|
||||
~DominatorTree() override { delete DT; }
|
||||
|
||||
llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; }
|
||||
llvm::DomTreeBase<CFGBlock>& getBase() { return *DT; }
|
||||
|
||||
/// \brief This method returns the root CFGBlock of the dominators tree.
|
||||
///
|
||||
|
|
|
@ -426,6 +426,7 @@ public:
|
|||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false,
|
||||
bool addTemporaryDtors = false,
|
||||
bool addLifetime = false,
|
||||
bool synthesizeBodies = false,
|
||||
bool addStaticInitBranches = false,
|
||||
bool addCXXNewAllocator = true,
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
Statement,
|
||||
Initializer,
|
||||
NewAllocator,
|
||||
LifetimeEnds,
|
||||
// dtor kind
|
||||
AutomaticObjectDtor,
|
||||
DeleteDtor,
|
||||
|
@ -167,6 +168,28 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/// Represents the point where the lifetime of an automatic object ends
|
||||
class CFGLifetimeEnds : public CFGElement {
|
||||
public:
|
||||
explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt)
|
||||
: CFGElement(LifetimeEnds, var, stmt) {}
|
||||
|
||||
const VarDecl *getVarDecl() const {
|
||||
return static_cast<VarDecl *>(Data1.getPointer());
|
||||
}
|
||||
|
||||
const Stmt *getTriggerStmt() const {
|
||||
return static_cast<Stmt *>(Data2.getPointer());
|
||||
}
|
||||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGLifetimeEnds() {}
|
||||
static bool isKind(const CFGElement &elem) {
|
||||
return elem.getKind() == LifetimeEnds;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGImplicitDtor - Represents C++ object destructor implicitly generated
|
||||
/// by compiler on various occasions.
|
||||
class CFGImplicitDtor : public CFGElement {
|
||||
|
@ -701,6 +724,10 @@ public:
|
|||
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
|
||||
}
|
||||
|
||||
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGLifetimeEnds(VD, S), C);
|
||||
}
|
||||
|
||||
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGDeleteDtor(RD, DE), C);
|
||||
}
|
||||
|
@ -717,6 +744,19 @@ public:
|
|||
*I = CFGAutomaticObjDtor(VD, S);
|
||||
return ++I;
|
||||
}
|
||||
|
||||
// Scope leaving must be performed in reversed order. So insertion is in two
|
||||
// steps. First we prepare space for some number of elements, then we insert
|
||||
// the elements beginning at the last position in prepared space.
|
||||
iterator beginLifetimeEndsInsert(iterator I, size_t Cnt,
|
||||
BumpVectorContext &C) {
|
||||
return iterator(
|
||||
Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C));
|
||||
}
|
||||
iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) {
|
||||
*I = CFGLifetimeEnds(VD, S);
|
||||
return ++I;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief CFGCallback defines methods that should be called when a logical
|
||||
|
@ -753,6 +793,7 @@ public:
|
|||
bool AddEHEdges;
|
||||
bool AddInitializers;
|
||||
bool AddImplicitDtors;
|
||||
bool AddLifetime;
|
||||
bool AddTemporaryDtors;
|
||||
bool AddStaticInitBranches;
|
||||
bool AddCXXNewAllocator;
|
||||
|
@ -774,8 +815,10 @@ public:
|
|||
|
||||
BuildOptions()
|
||||
: forcedBlkExprs(nullptr), Observer(nullptr),
|
||||
PruneTriviallyFalseEdges(true), AddEHEdges(false),
|
||||
PruneTriviallyFalseEdges(true),
|
||||
AddEHEdges(false),
|
||||
AddInitializers(false), AddImplicitDtors(false),
|
||||
AddLifetime(false),
|
||||
AddTemporaryDtors(false), AddStaticInitBranches(false),
|
||||
AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {}
|
||||
};
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
bool VisitFunctionDecl(FunctionDecl *FD) {
|
||||
// We skip function template definitions, as their semantics is
|
||||
// only determined when they are instantiated.
|
||||
if (includeInGraph(FD)) {
|
||||
if (includeInGraph(FD) && FD->isThisDeclarationADefinition()) {
|
||||
// Add all blocks declared inside this function to the graph.
|
||||
addNodesForBlocks(FD);
|
||||
// If this function has external linkage, anything could call it.
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
#ifndef LLVM_CLANG_AST_CLONEDETECTION_H
|
||||
#define LLVM_CLANG_AST_CLONEDETECTION_H
|
||||
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
@ -29,7 +31,193 @@ class VarDecl;
|
|||
class ASTContext;
|
||||
class CompoundStmt;
|
||||
|
||||
/// \brief Identifies a list of statements.
|
||||
namespace clone_detection {
|
||||
|
||||
/// Returns a string that represents all macro expansions that expanded into the
|
||||
/// given SourceLocation.
|
||||
///
|
||||
/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations
|
||||
/// A and B are expanded from the same macros in the same order.
|
||||
std::string getMacroStack(SourceLocation Loc, ASTContext &Context);
|
||||
|
||||
/// Collects the data of a single Stmt.
|
||||
///
|
||||
/// This class defines what a code clone is: If it collects for two statements
|
||||
/// the same data, then those two statements are considered to be clones of each
|
||||
/// other.
|
||||
///
|
||||
/// All collected data is forwarded to the given data consumer of the type T.
|
||||
/// The data consumer class needs to provide a member method with the signature:
|
||||
/// update(StringRef Str)
|
||||
template <typename T>
|
||||
class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> {
|
||||
|
||||
ASTContext &Context;
|
||||
/// The data sink to which all data is forwarded.
|
||||
T &DataConsumer;
|
||||
|
||||
public:
|
||||
/// Collects data of the given Stmt.
|
||||
/// \param S The given statement.
|
||||
/// \param Context The ASTContext of S.
|
||||
/// \param DataConsumer The data sink to which all data is forwarded.
|
||||
StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer)
|
||||
: Context(Context), DataConsumer(DataConsumer) {
|
||||
this->Visit(S);
|
||||
}
|
||||
|
||||
typedef unsigned DataPiece;
|
||||
|
||||
// Below are utility methods for appending different data to the vector.
|
||||
|
||||
void addData(DataPiece Integer) {
|
||||
DataConsumer.update(
|
||||
StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer)));
|
||||
}
|
||||
|
||||
void addData(llvm::StringRef Str) { DataConsumer.update(Str); }
|
||||
|
||||
void addData(const QualType &QT) { addData(QT.getAsString()); }
|
||||
|
||||
// The functions below collect the class specific data of each Stmt subclass.
|
||||
|
||||
// Utility macro for defining a visit method for a given class. This method
|
||||
// calls back to the ConstStmtVisitor to visit all parent classes.
|
||||
#define DEF_ADD_DATA(CLASS, CODE) \
|
||||
void Visit##CLASS(const CLASS *S) { \
|
||||
CODE; \
|
||||
ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
|
||||
}
|
||||
|
||||
DEF_ADD_DATA(Stmt, {
|
||||
addData(S->getStmtClass());
|
||||
// This ensures that macro generated code isn't identical to macro-generated
|
||||
// code.
|
||||
addData(getMacroStack(S->getLocStart(), Context));
|
||||
addData(getMacroStack(S->getLocEnd(), Context));
|
||||
})
|
||||
DEF_ADD_DATA(Expr, { addData(S->getType()); })
|
||||
|
||||
//--- Builtin functionality ----------------------------------------------//
|
||||
DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); })
|
||||
DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); })
|
||||
DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); })
|
||||
DEF_ADD_DATA(TypeTraitExpr, {
|
||||
addData(S->getTrait());
|
||||
for (unsigned i = 0; i < S->getNumArgs(); ++i)
|
||||
addData(S->getArg(i)->getType());
|
||||
})
|
||||
|
||||
//--- Calls --------------------------------------------------------------//
|
||||
DEF_ADD_DATA(CallExpr, {
|
||||
// Function pointers don't have a callee and we just skip hashing it.
|
||||
if (const FunctionDecl *D = S->getDirectCallee()) {
|
||||
// If the function is a template specialization, we also need to handle
|
||||
// the template arguments as they are not included in the qualified name.
|
||||
if (auto Args = D->getTemplateSpecializationArgs()) {
|
||||
std::string ArgString;
|
||||
|
||||
// Print all template arguments into ArgString
|
||||
llvm::raw_string_ostream OS(ArgString);
|
||||
for (unsigned i = 0; i < Args->size(); ++i) {
|
||||
Args->get(i).print(Context.getLangOpts(), OS);
|
||||
// Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
|
||||
OS << '\n';
|
||||
}
|
||||
OS.flush();
|
||||
|
||||
addData(ArgString);
|
||||
}
|
||||
addData(D->getQualifiedNameAsString());
|
||||
}
|
||||
})
|
||||
|
||||
//--- Exceptions ---------------------------------------------------------//
|
||||
DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); })
|
||||
|
||||
//--- C++ OOP Stmts ------------------------------------------------------//
|
||||
DEF_ADD_DATA(CXXDeleteExpr, {
|
||||
addData(S->isArrayFormAsWritten());
|
||||
addData(S->isGlobalDelete());
|
||||
})
|
||||
|
||||
//--- Casts --------------------------------------------------------------//
|
||||
DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); })
|
||||
|
||||
//--- Miscellaneous Exprs ------------------------------------------------//
|
||||
DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); })
|
||||
DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); })
|
||||
|
||||
//--- Control flow -------------------------------------------------------//
|
||||
DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); })
|
||||
DEF_ADD_DATA(IndirectGotoStmt, {
|
||||
if (S->getConstantTarget())
|
||||
addData(S->getConstantTarget()->getName());
|
||||
})
|
||||
DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); })
|
||||
DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); })
|
||||
DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); })
|
||||
|
||||
//--- Objective-C --------------------------------------------------------//
|
||||
DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); })
|
||||
DEF_ADD_DATA(ObjCPropertyRefExpr, {
|
||||
addData(S->isSuperReceiver());
|
||||
addData(S->isImplicitProperty());
|
||||
})
|
||||
DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); })
|
||||
|
||||
//--- Miscellaneous Stmts ------------------------------------------------//
|
||||
DEF_ADD_DATA(CXXFoldExpr, {
|
||||
addData(S->isRightFold());
|
||||
addData(S->getOperator());
|
||||
})
|
||||
DEF_ADD_DATA(GenericSelectionExpr, {
|
||||
for (unsigned i = 0; i < S->getNumAssocs(); ++i) {
|
||||
addData(S->getAssocType(i));
|
||||
}
|
||||
})
|
||||
DEF_ADD_DATA(LambdaExpr, {
|
||||
for (const LambdaCapture &C : S->captures()) {
|
||||
addData(C.isPackExpansion());
|
||||
addData(C.getCaptureKind());
|
||||
if (C.capturesVariable())
|
||||
addData(C.getCapturedVar()->getType());
|
||||
}
|
||||
addData(S->isGenericLambda());
|
||||
addData(S->isMutable());
|
||||
})
|
||||
DEF_ADD_DATA(DeclStmt, {
|
||||
auto numDecls = std::distance(S->decl_begin(), S->decl_end());
|
||||
addData(static_cast<DataPiece>(numDecls));
|
||||
for (const Decl *D : S->decls()) {
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
||||
addData(VD->getType());
|
||||
}
|
||||
}
|
||||
})
|
||||
DEF_ADD_DATA(AsmStmt, {
|
||||
addData(S->isSimple());
|
||||
addData(S->isVolatile());
|
||||
addData(S->generateAsmString(Context));
|
||||
for (unsigned i = 0; i < S->getNumInputs(); ++i) {
|
||||
addData(S->getInputConstraint(i));
|
||||
}
|
||||
for (unsigned i = 0; i < S->getNumOutputs(); ++i) {
|
||||
addData(S->getOutputConstraint(i));
|
||||
}
|
||||
for (unsigned i = 0; i < S->getNumClobbers(); ++i) {
|
||||
addData(S->getClobber(i));
|
||||
}
|
||||
})
|
||||
DEF_ADD_DATA(AttributedStmt, {
|
||||
for (const Attr *A : S->getAttrs()) {
|
||||
addData(std::string(A->getSpelling()));
|
||||
}
|
||||
})
|
||||
};
|
||||
} // namespace clone_detection
|
||||
|
||||
/// Identifies a list of statements.
|
||||
///
|
||||
/// Can either identify a single arbitrary Stmt object, a continuous sequence of
|
||||
/// child statements inside a CompoundStmt or no statements at all.
|
||||
|
@ -39,8 +227,8 @@ class StmtSequence {
|
|||
/// Stmt, then S is a pointer to this Stmt.
|
||||
const Stmt *S;
|
||||
|
||||
/// The related ASTContext for S.
|
||||
ASTContext *Context;
|
||||
/// The declaration that contains the statements.
|
||||
const Decl *D;
|
||||
|
||||
/// If EndIndex is non-zero, then S is a CompoundStmt and this StmtSequence
|
||||
/// instance is representing the CompoundStmt children inside the array
|
||||
|
@ -49,7 +237,7 @@ class StmtSequence {
|
|||
unsigned EndIndex;
|
||||
|
||||
public:
|
||||
/// \brief Constructs a StmtSequence holding multiple statements.
|
||||
/// Constructs a StmtSequence holding multiple statements.
|
||||
///
|
||||
/// The resulting StmtSequence identifies a continuous sequence of statements
|
||||
/// in the body of the given CompoundStmt. Which statements of the body should
|
||||
|
@ -57,20 +245,20 @@ public:
|
|||
/// that describe a non-empty sub-array in the body of the given CompoundStmt.
|
||||
///
|
||||
/// \param Stmt A CompoundStmt that contains all statements in its body.
|
||||
/// \param Context The ASTContext for the given CompoundStmt.
|
||||
/// \param D The Decl containing this Stmt.
|
||||
/// \param StartIndex The inclusive start index in the children array of
|
||||
/// \p Stmt
|
||||
/// \param EndIndex The exclusive end index in the children array of \p Stmt.
|
||||
StmtSequence(const CompoundStmt *Stmt, ASTContext &Context,
|
||||
unsigned StartIndex, unsigned EndIndex);
|
||||
StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex,
|
||||
unsigned EndIndex);
|
||||
|
||||
/// \brief Constructs a StmtSequence holding a single statement.
|
||||
/// Constructs a StmtSequence holding a single statement.
|
||||
///
|
||||
/// \param Stmt An arbitrary Stmt.
|
||||
/// \param Context The ASTContext for the given Stmt.
|
||||
StmtSequence(const Stmt *Stmt, ASTContext &Context);
|
||||
/// \param D The Decl containing this Stmt.
|
||||
StmtSequence(const Stmt *Stmt, const Decl *D);
|
||||
|
||||
/// \brief Constructs an empty StmtSequence.
|
||||
/// Constructs an empty StmtSequence.
|
||||
StmtSequence();
|
||||
|
||||
typedef const Stmt *const *iterator;
|
||||
|
@ -110,9 +298,12 @@ public:
|
|||
bool empty() const { return size() == 0; }
|
||||
|
||||
/// Returns the related ASTContext for the stored Stmts.
|
||||
ASTContext &getASTContext() const {
|
||||
assert(Context);
|
||||
return *Context;
|
||||
ASTContext &getASTContext() const;
|
||||
|
||||
/// Returns the declaration that contains the stored Stmts.
|
||||
const Decl *getContainingDecl() const {
|
||||
assert(D);
|
||||
return D;
|
||||
}
|
||||
|
||||
/// Returns true if this objects holds a list of statements.
|
||||
|
@ -150,106 +341,235 @@ public:
|
|||
bool contains(const StmtSequence &Other) const;
|
||||
};
|
||||
|
||||
/// \brief Searches for clones in source code.
|
||||
/// Searches for similar subtrees in the AST.
|
||||
///
|
||||
/// First, this class needs a translation unit which is passed via
|
||||
/// \p analyzeTranslationUnit . It will then generate and store search data
|
||||
/// for all statements inside the given translation unit.
|
||||
/// Afterwards the generated data can be used to find code clones by calling
|
||||
/// \p findClones .
|
||||
/// First, this class needs several declarations with statement bodies which
|
||||
/// can be passed via analyzeCodeBody. Afterwards all statements can be
|
||||
/// searched for clones by calling findClones with a given list of constraints
|
||||
/// that should specify the wanted properties of the clones.
|
||||
///
|
||||
/// The result of findClones can be further constrained with the constrainClones
|
||||
/// method.
|
||||
///
|
||||
/// This class only searches for clones in exectuable source code
|
||||
/// (e.g. function bodies). Other clones (e.g. cloned comments or declarations)
|
||||
/// are not supported.
|
||||
class CloneDetector {
|
||||
|
||||
public:
|
||||
typedef unsigned DataPiece;
|
||||
/// A collection of StmtSequences that share an arbitrary property.
|
||||
typedef llvm::SmallVector<StmtSequence, 8> CloneGroup;
|
||||
|
||||
/// Holds the data about a StmtSequence that is needed during the search for
|
||||
/// code clones.
|
||||
struct CloneSignature {
|
||||
/// \brief The hash code of the StmtSequence.
|
||||
///
|
||||
/// The initial clone groups that are formed during the search for clones
|
||||
/// consist only of Sequences that share the same hash code. This makes this
|
||||
/// value the central part of this heuristic that is needed to find clones
|
||||
/// in a performant way. For this to work, the type of this variable
|
||||
/// always needs to be small and fast to compare.
|
||||
///
|
||||
/// Also, StmtSequences that are clones of each others have to share
|
||||
/// the same hash code. StmtSequences that are not clones of each other
|
||||
/// shouldn't share the same hash code, but if they do, it will only
|
||||
/// degrade the performance of the hash search but doesn't influence
|
||||
/// the correctness of the result.
|
||||
size_t Hash;
|
||||
|
||||
/// \brief The complexity of the StmtSequence.
|
||||
///
|
||||
/// This value gives an approximation on how many direct or indirect child
|
||||
/// statements are contained in the related StmtSequence. In general, the
|
||||
/// greater this value, the greater the amount of statements. However, this
|
||||
/// is only an approximation and the actual amount of statements can be
|
||||
/// higher or lower than this value. Statements that are generated by the
|
||||
/// compiler (e.g. macro expansions) for example barely influence the
|
||||
/// complexity value.
|
||||
///
|
||||
/// The main purpose of this value is to filter clones that are too small
|
||||
/// and therefore probably not interesting enough for the user.
|
||||
unsigned Complexity;
|
||||
|
||||
/// \brief Creates an empty CloneSignature without any data.
|
||||
CloneSignature() : Complexity(1) {}
|
||||
|
||||
CloneSignature(llvm::hash_code Hash, unsigned Complexity)
|
||||
: Hash(Hash), Complexity(Complexity) {}
|
||||
};
|
||||
|
||||
/// Holds group of StmtSequences that are clones of each other and the
|
||||
/// complexity value (see CloneSignature::Complexity) that all stored
|
||||
/// StmtSequences have in common.
|
||||
struct CloneGroup {
|
||||
std::vector<StmtSequence> Sequences;
|
||||
CloneSignature Signature;
|
||||
|
||||
CloneGroup() {}
|
||||
|
||||
CloneGroup(const StmtSequence &Seq, CloneSignature Signature)
|
||||
: Signature(Signature) {
|
||||
Sequences.push_back(Seq);
|
||||
}
|
||||
|
||||
/// \brief Returns false if and only if this group should be skipped when
|
||||
/// searching for clones.
|
||||
bool isValid() const {
|
||||
// A clone group with only one member makes no sense, so we skip them.
|
||||
return Sequences.size() > 1;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Generates and stores search data for all statements in the body of
|
||||
/// the given Decl.
|
||||
/// Generates and stores search data for all statements in the body of
|
||||
/// the given Decl.
|
||||
void analyzeCodeBody(const Decl *D);
|
||||
|
||||
/// \brief Stores the CloneSignature to allow future querying.
|
||||
void add(const StmtSequence &S, const CloneSignature &Signature);
|
||||
|
||||
/// \brief Searches the provided statements for clones.
|
||||
/// Constrains the given list of clone groups with the given constraint.
|
||||
///
|
||||
/// \param Result Output parameter that is filled with a list of found
|
||||
/// clone groups. Each group contains multiple StmtSequences
|
||||
/// that were identified to be clones of each other.
|
||||
/// \param MinGroupComplexity Only return clones which have at least this
|
||||
/// complexity value.
|
||||
/// \param CheckPatterns Returns only clone groups in which the referenced
|
||||
/// variables follow the same pattern.
|
||||
void findClones(std::vector<CloneGroup> &Result, unsigned MinGroupComplexity,
|
||||
bool CheckPatterns = true);
|
||||
/// The constraint is expected to have a method with the signature
|
||||
/// `void constrain(std::vector<CloneDetector::CloneGroup> &Sequences)`
|
||||
/// as this is the interface that the CloneDetector uses for applying the
|
||||
/// constraint. The constraint is supposed to directly modify the passed list
|
||||
/// so that all clones in the list fulfill the specific property this
|
||||
/// constraint ensures.
|
||||
template <typename T>
|
||||
static void constrainClones(std::vector<CloneGroup> &CloneGroups, T C) {
|
||||
C.constrain(CloneGroups);
|
||||
}
|
||||
|
||||
/// \brief Describes two clones that reference their variables in a different
|
||||
/// pattern which could indicate a programming error.
|
||||
/// Constrains the given list of clone groups with the given list of
|
||||
/// constraints.
|
||||
///
|
||||
/// The constraints are applied in sequence in the order in which they are
|
||||
/// passed to this function.
|
||||
template <typename T1, typename... Ts>
|
||||
static void constrainClones(std::vector<CloneGroup> &CloneGroups, T1 C,
|
||||
Ts... ConstraintList) {
|
||||
constrainClones(CloneGroups, C);
|
||||
constrainClones(CloneGroups, ConstraintList...);
|
||||
}
|
||||
|
||||
/// Searches for clones in all previously passed statements.
|
||||
/// \param Result Output parameter to which all created clone groups are
|
||||
/// added.
|
||||
/// \param ConstraintList The constraints that should be applied to the
|
||||
// result.
|
||||
template <typename... Ts>
|
||||
void findClones(std::vector<CloneGroup> &Result, Ts... ConstraintList) {
|
||||
// The initial assumption is that there is only one clone group and every
|
||||
// statement is a clone of the others. This clone group will then be
|
||||
// split up with the help of the constraints.
|
||||
CloneGroup AllClones;
|
||||
AllClones.reserve(Sequences.size());
|
||||
for (const auto &C : Sequences) {
|
||||
AllClones.push_back(C);
|
||||
}
|
||||
|
||||
Result.push_back(AllClones);
|
||||
|
||||
constrainClones(Result, ConstraintList...);
|
||||
}
|
||||
|
||||
private:
|
||||
CloneGroup Sequences;
|
||||
};
|
||||
|
||||
/// This class is a utility class that contains utility functions for building
|
||||
/// custom constraints.
|
||||
class CloneConstraint {
|
||||
public:
|
||||
/// Removes all groups by using a filter function.
|
||||
/// \param CloneGroups The list of CloneGroups that is supposed to be
|
||||
/// filtered.
|
||||
/// \param Filter The filter function that should return true for all groups
|
||||
/// that should be removed from the list.
|
||||
static void
|
||||
filterGroups(std::vector<CloneDetector::CloneGroup> &CloneGroups,
|
||||
std::function<bool(const CloneDetector::CloneGroup &)> Filter) {
|
||||
CloneGroups.erase(
|
||||
std::remove_if(CloneGroups.begin(), CloneGroups.end(), Filter),
|
||||
CloneGroups.end());
|
||||
}
|
||||
|
||||
/// Splits the given CloneGroups until the given Compare function returns true
|
||||
/// for all clones in a single group.
|
||||
/// \param CloneGroups A list of CloneGroups that should be modified.
|
||||
/// \param Compare The comparison function that all clones are supposed to
|
||||
/// pass. Should return true if and only if two clones belong
|
||||
/// to the same CloneGroup.
|
||||
static void splitCloneGroups(
|
||||
std::vector<CloneDetector::CloneGroup> &CloneGroups,
|
||||
std::function<bool(const StmtSequence &, const StmtSequence &)> Compare);
|
||||
};
|
||||
|
||||
/// Searches all children of the given clones for type II clones (i.e. they are
|
||||
/// identical in every aspect beside the used variable names).
|
||||
class RecursiveCloneTypeIIConstraint {
|
||||
|
||||
/// Generates and saves a hash code for the given Stmt.
|
||||
/// \param S The given Stmt.
|
||||
/// \param D The Decl containing S.
|
||||
/// \param StmtsByHash Output parameter that will contain the hash codes for
|
||||
/// each StmtSequence in the given Stmt.
|
||||
/// \return The hash code of the given Stmt.
|
||||
///
|
||||
/// If the given Stmt is a CompoundStmt, this method will also generate
|
||||
/// hashes for all possible StmtSequences in the children of this Stmt.
|
||||
size_t saveHash(const Stmt *S, const Decl *D,
|
||||
std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash);
|
||||
|
||||
public:
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &Sequences);
|
||||
};
|
||||
|
||||
/// Ensures that every clone has at least the given complexity.
|
||||
///
|
||||
/// Complexity is here defined as the total amount of children of a statement.
|
||||
/// This constraint assumes the first statement in the group is representative
|
||||
/// for all other statements in the group in terms of complexity.
|
||||
class MinComplexityConstraint {
|
||||
unsigned MinComplexity;
|
||||
|
||||
public:
|
||||
MinComplexityConstraint(unsigned MinComplexity)
|
||||
: MinComplexity(MinComplexity) {}
|
||||
|
||||
size_t calculateStmtComplexity(const StmtSequence &Seq,
|
||||
const std::string &ParentMacroStack = "");
|
||||
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
|
||||
CloneConstraint::filterGroups(
|
||||
CloneGroups, [this](const CloneDetector::CloneGroup &A) {
|
||||
if (!A.empty())
|
||||
return calculateStmtComplexity(A.front()) < MinComplexity;
|
||||
else
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// Ensures that all clone groups contain at least the given amount of clones.
|
||||
class MinGroupSizeConstraint {
|
||||
unsigned MinGroupSize;
|
||||
|
||||
public:
|
||||
MinGroupSizeConstraint(unsigned MinGroupSize = 2)
|
||||
: MinGroupSize(MinGroupSize) {}
|
||||
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
|
||||
CloneConstraint::filterGroups(CloneGroups,
|
||||
[this](const CloneDetector::CloneGroup &A) {
|
||||
return A.size() < MinGroupSize;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// Ensures that no clone group fully contains another clone group.
|
||||
struct OnlyLargestCloneConstraint {
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &Result);
|
||||
};
|
||||
|
||||
struct FilenamePatternConstraint {
|
||||
StringRef IgnoredFilesPattern;
|
||||
std::shared_ptr<llvm::Regex> IgnoredFilesRegex;
|
||||
|
||||
FilenamePatternConstraint(StringRef IgnoredFilesPattern)
|
||||
: IgnoredFilesPattern(IgnoredFilesPattern) {
|
||||
IgnoredFilesRegex = std::make_shared<llvm::Regex>("^(" +
|
||||
IgnoredFilesPattern.str() + "$)");
|
||||
}
|
||||
|
||||
bool isAutoGenerated(const CloneDetector::CloneGroup &Group);
|
||||
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
|
||||
CloneConstraint::filterGroups(
|
||||
CloneGroups, [this](const CloneDetector::CloneGroup &Group) {
|
||||
return isAutoGenerated(Group);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// Analyzes the pattern of the referenced variables in a statement.
|
||||
class VariablePattern {
|
||||
|
||||
/// Describes an occurence of a variable reference in a statement.
|
||||
struct VariableOccurence {
|
||||
/// The index of the associated VarDecl in the Variables vector.
|
||||
size_t KindID;
|
||||
/// The statement in the code where the variable was referenced.
|
||||
const Stmt *Mention;
|
||||
|
||||
VariableOccurence(size_t KindID, const Stmt *Mention)
|
||||
: KindID(KindID), Mention(Mention) {}
|
||||
};
|
||||
|
||||
/// All occurences of referenced variables in the order of appearance.
|
||||
std::vector<VariableOccurence> Occurences;
|
||||
/// List of referenced variables in the order of appearance.
|
||||
/// Every item in this list is unique.
|
||||
std::vector<const VarDecl *> Variables;
|
||||
|
||||
/// Adds a new variable referenced to this pattern.
|
||||
/// \param VarDecl The declaration of the variable that is referenced.
|
||||
/// \param Mention The SourceRange where this variable is referenced.
|
||||
void addVariableOccurence(const VarDecl *VarDecl, const Stmt *Mention);
|
||||
|
||||
/// Adds each referenced variable from the given statement.
|
||||
void addVariables(const Stmt *S);
|
||||
|
||||
public:
|
||||
/// Creates an VariablePattern object with information about the given
|
||||
/// StmtSequence.
|
||||
VariablePattern(const StmtSequence &Sequence) {
|
||||
for (const Stmt *S : Sequence)
|
||||
addVariables(S);
|
||||
}
|
||||
|
||||
/// Describes two clones that reference their variables in a different pattern
|
||||
/// which could indicate a programming error.
|
||||
struct SuspiciousClonePair {
|
||||
/// \brief Utility class holding the relevant information about a single
|
||||
/// clone in this pair.
|
||||
/// Utility class holding the relevant information about a single
|
||||
/// clone in this pair.
|
||||
struct SuspiciousCloneInfo {
|
||||
/// The variable which referencing in this clone was against the pattern.
|
||||
const VarDecl *Variable;
|
||||
|
@ -270,17 +590,37 @@ public:
|
|||
SuspiciousCloneInfo SecondCloneInfo;
|
||||
};
|
||||
|
||||
/// \brief Searches the provided statements for pairs of clones that don't
|
||||
/// follow the same pattern when referencing variables.
|
||||
/// \param Result Output parameter that will contain the clone pairs.
|
||||
/// \param MinGroupComplexity Only clone pairs in which the clones have at
|
||||
/// least this complexity value.
|
||||
void findSuspiciousClones(std::vector<SuspiciousClonePair> &Result,
|
||||
unsigned MinGroupComplexity);
|
||||
/// Counts the differences between this pattern and the given one.
|
||||
/// \param Other The given VariablePattern to compare with.
|
||||
/// \param FirstMismatch Output parameter that will be filled with information
|
||||
/// about the first difference between the two patterns. This parameter
|
||||
/// can be a nullptr, in which case it will be ignored.
|
||||
/// \return Returns the number of differences between the pattern this object
|
||||
/// is following and the given VariablePattern.
|
||||
///
|
||||
/// For example, the following statements all have the same pattern and this
|
||||
/// function would return zero:
|
||||
///
|
||||
/// if (a < b) return a; return b;
|
||||
/// if (x < y) return x; return y;
|
||||
/// if (u2 < u1) return u2; return u1;
|
||||
///
|
||||
/// But the following statement has a different pattern (note the changed
|
||||
/// variables in the return statements) and would have two differences when
|
||||
/// compared with one of the statements above.
|
||||
///
|
||||
/// if (a < b) return b; return a;
|
||||
///
|
||||
/// This function should only be called if the related statements of the given
|
||||
/// pattern and the statements of this objects are clones of each other.
|
||||
unsigned countPatternDifferences(
|
||||
const VariablePattern &Other,
|
||||
VariablePattern::SuspiciousClonePair *FirstMismatch = nullptr);
|
||||
};
|
||||
|
||||
private:
|
||||
/// Stores all encountered StmtSequences alongside their CloneSignature.
|
||||
std::vector<std::pair<CloneSignature, StmtSequence>> Sequences;
|
||||
/// Ensures that all clones reference variables in the same pattern.
|
||||
struct MatchingVariablePatternConstraint {
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -20,30 +20,37 @@ namespace clang {
|
|||
|
||||
namespace LangAS {
|
||||
|
||||
/// \brief Defines the set of possible language-specific address spaces.
|
||||
/// \brief Defines the address space values used by the address space qualifier
|
||||
/// of QualType.
|
||||
///
|
||||
/// This uses a high starting offset so as not to conflict with any address
|
||||
/// space used by a target.
|
||||
enum ID {
|
||||
Offset = 0x7FFF00,
|
||||
// The default value 0 is the value used in QualType for the the situation
|
||||
// where there is no address space qualifier. For most languages, this also
|
||||
// corresponds to the situation where there is no address space qualifier in
|
||||
// the source code, except for OpenCL, where the address space value 0 in
|
||||
// QualType represents private address space in OpenCL source code.
|
||||
Default = 0,
|
||||
|
||||
opencl_global = Offset,
|
||||
// OpenCL specific address spaces.
|
||||
opencl_global,
|
||||
opencl_local,
|
||||
opencl_constant,
|
||||
opencl_generic,
|
||||
|
||||
// CUDA specific address spaces.
|
||||
cuda_device,
|
||||
cuda_constant,
|
||||
cuda_shared,
|
||||
|
||||
Last,
|
||||
Count = Last-Offset
|
||||
// This denotes the count of language-specific address spaces and also
|
||||
// the offset added to the target-specific address spaces, which are usually
|
||||
// specified by address space attributes __attribute__(address_space(n))).
|
||||
FirstTargetAddressSpace
|
||||
};
|
||||
|
||||
/// The type of a lookup table which maps from language-specific address spaces
|
||||
/// to target-specific ones.
|
||||
typedef unsigned Map[Count];
|
||||
|
||||
typedef unsigned Map[FirstTargetAddressSpace];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
namespace clang {
|
||||
template <size_t SizeOfStr, typename FieldType>
|
||||
class StringSizerHelper {
|
||||
char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
|
||||
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
|
||||
public:
|
||||
enum { Size = SizeOfStr };
|
||||
};
|
||||
|
|
|
@ -149,6 +149,9 @@ class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
|
|||
class FunctionArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
|
||||
opt,
|
||||
fake>;
|
||||
class NamedArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
|
||||
opt,
|
||||
fake>;
|
||||
class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
|
||||
|
@ -248,6 +251,8 @@ def COnly : LangOpt<"CPlusPlus", 1>;
|
|||
def CPlusPlus : LangOpt<"CPlusPlus">;
|
||||
def OpenCL : LangOpt<"OpenCL">;
|
||||
def RenderScript : LangOpt<"RenderScript">;
|
||||
def ObjC : LangOpt<"ObjC1">;
|
||||
def BlocksSupported : LangOpt<"Blocks">;
|
||||
|
||||
// Defines targets for target-specific attributes. The list of strings should
|
||||
// specify architectures for which the target applies, based off the ArchType
|
||||
|
@ -258,6 +263,7 @@ class TargetArch<list<string> arches> {
|
|||
list<string> CXXABIs;
|
||||
}
|
||||
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
|
||||
def TargetAVR : TargetArch<["avr"]>;
|
||||
def TargetMips : TargetArch<["mips", "mipsel"]>;
|
||||
def TargetMSP430 : TargetArch<["msp430"]>;
|
||||
def TargetX86 : TargetArch<["x86"]>;
|
||||
|
@ -269,6 +275,112 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
|
|||
let CXXABIs = ["Microsoft"];
|
||||
}
|
||||
|
||||
// Attribute subject match rules that are used for #pragma clang attribute.
|
||||
//
|
||||
// A instance of AttrSubjectMatcherRule represents an individual match rule.
|
||||
// An individual match rule can correspond to a number of different attribute
|
||||
// subjects, e.g. "record" matching rule corresponds to the Record and
|
||||
// CXXRecord attribute subjects.
|
||||
//
|
||||
// Match rules are used in the subject list of the #pragma clang attribute.
|
||||
// Match rules can have sub-match rules that are instances of
|
||||
// AttrSubjectMatcherSubRule. A sub-match rule can correspond to a number
|
||||
// of different attribute subjects, and it can have a negated spelling as well.
|
||||
// For example, "variable(unless(is_parameter))" matching rule corresponds to
|
||||
// the NonParmVar attribute subject.
|
||||
class AttrSubjectMatcherSubRule<string name, list<AttrSubject> subjects,
|
||||
bit negated = 0> {
|
||||
string Name = name;
|
||||
list<AttrSubject> Subjects = subjects;
|
||||
bit Negated = negated;
|
||||
// Lists language options, one of which is required to be true for the
|
||||
// attribute to be applicable. If empty, the language options are taken
|
||||
// from the parent matcher rule.
|
||||
list<LangOpt> LangOpts = [];
|
||||
}
|
||||
class AttrSubjectMatcherRule<string name, list<AttrSubject> subjects,
|
||||
list<AttrSubjectMatcherSubRule> subrules = []> {
|
||||
string Name = name;
|
||||
list<AttrSubject> Subjects = subjects;
|
||||
list<AttrSubjectMatcherSubRule> Constraints = subrules;
|
||||
// Lists language options, one of which is required to be true for the
|
||||
// attribute to be applicable. If empty, no language options are required.
|
||||
list<LangOpt> LangOpts = [];
|
||||
}
|
||||
|
||||
// function(is_member)
|
||||
def SubRuleForCXXMethod : AttrSubjectMatcherSubRule<"is_member", [CXXMethod]> {
|
||||
let LangOpts = [CPlusPlus];
|
||||
}
|
||||
def SubjectMatcherForFunction : AttrSubjectMatcherRule<"function", [Function], [
|
||||
SubRuleForCXXMethod
|
||||
]>;
|
||||
// hasType is abstract, it should be used with one of the sub-rules.
|
||||
def SubjectMatcherForType : AttrSubjectMatcherRule<"hasType", [], [
|
||||
AttrSubjectMatcherSubRule<"functionType", [FunctionLike]>
|
||||
|
||||
// FIXME: There's a matcher ambiguity with objc methods and blocks since
|
||||
// functionType excludes them but functionProtoType includes them.
|
||||
// AttrSubjectMatcherSubRule<"functionProtoType", [HasFunctionProto]>
|
||||
]>;
|
||||
def SubjectMatcherForTypedef : AttrSubjectMatcherRule<"type_alias",
|
||||
[TypedefName]>;
|
||||
def SubjectMatcherForRecord : AttrSubjectMatcherRule<"record", [Record,
|
||||
CXXRecord], [
|
||||
// unless(is_union)
|
||||
AttrSubjectMatcherSubRule<"is_union", [Struct], 1>
|
||||
]>;
|
||||
def SubjectMatcherForEnum : AttrSubjectMatcherRule<"enum", [Enum]>;
|
||||
def SubjectMatcherForEnumConstant : AttrSubjectMatcherRule<"enum_constant",
|
||||
[EnumConstant]>;
|
||||
def SubjectMatcherForVar : AttrSubjectMatcherRule<"variable", [Var], [
|
||||
AttrSubjectMatcherSubRule<"is_thread_local", [TLSVar]>,
|
||||
AttrSubjectMatcherSubRule<"is_global", [GlobalVar]>,
|
||||
AttrSubjectMatcherSubRule<"is_parameter", [ParmVar]>,
|
||||
// unless(is_parameter)
|
||||
AttrSubjectMatcherSubRule<"is_parameter", [NonParmVar], 1>
|
||||
]>;
|
||||
def SubjectMatcherForField : AttrSubjectMatcherRule<"field", [Field]>;
|
||||
def SubjectMatcherForNamespace : AttrSubjectMatcherRule<"namespace",
|
||||
[Namespace]> {
|
||||
let LangOpts = [CPlusPlus];
|
||||
}
|
||||
def SubjectMatcherForObjCInterface : AttrSubjectMatcherRule<"objc_interface",
|
||||
[ObjCInterface]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCProtocol : AttrSubjectMatcherRule<"objc_protocol",
|
||||
[ObjCProtocol]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCCategory : AttrSubjectMatcherRule<"objc_category",
|
||||
[ObjCCategory]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method",
|
||||
[ObjCMethod], [
|
||||
AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]>
|
||||
]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCProperty : AttrSubjectMatcherRule<"objc_property",
|
||||
[ObjCProperty]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForBlock : AttrSubjectMatcherRule<"block", [Block]> {
|
||||
let LangOpts = [BlocksSupported];
|
||||
}
|
||||
|
||||
// Aggregate attribute subject match rules are abstract match rules that can't
|
||||
// be used directly in #pragma clang attribute. Instead, users have to use
|
||||
// subject match rules that correspond to attribute subjects that derive from
|
||||
// the specified subject.
|
||||
class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
|
||||
AttrSubject Subject = subject;
|
||||
}
|
||||
|
||||
def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
|
||||
|
||||
class Attr {
|
||||
// The various ways in which an attribute can be spelled in source
|
||||
list<Spelling> Spellings;
|
||||
|
@ -301,6 +413,17 @@ class Attr {
|
|||
// Set to true if this attribute can be duplicated on a subject when merging
|
||||
// attributes. By default, attributes are not merged.
|
||||
bit DuplicatesAllowedWhileMerging = 0;
|
||||
// Set to true if this attribute meaningful when applied to or inherited
|
||||
// in a class template definition.
|
||||
bit MeaningfulToClassTemplateDefinition = 0;
|
||||
// Set to true if this attribute can be used with '#pragma clang attribute'.
|
||||
// By default, when this value is false, an attribute is supported by the
|
||||
// '#pragma clang attribute' only when:
|
||||
// - It has documentation.
|
||||
// - It has a subject list whose subjects can be represented using subject
|
||||
// match rules.
|
||||
// - It has GNU/CXX11 spelling and doesn't require delayed parsing.
|
||||
bit ForcePragmaAttributeSupport = 0;
|
||||
// Lists language options, one of which is required to be true for the
|
||||
// attribute to be applicable. If empty, no language options are required.
|
||||
list<LangOpt> LangOpts = [];
|
||||
|
@ -340,7 +463,7 @@ class TargetSpecificAttr<TargetArch target> {
|
|||
// should contain a shared value between the attributes.
|
||||
//
|
||||
// Target-specific attributes which use this feature should ensure that the
|
||||
// spellings match exactly betweeen the attributes, and if the arguments or
|
||||
// spellings match exactly between the attributes, and if the arguments or
|
||||
// subjects differ, should specify HasCustomParsing = 1 and implement their
|
||||
// own parsing and semantic handling requirements as-needed.
|
||||
string ParseKind;
|
||||
|
@ -372,6 +495,7 @@ def AbiTag : Attr {
|
|||
let Args = [VariadicStringArgument<"Tags">];
|
||||
let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag,
|
||||
"ExpectedStructClassVariableFunctionOrInlineNamespace">;
|
||||
let MeaningfulToClassTemplateDefinition = 1;
|
||||
let Documentation = [AbiTagsDocs];
|
||||
}
|
||||
|
||||
|
@ -449,6 +573,15 @@ def XRayInstrument : InheritableAttr {
|
|||
let Documentation = [XRayDocs];
|
||||
}
|
||||
|
||||
def XRayLogArgs : InheritableAttr {
|
||||
let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">];
|
||||
let Subjects = SubjectList<
|
||||
[CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod"
|
||||
>;
|
||||
let Args = [UnsignedArgument<"ArgumentCount">];
|
||||
let Documentation = [XRayDocs];
|
||||
}
|
||||
|
||||
def TLSModel : InheritableAttr {
|
||||
let Spellings = [GCC<"tls_model">];
|
||||
let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">;
|
||||
|
@ -464,6 +597,9 @@ def AnalyzerNoReturn : InheritableAttr {
|
|||
def Annotate : InheritableParamAttr {
|
||||
let Spellings = [GNU<"annotate">];
|
||||
let Args = [StringArgument<"Annotation">];
|
||||
// Ensure that the annotate attribute can be used with
|
||||
// '#pragma clang attribute' even though it has no subject list.
|
||||
let ForcePragmaAttributeSupport = 1;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
|
@ -480,6 +616,19 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
|
|||
let Documentation = [ARMInterruptDocs];
|
||||
}
|
||||
|
||||
def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> {
|
||||
let Spellings = [GNU<"interrupt">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let ParseKind = "Interrupt";
|
||||
let Documentation = [AVRInterruptDocs];
|
||||
}
|
||||
|
||||
def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
|
||||
let Spellings = [GNU<"signal">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [AVRSignalDocs];
|
||||
}
|
||||
|
||||
def AsmLabel : InheritableAttr {
|
||||
let Spellings = [Keyword<"asm">, Keyword<"__asm__">];
|
||||
let Args = [StringArgument<"Label">];
|
||||
|
@ -506,13 +655,48 @@ def Availability : InheritableAttr {
|
|||
.Case("tvos_app_extension", "tvOS (App Extension)")
|
||||
.Case("watchos_app_extension", "watchOS (App Extension)")
|
||||
.Default(llvm::StringRef());
|
||||
}
|
||||
static llvm::StringRef getPlatformNameSourceSpelling(llvm::StringRef Platform) {
|
||||
return llvm::StringSwitch<llvm::StringRef>(Platform)
|
||||
.Case("ios", "iOS")
|
||||
.Case("macos", "macOS")
|
||||
.Case("tvos", "tvOS")
|
||||
.Case("watchos", "watchOS")
|
||||
.Case("ios_app_extension", "iOSApplicationExtension")
|
||||
.Case("macos_app_extension", "macOSApplicationExtension")
|
||||
.Case("tvos_app_extension", "tvOSApplicationExtension")
|
||||
.Case("watchos_app_extension", "watchOSApplicationExtension")
|
||||
.Default(Platform);
|
||||
}
|
||||
static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
|
||||
return llvm::StringSwitch<llvm::StringRef>(Platform)
|
||||
.Case("iOS", "ios")
|
||||
.Case("macOS", "macos")
|
||||
.Case("tvOS", "tvos")
|
||||
.Case("watchOS", "watchos")
|
||||
.Case("iOSApplicationExtension", "ios_app_extension")
|
||||
.Case("macOSApplicationExtension", "macos_app_extension")
|
||||
.Case("tvOSApplicationExtension", "tvos_app_extension")
|
||||
.Case("watchOSApplicationExtension", "watchos_app_extension")
|
||||
.Default(Platform);
|
||||
} }];
|
||||
let HasCustomParsing = 1;
|
||||
let DuplicatesAllowedWhileMerging = 1;
|
||||
// let Subjects = SubjectList<[Named]>;
|
||||
let Subjects = SubjectList<[Named]>;
|
||||
let Documentation = [AvailabilityDocs];
|
||||
}
|
||||
|
||||
def ExternalSourceSymbol : InheritableAttr {
|
||||
let Spellings = [GNU<"external_source_symbol">,
|
||||
CXX11<"clang", "external_source_symbol">];
|
||||
let Args = [StringArgument<"language", 1>,
|
||||
StringArgument<"definedIn", 1>,
|
||||
BoolArgument<"generatedDeclaration", 1>];
|
||||
let HasCustomParsing = 1;
|
||||
let Subjects = SubjectList<[Named]>;
|
||||
let Documentation = [ExternalSourceSymbolDocs];
|
||||
}
|
||||
|
||||
def Blocks : InheritableAttr {
|
||||
let Spellings = [GNU<"blocks">];
|
||||
let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>];
|
||||
|
@ -707,6 +891,13 @@ def OpenCLUnrollHint : InheritableAttr {
|
|||
let Documentation = [OpenCLUnrollHintDocs];
|
||||
}
|
||||
|
||||
def OpenCLIntelReqdSubGroupSize: InheritableAttr {
|
||||
let Spellings = [GNU<"intel_reqd_sub_group_size">];
|
||||
let Args = [UnsignedArgument<"SubGroupSize">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [OpenCLIntelReqdSubGroupSizeDocs];
|
||||
}
|
||||
|
||||
// This attribute is both a type attribute, and a declaration attribute (for
|
||||
// parameter variables).
|
||||
def OpenCLAccess : Attr {
|
||||
|
@ -771,6 +962,7 @@ def Deprecated : InheritableAttr {
|
|||
// An optional string argument that enables us to provide a
|
||||
// Fix-It.
|
||||
StringArgument<"Replacement", 1>];
|
||||
let MeaningfulToClassTemplateDefinition = 1;
|
||||
let Documentation = [DeprecatedDocs];
|
||||
}
|
||||
|
||||
|
@ -847,7 +1039,15 @@ def FlagEnum : InheritableAttr {
|
|||
let Spellings = [GNU<"flag_enum">];
|
||||
let Subjects = SubjectList<[Enum]>;
|
||||
let Documentation = [FlagEnumDocs];
|
||||
let LangOpts = [COnly];
|
||||
}
|
||||
|
||||
def EnumExtensibility : InheritableAttr {
|
||||
let Spellings = [GNU<"enum_extensibility">,
|
||||
CXX11<"clang", "enum_extensibility">];
|
||||
let Subjects = SubjectList<[Enum]>;
|
||||
let Args = [EnumArgument<"Extensibility", "Kind",
|
||||
["closed", "open"], ["Closed", "Open"]>];
|
||||
let Documentation = [EnumExtensibilityDocs];
|
||||
}
|
||||
|
||||
def Flatten : InheritableAttr {
|
||||
|
@ -982,6 +1182,12 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
|||
let Documentation = [MipsInterruptDocs];
|
||||
}
|
||||
|
||||
def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
||||
let Spellings = [GCC<"micromips">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [MicroMipsDocs];
|
||||
}
|
||||
|
||||
def Mode : Attr {
|
||||
let Spellings = [GCC<"mode">];
|
||||
let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag,
|
||||
|
@ -1064,6 +1270,12 @@ def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
|||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
||||
let Spellings = [GCC<"nomicromips">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [MicroMipsDocs];
|
||||
}
|
||||
|
||||
// This is not a TargetSpecificAttr so that is silently accepted and
|
||||
// ignored on other targets as encouraged by the OpenCL spec.
|
||||
//
|
||||
|
@ -1115,7 +1327,7 @@ def NoSplitStack : InheritableAttr {
|
|||
let Documentation = [NoSplitStackDocs];
|
||||
}
|
||||
|
||||
def NonNull : InheritableAttr {
|
||||
def NonNull : InheritableParamAttr {
|
||||
let Spellings = [GCC<"nonnull">];
|
||||
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag,
|
||||
"ExpectedFunctionMethodOrParameter">;
|
||||
|
@ -1178,6 +1390,14 @@ def AssumeAligned : InheritableAttr {
|
|||
let Documentation = [AssumeAlignedDocs];
|
||||
}
|
||||
|
||||
def AllocAlign : InheritableAttr {
|
||||
let Spellings = [GCC<"alloc_align">];
|
||||
let Subjects = SubjectList<[HasFunctionProto], WarnDiag,
|
||||
"ExpectedFunctionWithProtoType">;
|
||||
let Args = [IntArgument<"ParamIndex">];
|
||||
let Documentation = [AllocAlignDocs];
|
||||
}
|
||||
|
||||
def NoReturn : InheritableAttr {
|
||||
let Spellings = [GCC<"noreturn">, Declspec<"noreturn">];
|
||||
// FIXME: Does GCC allow this on the function instead?
|
||||
|
@ -1463,6 +1683,42 @@ def Section : InheritableAttr {
|
|||
let Documentation = [SectionDocs];
|
||||
}
|
||||
|
||||
def PragmaClangBSSSection : InheritableAttr {
|
||||
// This attribute has no spellings as it is only ever created implicitly.
|
||||
let Spellings = [];
|
||||
let Args = [StringArgument<"Name">];
|
||||
let Subjects = SubjectList<[GlobalVar], ErrorDiag,
|
||||
"ExpectedFunctionMethodOrGlobalVar">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def PragmaClangDataSection : InheritableAttr {
|
||||
// This attribute has no spellings as it is only ever created implicitly.
|
||||
let Spellings = [];
|
||||
let Args = [StringArgument<"Name">];
|
||||
let Subjects = SubjectList<[GlobalVar], ErrorDiag,
|
||||
"ExpectedFunctionMethodOrGlobalVar">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def PragmaClangRodataSection : InheritableAttr {
|
||||
// This attribute has no spellings as it is only ever created implicitly.
|
||||
let Spellings = [];
|
||||
let Args = [StringArgument<"Name">];
|
||||
let Subjects = SubjectList<[GlobalVar], ErrorDiag,
|
||||
"ExpectedFunctionMethodOrGlobalVar">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def PragmaClangTextSection : InheritableAttr {
|
||||
// This attribute has no spellings as it is only ever created implicitly.
|
||||
let Spellings = [];
|
||||
let Args = [StringArgument<"Name">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag,
|
||||
"ExpectedFunctionMethodOrGlobalVar">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def Sentinel : InheritableAttr {
|
||||
let Spellings = [GCC<"sentinel">];
|
||||
let Args = [DefaultIntArgument<"Sentinel", 0>,
|
||||
|
@ -1498,6 +1754,12 @@ def SwiftIndirectResult : ParameterABIAttr {
|
|||
let Documentation = [SwiftIndirectResultDocs];
|
||||
}
|
||||
|
||||
def Suppress : StmtAttr {
|
||||
let Spellings = [CXX11<"gsl", "suppress">];
|
||||
let Args = [VariadicStringArgument<"DiagnosticIdentifiers">];
|
||||
let Documentation = [SuppressDocs];
|
||||
}
|
||||
|
||||
def SysVABI : InheritableAttr {
|
||||
let Spellings = [GCC<"sysv_abi">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
|
@ -1540,11 +1802,18 @@ def Target : InheritableAttr {
|
|||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [TargetDocs];
|
||||
let AdditionalMembers = [{
|
||||
typedef std::pair<std::vector<std::string>, StringRef> ParsedTargetAttr;
|
||||
struct ParsedTargetAttr {
|
||||
std::vector<std::string> Features;
|
||||
StringRef Architecture;
|
||||
bool DuplicateArchitecture = false;
|
||||
};
|
||||
ParsedTargetAttr parse() const {
|
||||
return parse(getFeaturesStr());
|
||||
}
|
||||
static ParsedTargetAttr parse(StringRef Features) {
|
||||
ParsedTargetAttr Ret;
|
||||
SmallVector<StringRef, 1> AttrFeatures;
|
||||
getFeaturesStr().split(AttrFeatures, ",");
|
||||
Features.split(AttrFeatures, ",");
|
||||
|
||||
// Grab the various features and prepend a "+" to turn on the feature to
|
||||
// the backend and add them to our existing set of features.
|
||||
|
@ -1561,12 +1830,15 @@ def Target : InheritableAttr {
|
|||
continue;
|
||||
|
||||
// While we're here iterating check for a different target cpu.
|
||||
if (Feature.startswith("arch="))
|
||||
Ret.second = Feature.split("=").second.trim();
|
||||
else if (Feature.startswith("no-"))
|
||||
Ret.first.push_back("-" + Feature.split("-").second.str());
|
||||
if (Feature.startswith("arch=")) {
|
||||
if (!Ret.Architecture.empty())
|
||||
Ret.DuplicateArchitecture = true;
|
||||
else
|
||||
Ret.Architecture = Feature.split("=").second.trim();
|
||||
} else if (Feature.startswith("no-"))
|
||||
Ret.Features.push_back("-" + Feature.split("-").second.str());
|
||||
else
|
||||
Ret.first.push_back("+" + Feature.str());
|
||||
Ret.Features.push_back("+" + Feature.str());
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
@ -1596,14 +1868,14 @@ def Unavailable : InheritableAttr {
|
|||
|
||||
def DiagnoseIf : InheritableAttr {
|
||||
let Spellings = [GNU<"diagnose_if">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>;
|
||||
let Args = [ExprArgument<"Cond">, StringArgument<"Message">,
|
||||
EnumArgument<"DiagnosticType",
|
||||
"DiagnosticType",
|
||||
["error", "warning"],
|
||||
["DT_Error", "DT_Warning"]>,
|
||||
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
|
||||
FunctionArgument<"Parent", 0, /*fake*/ 1>];
|
||||
NamedArgument<"Parent", 0, /*fake*/ 1>];
|
||||
let DuplicatesAllowedWhileMerging = 1;
|
||||
let LateParsed = 1;
|
||||
let AdditionalMembers = [{
|
||||
|
@ -1681,6 +1953,7 @@ def Visibility : InheritableAttr {
|
|||
let Args = [EnumArgument<"Visibility", "VisibilityType",
|
||||
["default", "hidden", "internal", "protected"],
|
||||
["Default", "Hidden", "Hidden", "Protected"]>];
|
||||
let MeaningfulToClassTemplateDefinition = 1;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
|
@ -1750,6 +2023,12 @@ def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
|
|||
let Documentation = [AnyX86InterruptDocs];
|
||||
}
|
||||
|
||||
def AnyX86NoCallerSavedRegisters : InheritableAttr,
|
||||
TargetSpecificAttr<TargetAnyX86> {
|
||||
let Spellings = [GCC<"no_caller_saved_registers">];
|
||||
let Documentation = [AnyX86NoCallerSavedRegistersDocs];
|
||||
}
|
||||
|
||||
def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
|
||||
let Spellings = [GNU<"force_align_arg_pointer">];
|
||||
// Technically, this appertains to a FunctionDecl, but the target-specific
|
||||
|
@ -2180,9 +2459,8 @@ def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
|
|||
let Documentation = [DLLImportDocs];
|
||||
}
|
||||
|
||||
def SelectAny : InheritableAttr {
|
||||
let Spellings = [Declspec<"selectany">];
|
||||
let LangOpts = [MicrosoftExt];
|
||||
def SelectAny : InheritableAttr, TargetSpecificAttr<TargetWindows> {
|
||||
let Spellings = [Declspec<"selectany">, GCC<"selectany">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
|
|
|
@ -244,6 +244,36 @@ An example of how to use ``alloc_size``
|
|||
}];
|
||||
}
|
||||
|
||||
def AllocAlignDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Use ``__attribute__((alloc_align(<alignment>))`` on a function
|
||||
declaration to specify that the return value of the function (which must be a
|
||||
pointer type) is at least as aligned as the value of the indicated parameter. The
|
||||
parameter is given by its index in the list of formal parameters; the first
|
||||
parameter has index 1 unless the function is a C++ non-static member function,
|
||||
in which case the first parameter has index 2 to account for the implicit ``this``
|
||||
parameter.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// The returned pointer has the alignment specified by the first parameter.
|
||||
void *a(size_t align) __attribute__((alloc_align(1)));
|
||||
|
||||
// The returned pointer has the alignment specified by the second parameter.
|
||||
void *b(void *v, size_t align) __attribute__((alloc_align(2)));
|
||||
|
||||
// The returned pointer has the alignment specified by the second visible
|
||||
// parameter, however it must be adjusted for the implicit 'this' parameter.
|
||||
void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3)));
|
||||
|
||||
Note that this attribute merely informs the compiler that a function always
|
||||
returns a sufficiently aligned pointer. It does not cause the compiler to
|
||||
emit code to enforce that alignment. The behavior is undefined if the returned
|
||||
poitner is not sufficiently aligned.
|
||||
}];
|
||||
}
|
||||
|
||||
def EnableIfDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
@ -575,20 +605,27 @@ semantics:
|
|||
for ``T`` and ``U`` to be incompatible.
|
||||
|
||||
The declaration of ``overloadable`` functions is restricted to function
|
||||
declarations and definitions. Most importantly, if any function with a given
|
||||
name is given the ``overloadable`` attribute, then all function declarations
|
||||
and definitions with that name (and in that scope) must have the
|
||||
``overloadable`` attribute. This rule even applies to redeclarations of
|
||||
functions whose original declaration had the ``overloadable`` attribute, e.g.,
|
||||
declarations and definitions. If a function is marked with the ``overloadable``
|
||||
attribute, then all declarations and definitions of functions with that name,
|
||||
except for at most one (see the note below about unmarked overloads), must have
|
||||
the ``overloadable`` attribute. In addition, redeclarations of a function with
|
||||
the ``overloadable`` attribute must have the ``overloadable`` attribute, and
|
||||
redeclarations of a function without the ``overloadable`` attribute must *not*
|
||||
have the ``overloadable`` attribute. e.g.,
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int f(int) __attribute__((overloadable));
|
||||
float f(float); // error: declaration of "f" must have the "overloadable" attribute
|
||||
int f(int); // error: redeclaration of "f" must have the "overloadable" attribute
|
||||
|
||||
int g(int) __attribute__((overloadable));
|
||||
int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute
|
||||
|
||||
int h(int);
|
||||
int h(int) __attribute__((overloadable)); // error: declaration of "h" must not
|
||||
// have the "overloadable" attribute
|
||||
|
||||
Functions marked ``overloadable`` must have prototypes. Therefore, the
|
||||
following code is ill-formed:
|
||||
|
||||
|
@ -621,7 +658,28 @@ caveats to this use of name mangling:
|
|||
linkage specification, it's name *will* be mangled in the same way as it
|
||||
would in C.
|
||||
|
||||
Query for this feature with ``__has_extension(attribute_overloadable)``.
|
||||
For the purpose of backwards compatibility, at most one function with the same
|
||||
name as other ``overloadable`` functions may omit the ``overloadable``
|
||||
attribute. In this case, the function without the ``overloadable`` attribute
|
||||
will not have its name mangled.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// Notes with mangled names assume Itanium mangling.
|
||||
int f(int);
|
||||
int f(double) __attribute__((overloadable));
|
||||
void foo() {
|
||||
f(5); // Emits a call to f (not _Z1fi, as it would with an overload that
|
||||
// was marked with overloadable).
|
||||
f(1.0); // Emits a call to _Z1fd.
|
||||
}
|
||||
|
||||
Support for unmarked overloads is not present in some versions of clang. You may
|
||||
query for it using ``__has_extension(overloadable_unmarked)``.
|
||||
|
||||
Query for this attribute with ``__has_attribute(overloadable)``.
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -852,13 +910,13 @@ the function declaration for a hypothetical function ``f``:
|
|||
|
||||
void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
|
||||
|
||||
The availability attribute states that ``f`` was introduced in Mac OS X 10.4,
|
||||
deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information
|
||||
The availability attribute states that ``f`` was introduced in macOS 10.4,
|
||||
deprecated in macOS 10.6, and obsoleted in macOS 10.7. This information
|
||||
is used by Clang to determine when it is safe to use ``f``: for example, if
|
||||
Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()``
|
||||
succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call
|
||||
Clang is instructed to compile code for macOS 10.5, a call to ``f()``
|
||||
succeeds. If Clang is instructed to compile code for macOS 10.6, the call
|
||||
succeeds but Clang emits a warning specifying that the function is deprecated.
|
||||
Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call
|
||||
Finally, if Clang is instructed to compile code for macOS 10.7, the call
|
||||
fails because ``f()`` is no longer available.
|
||||
|
||||
The availability attribute is a comma-separated list starting with the
|
||||
|
@ -903,7 +961,7 @@ are:
|
|||
command-line arguments.
|
||||
|
||||
``macos``
|
||||
Apple's Mac OS X operating system. The minimum deployment target is
|
||||
Apple's macOS operating system. The minimum deployment target is
|
||||
specified by the ``-mmacosx-version-min=*version*`` command-line argument.
|
||||
``macosx`` is supported for backward-compatibility reasons, but it is
|
||||
deprecated.
|
||||
|
@ -957,9 +1015,79 @@ When one method overrides another, the overriding method can be more widely avai
|
|||
- (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later
|
||||
- (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4
|
||||
@end
|
||||
|
||||
Starting with the macOS 10.12 SDK, the ``API_AVAILABLE`` macro from
|
||||
``<os/availability.h>`` can simplify the spelling:
|
||||
|
||||
.. code-block:: objc
|
||||
|
||||
@interface A
|
||||
- (id)method API_AVAILABLE(macos(10.11)));
|
||||
- (id)otherMethod API_AVAILABLE(macos(10.11), ios(11.0));
|
||||
@end
|
||||
|
||||
Also see the documentation for `@available
|
||||
<http://clang.llvm.org/docs/LanguageExtensions.html#objective-c-available>`_
|
||||
}];
|
||||
}
|
||||
|
||||
def ExternalSourceSymbolDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``external_source_symbol`` attribute specifies that a declaration originates
|
||||
from an external source and describes the nature of that source.
|
||||
|
||||
The fact that Clang is capable of recognizing declarations that were defined
|
||||
externally can be used to provide better tooling support for mixed-language
|
||||
projects or projects that rely on auto-generated code. For instance, an IDE that
|
||||
uses Clang and that supports mixed-language projects can use this attribute to
|
||||
provide a correct 'jump-to-definition' feature. For a concrete example,
|
||||
consider a protocol that's defined in a Swift file:
|
||||
|
||||
.. code-block:: swift
|
||||
|
||||
@objc public protocol SwiftProtocol {
|
||||
func method()
|
||||
}
|
||||
|
||||
This protocol can be used from Objective-C code by including a header file that
|
||||
was generated by the Swift compiler. The declarations in that header can use
|
||||
the ``external_source_symbol`` attribute to make Clang aware of the fact
|
||||
that ``SwiftProtocol`` actually originates from a Swift module:
|
||||
|
||||
.. code-block:: objc
|
||||
|
||||
__attribute__((external_source_symbol(language="Swift",defined_in="module")))
|
||||
@protocol SwiftProtocol
|
||||
@required
|
||||
- (void) method;
|
||||
@end
|
||||
|
||||
Consequently, when 'jump-to-definition' is performed at a location that
|
||||
references ``SwiftProtocol``, the IDE can jump to the original definition in
|
||||
the Swift source file rather than jumping to the Objective-C declaration in the
|
||||
auto-generated header file.
|
||||
|
||||
The ``external_source_symbol`` attribute is a comma-separated list that includes
|
||||
clauses that describe the origin and the nature of the particular declaration.
|
||||
Those clauses can be:
|
||||
|
||||
language=\ *string-literal*
|
||||
The name of the source language in which this declaration was defined.
|
||||
|
||||
defined_in=\ *string-literal*
|
||||
The name of the source container in which the declaration was defined. The
|
||||
exact definition of source container is language-specific, e.g. Swift's
|
||||
source containers are modules, so ``defined_in`` should specify the Swift
|
||||
module name.
|
||||
|
||||
generated_declaration
|
||||
This declaration was automatically generated by some tool.
|
||||
|
||||
The clauses can be specified in any order. The clauses that are listed above are
|
||||
all optional, but the attribute has to have at least one clause.
|
||||
}];
|
||||
}
|
||||
|
||||
def RequireConstantInitDocs : Documentation {
|
||||
let Category = DocCatVariable;
|
||||
|
@ -1182,6 +1310,46 @@ The semantics are as follows:
|
|||
}];
|
||||
}
|
||||
|
||||
def MicroMipsDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Clang supports the GNU style ``__attribute__((micromips))`` and
|
||||
``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes
|
||||
may be attached to a function definition and instructs the backend to generate
|
||||
or not to generate microMIPS code for that function.
|
||||
|
||||
These attributes override the `-mmicromips` and `-mno-micromips` options
|
||||
on the command line.
|
||||
}];
|
||||
}
|
||||
|
||||
def AVRInterruptDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
|
||||
AVR 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.
|
||||
|
||||
On the AVR, the hardware globally disables interrupts when an interrupt is executed.
|
||||
The first instruction of an interrupt handler declared with this attribute is a SEI
|
||||
instruction to re-enable interrupts. See also the signal attribute that
|
||||
does not insert a SEI instruction.
|
||||
}];
|
||||
}
|
||||
|
||||
def AVRSignalDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Clang supports the GNU style ``__attribute__((signal))`` attribute on
|
||||
AVR 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.
|
||||
|
||||
Interrupt handler functions defined with the signal attribute do not re-enable interrupts.
|
||||
}];
|
||||
}
|
||||
|
||||
def TargetDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
@ -1879,6 +2047,55 @@ manipulating bits of the enumerator when issuing warnings.
|
|||
}];
|
||||
}
|
||||
|
||||
def EnumExtensibilityDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
Attribute ``enum_extensibility`` is used to distinguish between enum definitions
|
||||
that are extensible and those that are not. The attribute can take either
|
||||
``closed`` or ``open`` as an argument. ``closed`` indicates a variable of the
|
||||
enum type takes a value that corresponds to one of the enumerators listed in the
|
||||
enum definition or, when the enum is annotated with ``flag_enum``, a value that
|
||||
can be constructed using values corresponding to the enumerators. ``open``
|
||||
indicates a variable of the enum type can take any values allowed by the
|
||||
standard and instructs clang to be more lenient when issuing warnings.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
enum __attribute__((enum_extensibility(closed))) ClosedEnum {
|
||||
A0, A1
|
||||
};
|
||||
|
||||
enum __attribute__((enum_extensibility(open))) OpenEnum {
|
||||
B0, B1
|
||||
};
|
||||
|
||||
enum __attribute__((enum_extensibility(closed),flag_enum)) ClosedFlagEnum {
|
||||
C0 = 1 << 0, C1 = 1 << 1
|
||||
};
|
||||
|
||||
enum __attribute__((enum_extensibility(open),flag_enum)) OpenFlagEnum {
|
||||
D0 = 1 << 0, D1 = 1 << 1
|
||||
};
|
||||
|
||||
void foo1() {
|
||||
enum ClosedEnum ce;
|
||||
enum OpenEnum oe;
|
||||
enum ClosedFlagEnum cfe;
|
||||
enum OpenFlagEnum ofe;
|
||||
|
||||
ce = A1; // no warnings
|
||||
ce = 100; // warning issued
|
||||
oe = B1; // no warnings
|
||||
oe = 100; // no warnings
|
||||
cfe = C0 | C1; // no warnings
|
||||
cfe = C0 | C1 | 4; // warning issued
|
||||
ofe = D0 | D1; // no warnings
|
||||
ofe = D0 | D1 | 4; // no warnings
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
def EmptyBasesDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
|
@ -2053,6 +2270,21 @@ s6.11.5 for details.
|
|||
}];
|
||||
}
|
||||
|
||||
def OpenCLIntelReqdSubGroupSizeDocs : Documentation {
|
||||
let Category = DocCatStmt;
|
||||
let Heading = "__attribute__((intel_reqd_sub_group_size))";
|
||||
let Content = [{
|
||||
The optional attribute intel_reqd_sub_group_size can be used to indicate that
|
||||
the kernel must be compiled and executed with the specified subgroup size. When
|
||||
this attribute is present, get_max_sub_group_size() is guaranteed to return the
|
||||
specified integer value. This is important for the correctness of many subgroup
|
||||
algorithms, and in some cases may be used by the compiler to generate more optimal
|
||||
code. See `cl_intel_required_subgroup_size
|
||||
<https://www.khronos.org/registry/OpenCL/extensions/intel/cl_intel_required_subgroup_size.txt>`
|
||||
for details.
|
||||
}];
|
||||
}
|
||||
|
||||
def OpenCLAccessDocs : Documentation {
|
||||
let Category = DocCatStmt;
|
||||
let Heading = "__read_only, __write_only, __read_write (read_only, write_only, read_write)";
|
||||
|
@ -2494,6 +2726,40 @@ hardware design, touch the red zone.
|
|||
}];
|
||||
}
|
||||
|
||||
def AnyX86NoCallerSavedRegistersDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Use this attribute to indicate that the specified function has no
|
||||
caller-saved registers. That is, all registers are callee-saved except for
|
||||
registers used for passing parameters to the function or returning parameters
|
||||
from the function.
|
||||
The compiler saves and restores any modified registers that were not used for
|
||||
passing or returning arguments to the function.
|
||||
|
||||
The user can call functions specified with the 'no_caller_saved_registers'
|
||||
attribute from an interrupt handler without saving and restoring all
|
||||
call-clobbered registers.
|
||||
|
||||
Note that 'no_caller_saved_registers' attribute is not a calling convention.
|
||||
In fact, it only overrides the decision of which registers should be saved by
|
||||
the caller, but not how the parameters are passed from the caller to the callee.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
__attribute__ ((no_caller_saved_registers, fastcall))
|
||||
void f (int arg1, int arg2) {
|
||||
...
|
||||
}
|
||||
|
||||
In this case parameters 'arg1' and 'arg2' will be passed in registers.
|
||||
In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as
|
||||
register parameters. However, it will not assume any scratch registers and
|
||||
should save and restore any modified registers except for ECX and EDX.
|
||||
}];
|
||||
}
|
||||
|
||||
def SwiftCallDocs : Documentation {
|
||||
let Category = DocCatVariable;
|
||||
let Content = [{
|
||||
|
@ -2638,6 +2904,32 @@ optimizations like C++'s named return value optimization (NRVO).
|
|||
}];
|
||||
}
|
||||
|
||||
def SuppressDocs : Documentation {
|
||||
let Category = DocCatStmt;
|
||||
let Content = [{
|
||||
The ``[[gsl::suppress]]`` attribute suppresses specific
|
||||
clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable
|
||||
way. The attribute can be attached to declarations, statements, and at
|
||||
namespace scope.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
[[gsl::suppress("Rh-public")]]
|
||||
void f_() {
|
||||
int *p;
|
||||
[[gsl::suppress("type")]] {
|
||||
p = reinterpret_cast<int*>(7);
|
||||
}
|
||||
}
|
||||
namespace N {
|
||||
[[clang::suppress("type", "bounds")]];
|
||||
...
|
||||
}
|
||||
|
||||
.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement
|
||||
}];
|
||||
}
|
||||
|
||||
def AbiTagsDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
@ -2777,13 +3069,15 @@ See the RenderScript_ documentation for more information.
|
|||
|
||||
def XRayDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument)";
|
||||
let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument), xray_log_args (clang::xray_log_args)";
|
||||
let Content = [{
|
||||
``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching.
|
||||
|
||||
Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points.
|
||||
|
||||
If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise.
|
||||
|
||||
``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported.
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
//===-- AttrSubjectMatchRules.h - Attribute subject match rules -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
|
||||
#define LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
namespace attr {
|
||||
|
||||
/// \brief A list of all the recognized kinds of attributes.
|
||||
enum SubjectMatchRule {
|
||||
#define ATTR_MATCH_RULE(X, Spelling, IsAbstract) X,
|
||||
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
||||
};
|
||||
|
||||
const char *getSubjectMatchRuleSpelling(SubjectMatchRule Rule);
|
||||
|
||||
using ParsedSubjectMatchRuleSet = llvm::DenseMap<int, SourceRange>;
|
||||
|
||||
} // end namespace attr
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -52,6 +52,7 @@
|
|||
// LL -> long long
|
||||
// LLL -> __int128_t (e.g. LLLi)
|
||||
// W -> int64_t
|
||||
// N -> 'int' size if target is LP64, 'L' otherwise.
|
||||
// S -> signed
|
||||
// U -> unsigned
|
||||
// I -> Required to constant fold to an integer constant expression.
|
||||
|
@ -718,11 +719,11 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
|
|||
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_ulong, "ULiULi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_uint64, "ULLiULLi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_code, "UNi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_code, "UNi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
|
||||
|
@ -730,49 +731,50 @@ LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
|
|||
LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange8, "ccD*cc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement16, "ssD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__popcnt64, "ULLiULLi", "nc", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl, "UiUii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotl, "ULiULii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotl, "UNiUNii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr8, "UcUcUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr16, "UsUsUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotr, "UNiUNii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES)
|
||||
|
||||
// Microsoft library builtins.
|
||||
LIBBUILTIN(_setjmpex, "iJ", "fj", "setjmpex.h", ALL_MS_LANGUAGES)
|
||||
|
@ -1086,9 +1088,11 @@ LIBBUILTIN(ilogb, "id", "fne", "math.h", ALL_LANGUAGES)
|
|||
LIBBUILTIN(ilogbf, "if", "fne", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(ilogbl, "iLd", "fne", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(lgamma, "dd", "fne", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(lgammaf, "ff", "fne", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(lgammal, "LdLd", "fne", "math.h", ALL_LANGUAGES)
|
||||
// POSIX math.h declares a global, signgam, that lgamma writes to, so these
|
||||
// shouldn't have "e" or "c" attributes
|
||||
LIBBUILTIN(lgamma, "dd", "fn", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(lgammaf, "ff", "fn", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(lgammal, "LdLd", "fn", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(llrint, "LLid", "fne", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(llrintf, "LLif", "fne", "math.h", ALL_LANGUAGES)
|
||||
|
@ -1362,7 +1366,7 @@ BUILTIN(__builtin_coro_free, "v*v*", "n")
|
|||
BUILTIN(__builtin_coro_id, "v*Iiv*v*v*", "n")
|
||||
BUILTIN(__builtin_coro_alloc, "b", "n")
|
||||
BUILTIN(__builtin_coro_begin, "v*v*", "n")
|
||||
BUILTIN(__builtin_coro_end, "vv*Ib", "n")
|
||||
BUILTIN(__builtin_coro_end, "bv*Ib", "n")
|
||||
BUILTIN(__builtin_coro_suspend, "cIb", "n")
|
||||
BUILTIN(__builtin_coro_param, "bv*v*", "n")
|
||||
// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
|
||||
|
@ -1406,6 +1410,14 @@ LANGBUILTIN(to_private, "v*v*", "tn", OCLC20_LANG)
|
|||
BUILTIN(__builtin_os_log_format_buffer_size, "zcC*.", "p:0:nut")
|
||||
BUILTIN(__builtin_os_log_format, "v*v*cC*.", "p:0:nt")
|
||||
|
||||
// Builtins for XRay
|
||||
BUILTIN(__xray_customevent, "vcC*z", "")
|
||||
|
||||
// Win64-compatible va_list functions
|
||||
BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
|
||||
BUILTIN(__builtin_ms_va_end, "vc*&", "n")
|
||||
BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LIBBUILTIN
|
||||
#undef LANGBUILTIN
|
||||
|
|
|
@ -35,8 +35,15 @@ BUILTIN(__builtin_amdgcn_workitem_id_z, "Ui", "nc")
|
|||
//===----------------------------------------------------------------------===//
|
||||
// Instruction builtins.
|
||||
//===----------------------------------------------------------------------===//
|
||||
BUILTIN(__builtin_amdgcn_s_getreg, "UiIi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_getpc, "LUi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_waitcnt, "vIi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_sendmsg, "vIiUi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_sendmsghalt, "vIiUi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_barrier, "v", "n")
|
||||
BUILTIN(__builtin_amdgcn_wave_barrier, "v", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_dcache_inv, "v", "n")
|
||||
BUILTIN(__builtin_amdgcn_buffer_wbinvl1, "v", "n")
|
||||
BUILTIN(__builtin_amdgcn_div_scale, "dddbb*", "n")
|
||||
BUILTIN(__builtin_amdgcn_div_scalef, "fffbb*", "n")
|
||||
BUILTIN(__builtin_amdgcn_div_fmas, "ddddb", "nc")
|
||||
|
@ -80,6 +87,11 @@ BUILTIN(__builtin_amdgcn_sicmpl, "LUiLiLiIi", "nc")
|
|||
BUILTIN(__builtin_amdgcn_fcmp, "LUiddIi", "nc")
|
||||
BUILTIN(__builtin_amdgcn_fcmpf, "LUiffIi", "nc")
|
||||
BUILTIN(__builtin_amdgcn_ds_swizzle, "iiIi", "nc")
|
||||
BUILTIN(__builtin_amdgcn_ds_permute, "iii", "nc")
|
||||
BUILTIN(__builtin_amdgcn_ds_bpermute, "iii", "nc")
|
||||
BUILTIN(__builtin_amdgcn_readfirstlane, "ii", "nc")
|
||||
BUILTIN(__builtin_amdgcn_readlane, "iii", "nc")
|
||||
BUILTIN(__builtin_amdgcn_fmed3f, "ffff", "nc")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VI+ only builtins.
|
||||
|
@ -96,6 +108,13 @@ TARGET_BUILTIN(__builtin_amdgcn_frexp_exph, "sh", "nc", "16-bit-insts")
|
|||
TARGET_BUILTIN(__builtin_amdgcn_fracth, "hh", "nc", "16-bit-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_classh, "bhi", "nc", "16-bit-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_s_memrealtime, "LUi", "n", "s-memrealtime")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mov_dpp, "iiIiIiIiIb", "nc", "dpp")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GFX9+ only builtins.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Special builtins.
|
||||
|
|
|
@ -25,11 +25,93 @@
|
|||
// In libgcc
|
||||
BUILTIN(__clear_cache, "vv*v*", "i")
|
||||
|
||||
// 16-bit multiplications
|
||||
BUILTIN(__builtin_arm_smulbb, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smulbt, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smultb, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smultt, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smulwb, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smulwt, "iii", "nc")
|
||||
|
||||
// Saturating arithmetic
|
||||
BUILTIN(__builtin_arm_qadd, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_qsub, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_ssat, "iiUi", "nc")
|
||||
BUILTIN(__builtin_arm_usat, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_usat, "UiiUi", "nc")
|
||||
|
||||
BUILTIN(__builtin_arm_smlabb, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlabt, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlatb, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlatt, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlawb, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlawt, "iiii", "nc")
|
||||
|
||||
BUILTIN(__builtin_arm_ssat16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_usat16, "iii", "nc")
|
||||
|
||||
BUILTIN(__builtin_arm_sxtab16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_sxtb16, "ii", "nc")
|
||||
BUILTIN(__builtin_arm_uxtab16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_uxtb16, "ii", "nc")
|
||||
|
||||
BUILTIN(__builtin_arm_sel, "iii", "nc")
|
||||
|
||||
BUILTIN(__builtin_arm_qadd8, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_qsub8, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_sadd8, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_shadd8, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_shsub8, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_ssub8, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_uadd8, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uhadd8, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uhsub8, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uqadd8, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uqsub8, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_usub8, "UiUiUi", "nc")
|
||||
|
||||
// Sum of 8-bit absolute differences
|
||||
BUILTIN(__builtin_arm_usad8, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_usada8, "UiUiUiUi", "nc")
|
||||
|
||||
// Parallel 16-bit addition and subtraction
|
||||
BUILTIN(__builtin_arm_qadd16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_qasx, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_qsax, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_qsub16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_sadd16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_sasx, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_shadd16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_shasx, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_shsax, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_shsub16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_ssax, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_ssub16, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_uadd16, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uasx, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uhadd16, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uhasx, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uhsax, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uhsub16, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uqadd16, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uqasx, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uqsax, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_uqsub16, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_usax, "UiUiUi", "nc")
|
||||
BUILTIN(__builtin_arm_usub16, "UiUiUi", "nc")
|
||||
|
||||
// Parallel 16-bit multiplication
|
||||
BUILTIN(__builtin_arm_smlad, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smladx, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlald, "LLiiiLLi", "nc")
|
||||
BUILTIN(__builtin_arm_smlaldx, "LLiiiLLi", "nc")
|
||||
BUILTIN(__builtin_arm_smlsd, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlsdx, "iiii", "nc")
|
||||
BUILTIN(__builtin_arm_smlsld, "LLiiiLLi", "nc")
|
||||
BUILTIN(__builtin_arm_smlsldx, "LLiiiLLi", "nc")
|
||||
BUILTIN(__builtin_arm_smuad, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smuadx, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smusd, "iii", "nc")
|
||||
BUILTIN(__builtin_arm_smusdx, "iii", "nc")
|
||||
|
||||
// Bit manipulation
|
||||
BUILTIN(__builtin_arm_rbit, "UiUi", "nc")
|
||||
|
@ -133,10 +215,10 @@ LANGBUILTIN(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
|
|||
LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
|
||||
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
|
|
@ -882,6 +882,12 @@ BUILTIN(__builtin_HEXAGON_S2_ct0p,"iLLi","")
|
|||
BUILTIN(__builtin_HEXAGON_S2_ct1p,"iLLi","")
|
||||
BUILTIN(__builtin_HEXAGON_S2_interleave,"LLiLLi","")
|
||||
BUILTIN(__builtin_HEXAGON_S2_deinterleave,"LLiLLi","")
|
||||
BUILTIN(__builtin_HEXAGON_Y2_dccleana,"vv*","")
|
||||
BUILTIN(__builtin_HEXAGON_Y2_dccleaninva,"vv*","")
|
||||
BUILTIN(__builtin_HEXAGON_Y2_dcinva,"vv*","")
|
||||
BUILTIN(__builtin_HEXAGON_Y2_dczeroa,"vv*","")
|
||||
BUILTIN(__builtin_HEXAGON_Y4_l2fetch,"vv*Ui","")
|
||||
BUILTIN(__builtin_HEXAGON_Y5_l2fetch,"vv*LLUi","")
|
||||
|
||||
BUILTIN(__builtin_HEXAGON_S6_rol_i_r,"iii","v:60:")
|
||||
BUILTIN(__builtin_HEXAGON_S6_rol_i_p,"LLiLLii","v:60:")
|
||||
|
|
|
@ -64,24 +64,10 @@ BUILTIN(__nvvm_read_ptx_sreg_pm3, "i", "n")
|
|||
|
||||
// MISC
|
||||
|
||||
BUILTIN(__nvvm_clz_i, "ii", "")
|
||||
BUILTIN(__nvvm_clz_ll, "iLLi", "")
|
||||
BUILTIN(__nvvm_popc_i, "ii", "")
|
||||
BUILTIN(__nvvm_popc_ll, "iLLi", "")
|
||||
BUILTIN(__nvvm_prmt, "UiUiUiUi", "")
|
||||
|
||||
// Min Max
|
||||
|
||||
BUILTIN(__nvvm_min_i, "iii", "")
|
||||
BUILTIN(__nvvm_min_ui, "UiUiUi", "")
|
||||
BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "")
|
||||
BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "")
|
||||
|
||||
BUILTIN(__nvvm_max_i, "iii", "")
|
||||
BUILTIN(__nvvm_max_ui, "UiUiUi", "")
|
||||
BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "")
|
||||
BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "")
|
||||
|
||||
BUILTIN(__nvvm_fmax_ftz_f, "fff", "")
|
||||
BUILTIN(__nvvm_fmax_f, "fff", "")
|
||||
BUILTIN(__nvvm_fmin_ftz_f, "fff", "")
|
||||
|
@ -133,11 +119,6 @@ BUILTIN(__nvvm_div_rz_d, "ddd", "")
|
|||
BUILTIN(__nvvm_div_rm_d, "ddd", "")
|
||||
BUILTIN(__nvvm_div_rp_d, "ddd", "")
|
||||
|
||||
// Brev
|
||||
|
||||
BUILTIN(__nvvm_brev32, "UiUi", "")
|
||||
BUILTIN(__nvvm_brev64, "ULLiULLi", "")
|
||||
|
||||
// Sad
|
||||
|
||||
BUILTIN(__nvvm_sad_i, "iiii", "")
|
||||
|
@ -155,9 +136,6 @@ BUILTIN(__nvvm_ceil_d, "dd", "")
|
|||
|
||||
// Abs
|
||||
|
||||
BUILTIN(__nvvm_abs_i, "ii", "")
|
||||
BUILTIN(__nvvm_abs_ll, "LLiLLi", "")
|
||||
|
||||
BUILTIN(__nvvm_fabs_ftz_f, "ff", "")
|
||||
BUILTIN(__nvvm_fabs_f, "ff", "")
|
||||
BUILTIN(__nvvm_fabs_d, "dd", "")
|
||||
|
@ -385,8 +363,6 @@ BUILTIN(__nvvm_ull2d_rp, "dULLi", "")
|
|||
BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "")
|
||||
BUILTIN(__nvvm_f2h_rn, "Usf", "")
|
||||
|
||||
BUILTIN(__nvvm_h2f, "fUs", "")
|
||||
|
||||
// Bitcast
|
||||
|
||||
BUILTIN(__nvvm_bitcast_f2i, "if", "")
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
//===-- BuiltinsNios2.def - Nios2 Builtin function database --------*- 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 Nios2-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The format of this database matches clang/Basic/Builtins.def.
|
||||
|
||||
#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
|
||||
# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
// Nios2 R1 builtins:
|
||||
|
||||
//int __builtin_ldbio(volatile const void *);
|
||||
BUILTIN(__builtin_ldbio, "ivDC*", "")
|
||||
//int __builtin_ldbuio(volatile const void *);
|
||||
BUILTIN(__builtin_ldbuio, "ivDC*", "")
|
||||
//int __builtin_ldhio(volatile const void *);
|
||||
BUILTIN(__builtin_ldhio, "ivDC*", "")
|
||||
//int __builtin_ldhuio(volatile const void *);
|
||||
BUILTIN(__builtin_ldhuio, "ivDC*", "")
|
||||
//int __builtin_ldwio(volatile const void *);
|
||||
BUILTIN(__builtin_ldwio, "ivDC*", "")
|
||||
//int __builtin_ldwuio(int);
|
||||
BUILTIN(__builtin_ldwuio, "ii", "")
|
||||
// int __builtin_rdctl(int);
|
||||
BUILTIN(__builtin_rdctl, "iIi", "")
|
||||
// void __builtin_wrctl(int, int);
|
||||
BUILTIN(__builtin_wrctl, "vIii", "")
|
||||
// int __builtin_rdprs(int, int);
|
||||
BUILTIN(__builtin_rdprs, "iii", "")
|
||||
//void __builtin_stbio(volatile void *, int);
|
||||
BUILTIN(__builtin_stbio, "vvD*i", "")
|
||||
//void __builtin_sthio(volatile void *, int);
|
||||
BUILTIN(__builtin_sthio, "vvD*i", "")
|
||||
//void __builtin_stwio(volatile void *, int);
|
||||
BUILTIN(__builtin_stwio, "vvD*i", "")
|
||||
//void __builtin_sync(void);
|
||||
BUILTIN(__builtin_sync, "v", "")
|
||||
// void __builtin_flushd(volatile void *);
|
||||
BUILTIN(__builtin_flushd, "vvD*", "")
|
||||
// void __builtin_flushda(volatile void *);
|
||||
BUILTIN(__builtin_flushda, "vvD*", "")
|
||||
|
||||
// Nios2 R2 builtins:
|
||||
|
||||
// int __builtin_wrpie(int);
|
||||
TARGET_BUILTIN(__builtin_wrpie, "ii", "", "nios2r2mandatory")
|
||||
// void __builtin_eni(int);
|
||||
TARGET_BUILTIN(__builtin_eni, "vi", "", "nios2r2mandatory")
|
||||
// int __builtin_ldex(volatile const void *);
|
||||
TARGET_BUILTIN(__builtin_ldex, "ivDC*", "", "nios2r2mandatory")
|
||||
// int __builtin_stex(volatile void *, int);
|
||||
TARGET_BUILTIN(__builtin_stex, "ivD*i", "", "nios2r2mandatory")
|
||||
// int __builtin_ldsex(volatile const void *);
|
||||
TARGET_BUILTIN(__builtin_ldsex, "ivDC*", "", "nios2r2mpx")
|
||||
// int __builtin_stsex(volatile void *, int);
|
||||
TARGET_BUILTIN(__builtin_stsex, "ivDC*i", "", "nios2r2mpx")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue