mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Vendor import of clang trunk r154661:
http://llvm.org/svn/llvm-project/cfe/trunk@r154661
This commit is contained in:
parent
9da628931e
commit
dbe13110f5
2685 changed files with 181522 additions and 52786 deletions
|
|
@ -204,7 +204,8 @@ macro(add_clang_library name)
|
|||
endif(MSVC)
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
|
||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
RUNTIME DESTINATION bin)
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
|
||||
endmacro(add_clang_library)
|
||||
|
||||
|
|
@ -223,6 +224,7 @@ install(DIRECTORY include/
|
|||
FILES_MATCHING
|
||||
PATTERN "*.def"
|
||||
PATTERN "*.h"
|
||||
PATTERN "config.h" EXCLUDE
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
|
|
@ -233,7 +235,7 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
|||
PATTERN "*.inc"
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H )
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
# Clang version information
|
||||
set(CLANG_EXECUTABLE_VERSION
|
||||
|
|
@ -246,10 +248,8 @@ mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
|
|||
|
||||
add_subdirectory(utils/TableGen)
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
|
||||
if(CLANG_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif ()
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
|
||||
add_subdirectory(examples)
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(lib)
|
||||
|
|
|
|||
|
|
@ -44,8 +44,43 @@
|
|||
#include <stdexcept>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
#include <strstream>
|
||||
#if __has_include(<strstream>)
|
||||
#include <strstream>
|
||||
#endif
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
#if __cplusplus >= 201103 || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
#include <array>
|
||||
#if __has_include(<atomic>)
|
||||
#include <atomic>
|
||||
#endif
|
||||
#include <chrono>
|
||||
#if __has_include(<codecvt>)
|
||||
#include <codecvt>
|
||||
#endif
|
||||
#include <condition_variable>
|
||||
#include <forward_list>
|
||||
#if __has_include(<future>)
|
||||
#include <future>
|
||||
#endif
|
||||
#include <initializer_list>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <ratio>
|
||||
#include <regex>
|
||||
#if __has_include(<scoped_allocator>)
|
||||
#include <scoped_allocator>
|
||||
#endif
|
||||
#include <system_error>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#if __has_include(<typeindex>)
|
||||
#include <typeindex>
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ LLVM Release License
|
|||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007-2011 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2007-2012 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
|
|
|||
11
NOTES.txt
11
NOTES.txt
|
|
@ -101,3 +101,14 @@ only if the non-reachability is not due to macro or template
|
|||
metaprogramming.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
We can still apply a modified version of the constructor/destructor
|
||||
delegation optimization in cases of virtual inheritance where:
|
||||
- there is no function-try-block,
|
||||
- the constructor signature is not variadic, and
|
||||
- the parameter variables can safely be copied and repassed
|
||||
to the base constructor because either
|
||||
- they have not had their addresses taken by the vbase initializers or
|
||||
- they were passed indirectly.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ call is efficient.
|
|||
# o implement additional SourceLocation, SourceRange, and File methods.
|
||||
|
||||
from ctypes import *
|
||||
import collections
|
||||
|
||||
def get_cindex_library():
|
||||
# FIXME: It's probably not the case that the library is actually found in
|
||||
|
|
@ -111,10 +112,21 @@ class SourceLocation(Structure):
|
|||
if self._data is None:
|
||||
f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
|
||||
SourceLocation_loc(self, byref(f), byref(l), byref(c), byref(o))
|
||||
f = File(f) if f else None
|
||||
if f:
|
||||
f = File(f)
|
||||
else:
|
||||
f = None
|
||||
self._data = (f, int(l.value), int(c.value), int(o.value))
|
||||
return self._data
|
||||
|
||||
@staticmethod
|
||||
def from_position(tu, file, line, column):
|
||||
"""
|
||||
Retrieve the source location associated with a given file/line/column in
|
||||
a particular translation unit.
|
||||
"""
|
||||
return SourceLocation_getLocation(tu, file, line, column)
|
||||
|
||||
@property
|
||||
def file(self):
|
||||
"""Get the file represented by this source location."""
|
||||
|
|
@ -135,9 +147,19 @@ class SourceLocation(Structure):
|
|||
"""Get the file offset represented by this source location."""
|
||||
return self._get_instantiation()[3]
|
||||
|
||||
def __eq__(self, other):
|
||||
return SourceLocation_equalLocations(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __repr__(self):
|
||||
if self.file:
|
||||
filename = self.file.name
|
||||
else:
|
||||
filename = None
|
||||
return "<SourceLocation file %r, line %r, column %r>" % (
|
||||
self.file.name if self.file else None, self.line, self.column)
|
||||
filename, self.line, self.column)
|
||||
|
||||
class SourceRange(Structure):
|
||||
"""
|
||||
|
|
@ -171,6 +193,12 @@ class SourceRange(Structure):
|
|||
"""
|
||||
return SourceRange_end(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
return SourceRange_equalRanges(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __repr__(self):
|
||||
return "<SourceRange start %r, end %r>" % (self.start, self.end)
|
||||
|
||||
|
|
@ -215,8 +243,8 @@ class Diagnostic(object):
|
|||
return int(_clang_getDiagnosticNumRanges(self.diag))
|
||||
|
||||
def __getitem__(self, key):
|
||||
if (key >= len(self)):
|
||||
raise IndexError
|
||||
if (key >= len(self)):
|
||||
raise IndexError
|
||||
return _clang_getDiagnosticRange(self.diag, key)
|
||||
|
||||
return RangeIterator(self)
|
||||
|
|
@ -240,6 +268,29 @@ class Diagnostic(object):
|
|||
|
||||
return FixItIterator(self)
|
||||
|
||||
@property
|
||||
def category_number(self):
|
||||
"""The category number for this diagnostic."""
|
||||
return _clang_getDiagnosticCategory(self)
|
||||
|
||||
@property
|
||||
def category_name(self):
|
||||
"""The string name of the category for this diagnostic."""
|
||||
return _clang_getDiagnosticCategoryName(self.category_number)
|
||||
|
||||
@property
|
||||
def option(self):
|
||||
"""The command-line option that enables this diagnostic."""
|
||||
return _clang_getDiagnosticOption(self, None)
|
||||
|
||||
@property
|
||||
def disable_option(self):
|
||||
"""The command-line option that disables this diagnostic."""
|
||||
disable = _CXString()
|
||||
_clang_getDiagnosticOption(self, byref(disable))
|
||||
|
||||
return _CXString_getCString(disable)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Diagnostic severity %r, location %r, spelling %r>" % (
|
||||
self.severity, self.location, self.spelling)
|
||||
|
|
@ -329,6 +380,18 @@ class CursorKind(object):
|
|||
"""Test if this is an invalid kind."""
|
||||
return CursorKind_is_inv(self)
|
||||
|
||||
def is_translation_unit(self):
|
||||
"""Test if this is a translation unit kind."""
|
||||
return CursorKind_is_translation_unit(self)
|
||||
|
||||
def is_preprocessing(self):
|
||||
"""Test if this is a preprocessing kind."""
|
||||
return CursorKind_is_preprocessing(self)
|
||||
|
||||
def is_unexposed(self):
|
||||
"""Test if this is an unexposed kind."""
|
||||
return CursorKind_is_unexposed(self)
|
||||
|
||||
def __repr__(self):
|
||||
return 'CursorKind.%s' % (self.name,)
|
||||
|
||||
|
|
@ -592,7 +655,7 @@ CursorKind.ADDR_LABEL_EXPR = CursorKind(120)
|
|||
# This is the GNU Statement Expression extension: ({int X=4; X;})
|
||||
CursorKind.StmtExpr = CursorKind(121)
|
||||
|
||||
# Represents a C1X generic selection.
|
||||
# Represents a C11 generic selection.
|
||||
CursorKind.GENERIC_SELECTION_EXPR = CursorKind(122)
|
||||
|
||||
# Implements the GNU __null extension, which is a name for a null
|
||||
|
|
@ -801,6 +864,11 @@ CursorKind.IB_ACTION_ATTR = CursorKind(401)
|
|||
CursorKind.IB_OUTLET_ATTR = CursorKind(402)
|
||||
CursorKind.IB_OUTLET_COLLECTION_ATTR = CursorKind(403)
|
||||
|
||||
CursorKind.CXX_FINAL_ATTR = CursorKind(404)
|
||||
CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
|
||||
CursorKind.ANNOTATE_ATTR = CursorKind(406)
|
||||
CursorKind.ASM_LABEL_ATTR = CursorKind(407)
|
||||
|
||||
###
|
||||
# Preprocessing
|
||||
CursorKind.PREPROCESSING_DIRECTIVE = CursorKind(500)
|
||||
|
|
@ -817,11 +885,15 @@ class Cursor(Structure):
|
|||
"""
|
||||
_fields_ = [("_kind_id", c_int), ("xdata", c_int), ("data", c_void_p * 3)]
|
||||
|
||||
@staticmethod
|
||||
def from_location(tu, location):
|
||||
return Cursor_get(tu, location)
|
||||
|
||||
def __eq__(self, other):
|
||||
return Cursor_eq(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not Cursor_eq(self, other)
|
||||
return not self.__eq__(other)
|
||||
|
||||
def is_definition(self):
|
||||
"""
|
||||
|
|
@ -903,13 +975,54 @@ class Cursor(Structure):
|
|||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Retrieve the type (if any) of of the entity pointed at by the
|
||||
cursor.
|
||||
Retrieve the Type (if any) of the entity pointed at by the cursor.
|
||||
"""
|
||||
if not hasattr(self, '_type'):
|
||||
self._type = Cursor_type(self)
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def underlying_typedef_type(self):
|
||||
"""Return the underlying type of a typedef declaration.
|
||||
|
||||
Returns a Type for the typedef this cursor is a declaration for. If
|
||||
the current cursor is not a typedef, this raises.
|
||||
"""
|
||||
if not hasattr(self, '_underlying_type'):
|
||||
assert self.kind.is_declaration()
|
||||
self._underlying_type = Cursor_underlying_type(self)
|
||||
|
||||
return self._underlying_type
|
||||
|
||||
@property
|
||||
def enum_type(self):
|
||||
"""Return the integer type of an enum declaration.
|
||||
|
||||
Returns a Type corresponding to an integer. If the cursor is not for an
|
||||
enum, this raises.
|
||||
"""
|
||||
if not hasattr(self, '_enum_type'):
|
||||
assert self.kind == CursorKind.ENUM_DECL
|
||||
self._enum_type = Cursor_enum_type(self)
|
||||
|
||||
return self._enum_type
|
||||
|
||||
@property
|
||||
def objc_type_encoding(self):
|
||||
"""Return the Objective-C type encoding as a str."""
|
||||
if not hasattr(self, '_objc_type_encoding'):
|
||||
self._objc_type_encoding = Cursor_objc_type_encoding(self)
|
||||
|
||||
return self._objc_type_encoding
|
||||
|
||||
@property
|
||||
def hash(self):
|
||||
"""Returns a hash of the cursor as an int."""
|
||||
if not hasattr(self, '_hash'):
|
||||
self._hash = Cursor_hash(self)
|
||||
|
||||
return self._hash
|
||||
|
||||
def get_children(self):
|
||||
"""Return an iterator for accessing the children of this cursor."""
|
||||
|
||||
|
|
@ -969,7 +1082,7 @@ class TypeKind(object):
|
|||
@staticmethod
|
||||
def from_id(id):
|
||||
if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
|
||||
raise ValueError,'Unknown cursor kind'
|
||||
raise ValueError,'Unknown type kind %d' % id
|
||||
return TypeKind._kinds[id]
|
||||
|
||||
def __repr__(self):
|
||||
|
|
@ -1020,6 +1133,7 @@ TypeKind.OBJCOBJECTPOINTER = TypeKind(109)
|
|||
TypeKind.FUNCTIONNOPROTO = TypeKind(110)
|
||||
TypeKind.FUNCTIONPROTO = TypeKind(111)
|
||||
TypeKind.CONSTANTARRAY = TypeKind(112)
|
||||
TypeKind.VECTOR = TypeKind(113)
|
||||
|
||||
class Type(Structure):
|
||||
"""
|
||||
|
|
@ -1032,6 +1146,71 @@ class Type(Structure):
|
|||
"""Return the kind of this type."""
|
||||
return TypeKind.from_id(self._kind_id)
|
||||
|
||||
def argument_types(self):
|
||||
"""Retrieve a container for the non-variadic arguments for this type.
|
||||
|
||||
The returned object is iterable and indexable. Each item in the
|
||||
container is a Type instance.
|
||||
"""
|
||||
class ArgumentsIterator(collections.Sequence):
|
||||
def __init__(self, parent):
|
||||
self.parent = parent
|
||||
self.length = None
|
||||
|
||||
def __len__(self):
|
||||
if self.length is None:
|
||||
self.length = Type_get_num_arg_types(self.parent)
|
||||
|
||||
return self.length
|
||||
|
||||
def __getitem__(self, key):
|
||||
# FIXME Support slice objects.
|
||||
if not isinstance(key, int):
|
||||
raise TypeError("Must supply a non-negative int.")
|
||||
|
||||
if key < 0:
|
||||
raise IndexError("Only non-negative indexes are accepted.")
|
||||
|
||||
if key >= len(self):
|
||||
raise IndexError("Index greater than container length: "
|
||||
"%d > %d" % ( key, len(self) ))
|
||||
|
||||
result = Type_get_arg_type(self.parent, key)
|
||||
if result.kind == TypeKind.INVALID:
|
||||
raise IndexError("Argument could not be retrieved.")
|
||||
|
||||
return result
|
||||
|
||||
assert self.kind == TypeKind.FUNCTIONPROTO
|
||||
return ArgumentsIterator(self)
|
||||
|
||||
@property
|
||||
def element_type(self):
|
||||
"""Retrieve the Type of elements within this Type.
|
||||
|
||||
If accessed on a type that is not an array, complex, or vector type, an
|
||||
exception will be raised.
|
||||
"""
|
||||
result = Type_get_element_type(self)
|
||||
if result.kind == TypeKind.INVALID:
|
||||
raise Exception('Element type not available on this type.')
|
||||
|
||||
return result
|
||||
|
||||
@property
|
||||
def element_count(self):
|
||||
"""Retrieve the number of elements in this type.
|
||||
|
||||
Returns an int.
|
||||
|
||||
If the Type is not an array or vector, this raises.
|
||||
"""
|
||||
result = Type_get_num_elements(self)
|
||||
if result < 0:
|
||||
raise Exception('Type does not have elements.')
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def from_result(res, fn, args):
|
||||
assert isinstance(res, Type)
|
||||
|
|
@ -1050,29 +1229,39 @@ class Type(Structure):
|
|||
return Type_get_canonical(self)
|
||||
|
||||
def is_const_qualified(self):
|
||||
"""
|
||||
Determine whether a Type has the "const" qualifier set,
|
||||
without looking through typedefs that may have added "const"
|
||||
"""Determine whether a Type has the "const" qualifier set.
|
||||
|
||||
This does not look through typedefs that may have added "const"
|
||||
at a different level.
|
||||
"""
|
||||
return Type_is_const_qualified(self)
|
||||
|
||||
def is_volatile_qualified(self):
|
||||
"""
|
||||
Determine whether a Type has the "volatile" qualifier set,
|
||||
without looking through typedefs that may have added
|
||||
"volatile" at a different level.
|
||||
"""Determine whether a Type has the "volatile" qualifier set.
|
||||
|
||||
This does not look through typedefs that may have added "volatile"
|
||||
at a different level.
|
||||
"""
|
||||
return Type_is_volatile_qualified(self)
|
||||
|
||||
def is_restrict_qualified(self):
|
||||
"""
|
||||
Determine whether a Type has the "restrict" qualifier set,
|
||||
without looking through typedefs that may have added
|
||||
"restrict" at a different level.
|
||||
"""Determine whether a Type has the "restrict" qualifier set.
|
||||
|
||||
This does not look through typedefs that may have added "restrict" at
|
||||
a different level.
|
||||
"""
|
||||
return Type_is_restrict_qualified(self)
|
||||
|
||||
def is_function_variadic(self):
|
||||
"""Determine whether this function Type is a variadic function type."""
|
||||
assert self.kind == TypeKind.FUNCTIONPROTO
|
||||
|
||||
return Type_is_variadic(self)
|
||||
|
||||
def is_pod(self):
|
||||
"""Determine whether this Type represents plain old data (POD)."""
|
||||
return Type_is_pod(self)
|
||||
|
||||
def get_pointee(self):
|
||||
"""
|
||||
For pointer types, returns the type of the pointee.
|
||||
|
|
@ -1091,6 +1280,27 @@ class Type(Structure):
|
|||
"""
|
||||
return Type_get_result(self)
|
||||
|
||||
def get_array_element_type(self):
|
||||
"""
|
||||
Retrieve the type of the elements of the array type.
|
||||
"""
|
||||
return Type_get_array_element(self)
|
||||
|
||||
def get_array_size(self):
|
||||
"""
|
||||
Retrieve the size of the constant array.
|
||||
"""
|
||||
return Type_get_array_size(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
if type(other) != type(self):
|
||||
return False
|
||||
|
||||
return Type_equal(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
## CIndex Objects ##
|
||||
|
||||
# CIndex objects (derived from ClangObject) are essentially lightweight
|
||||
|
|
@ -1157,6 +1367,20 @@ _clang_getDiagnosticFixIt.argtypes = [Diagnostic, c_uint, POINTER(SourceRange)]
|
|||
_clang_getDiagnosticFixIt.restype = _CXString
|
||||
_clang_getDiagnosticFixIt.errcheck = _CXString.from_result
|
||||
|
||||
_clang_getDiagnosticCategory = lib.clang_getDiagnosticCategory
|
||||
_clang_getDiagnosticCategory.argtypes = [Diagnostic]
|
||||
_clang_getDiagnosticCategory.restype = c_uint
|
||||
|
||||
_clang_getDiagnosticCategoryName = lib.clang_getDiagnosticCategoryName
|
||||
_clang_getDiagnosticCategoryName.argtypes = [c_uint]
|
||||
_clang_getDiagnosticCategoryName.restype = _CXString
|
||||
_clang_getDiagnosticCategoryName.errcheck = _CXString.from_result
|
||||
|
||||
_clang_getDiagnosticOption = lib.clang_getDiagnosticOption
|
||||
_clang_getDiagnosticOption.argtypes = [Diagnostic, POINTER(_CXString)]
|
||||
_clang_getDiagnosticOption.restype = _CXString
|
||||
_clang_getDiagnosticOption.errcheck = _CXString.from_result
|
||||
|
||||
###
|
||||
|
||||
class CompletionChunk:
|
||||
|
|
@ -1350,7 +1574,9 @@ class Index(ClangObject):
|
|||
def read(self, path):
|
||||
"""Load the translation unit from the given AST file."""
|
||||
ptr = TranslationUnit_read(self, path)
|
||||
return TranslationUnit(ptr) if ptr else None
|
||||
if ptr:
|
||||
return TranslationUnit(ptr)
|
||||
return None
|
||||
|
||||
def parse(self, path, args = [], unsaved_files = [], options = 0):
|
||||
"""
|
||||
|
|
@ -1383,7 +1609,9 @@ class Index(ClangObject):
|
|||
ptr = TranslationUnit_parse(self, path, arg_array, len(args),
|
||||
unsaved_files_array, len(unsaved_files),
|
||||
options)
|
||||
return TranslationUnit(ptr) if ptr else None
|
||||
if ptr:
|
||||
return TranslationUnit(ptr)
|
||||
return None
|
||||
|
||||
|
||||
class TranslationUnit(ClangObject):
|
||||
|
|
@ -1502,8 +1730,9 @@ class TranslationUnit(ClangObject):
|
|||
unsaved_files_array,
|
||||
len(unsaved_files),
|
||||
options)
|
||||
return CodeCompletionResults(ptr) if ptr else None
|
||||
|
||||
if ptr:
|
||||
return CodeCompletionResults(ptr)
|
||||
return None
|
||||
|
||||
class File(ClangObject):
|
||||
"""
|
||||
|
|
@ -1511,6 +1740,11 @@ class File(ClangObject):
|
|||
translation unit.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def from_name(translation_unit, file_name):
|
||||
"""Retrieve a file handle within the given translation unit."""
|
||||
return File(File_getFile(translation_unit, file_name))
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the complete file and path name of the file."""
|
||||
|
|
@ -1521,6 +1755,12 @@ class File(ClangObject):
|
|||
"""Return the last modification time of the file."""
|
||||
return File_time(self)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "<File: %s>" % (self.name)
|
||||
|
||||
class FileInclusion(object):
|
||||
"""
|
||||
The FileInclusion class represents the inclusion of one source file by
|
||||
|
|
@ -1557,6 +1797,14 @@ SourceLocation_loc.argtypes = [SourceLocation, POINTER(c_object_p),
|
|||
POINTER(c_uint), POINTER(c_uint),
|
||||
POINTER(c_uint)]
|
||||
|
||||
SourceLocation_getLocation = lib.clang_getLocation
|
||||
SourceLocation_getLocation.argtypes = [TranslationUnit, File, c_uint, c_uint]
|
||||
SourceLocation_getLocation.restype = SourceLocation
|
||||
|
||||
SourceLocation_equalLocations = lib.clang_equalLocations
|
||||
SourceLocation_equalLocations.argtypes = [SourceLocation, SourceLocation]
|
||||
SourceLocation_equalLocations.restype = bool
|
||||
|
||||
# Source Range Functions
|
||||
SourceRange_getRange = lib.clang_getRange
|
||||
SourceRange_getRange.argtypes = [SourceLocation, SourceLocation]
|
||||
|
|
@ -1570,6 +1818,10 @@ SourceRange_end = lib.clang_getRangeEnd
|
|||
SourceRange_end.argtypes = [SourceRange]
|
||||
SourceRange_end.restype = SourceLocation
|
||||
|
||||
SourceRange_equalRanges = lib.clang_equalRanges
|
||||
SourceRange_equalRanges.argtypes = [SourceRange, SourceRange]
|
||||
SourceRange_equalRanges.restype = bool
|
||||
|
||||
# CursorKind Functions
|
||||
CursorKind_is_decl = lib.clang_isDeclaration
|
||||
CursorKind_is_decl.argtypes = [CursorKind]
|
||||
|
|
@ -1595,6 +1847,18 @@ CursorKind_is_inv = lib.clang_isInvalid
|
|||
CursorKind_is_inv.argtypes = [CursorKind]
|
||||
CursorKind_is_inv.restype = bool
|
||||
|
||||
CursorKind_is_translation_unit = lib.clang_isTranslationUnit
|
||||
CursorKind_is_translation_unit.argtypes = [CursorKind]
|
||||
CursorKind_is_translation_unit.restype = bool
|
||||
|
||||
CursorKind_is_preprocessing = lib.clang_isPreprocessing
|
||||
CursorKind_is_preprocessing.argtypes = [CursorKind]
|
||||
CursorKind_is_preprocessing.restype = bool
|
||||
|
||||
CursorKind_is_unexposed = lib.clang_isUnexposed
|
||||
CursorKind_is_unexposed.argtypes = [CursorKind]
|
||||
CursorKind_is_unexposed.restype = bool
|
||||
|
||||
# Cursor Functions
|
||||
# TODO: Implement this function
|
||||
Cursor_get = lib.clang_getCursor
|
||||
|
|
@ -1620,7 +1884,11 @@ Cursor_def.errcheck = Cursor.from_result
|
|||
|
||||
Cursor_eq = lib.clang_equalCursors
|
||||
Cursor_eq.argtypes = [Cursor, Cursor]
|
||||
Cursor_eq.restype = c_uint
|
||||
Cursor_eq.restype = bool
|
||||
|
||||
Cursor_hash = lib.clang_hashCursor
|
||||
Cursor_hash.argtypes = [Cursor]
|
||||
Cursor_hash.restype = c_uint
|
||||
|
||||
Cursor_spelling = lib.clang_getCursorSpelling
|
||||
Cursor_spelling.argtypes = [Cursor]
|
||||
|
|
@ -1650,6 +1918,21 @@ Cursor_type.argtypes = [Cursor]
|
|||
Cursor_type.restype = Type
|
||||
Cursor_type.errcheck = Type.from_result
|
||||
|
||||
Cursor_underlying_type = lib.clang_getTypedefDeclUnderlyingType
|
||||
Cursor_underlying_type.argtypes = [Cursor]
|
||||
Cursor_underlying_type.restype = Type
|
||||
Cursor_underlying_type.errcheck = Type.from_result
|
||||
|
||||
Cursor_enum_type = lib.clang_getEnumDeclIntegerType
|
||||
Cursor_enum_type.argtypes = [Cursor]
|
||||
Cursor_enum_type.restype = Type
|
||||
Cursor_enum_type.errcheck = Type.from_result
|
||||
|
||||
Cursor_objc_type_encoding = lib.clang_getDeclObjCTypeEncoding
|
||||
Cursor_objc_type_encoding.argtypes = [Cursor]
|
||||
Cursor_objc_type_encoding.restype = _CXString
|
||||
Cursor_objc_type_encoding.errcheck = _CXString.from_result
|
||||
|
||||
Cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
|
||||
Cursor_visit = lib.clang_visitChildren
|
||||
Cursor_visit.argtypes = [Cursor, Cursor_visit_callback, py_object]
|
||||
|
|
@ -1673,6 +1956,14 @@ Type_is_restrict_qualified = lib.clang_isRestrictQualifiedType
|
|||
Type_is_restrict_qualified.argtypes = [Type]
|
||||
Type_is_restrict_qualified.restype = bool
|
||||
|
||||
Type_is_pod = lib.clang_isPODType
|
||||
Type_is_pod.argtypes = [Type]
|
||||
Type_is_pod.restype = bool
|
||||
|
||||
Type_is_variadic = lib.clang_isFunctionTypeVariadic
|
||||
Type_is_variadic.argtypes = [Type]
|
||||
Type_is_variadic.restype = bool
|
||||
|
||||
Type_get_pointee = lib.clang_getPointeeType
|
||||
Type_get_pointee.argtypes = [Type]
|
||||
Type_get_pointee.restype = Type
|
||||
|
|
@ -1688,6 +1979,36 @@ Type_get_result.argtypes = [Type]
|
|||
Type_get_result.restype = Type
|
||||
Type_get_result.errcheck = Type.from_result
|
||||
|
||||
Type_get_num_arg_types = lib.clang_getNumArgTypes
|
||||
Type_get_num_arg_types.argtypes = [Type]
|
||||
Type_get_num_arg_types.restype = c_uint
|
||||
|
||||
Type_get_arg_type = lib.clang_getArgType
|
||||
Type_get_arg_type.argtypes = [Type, c_uint]
|
||||
Type_get_arg_type.restype = Type
|
||||
Type_get_arg_type.errcheck = Type.from_result
|
||||
Type_get_element_type = lib.clang_getElementType
|
||||
|
||||
Type_get_element_type.argtypes = [Type]
|
||||
Type_get_element_type.restype = Type
|
||||
Type_get_element_type.errcheck = Type.from_result
|
||||
|
||||
Type_get_num_elements = lib.clang_getNumElements
|
||||
Type_get_num_elements.argtypes = [Type]
|
||||
Type_get_num_elements.restype = c_longlong
|
||||
|
||||
Type_get_array_element = lib.clang_getArrayElementType
|
||||
Type_get_array_element.argtypes = [Type]
|
||||
Type_get_array_element.restype = Type
|
||||
Type_get_array_element.errcheck = Type.from_result
|
||||
|
||||
Type_get_array_size = lib.clang_getArraySize
|
||||
Type_get_array_size.argtype = [Type]
|
||||
Type_get_array_size.restype = c_longlong
|
||||
|
||||
Type_equal = lib.clang_equalTypes
|
||||
Type_equal.argtypes = [Type, Type]
|
||||
Type_equal.restype = bool
|
||||
|
||||
# Index Functions
|
||||
Index_create = lib.clang_createIndex
|
||||
|
|
@ -1739,6 +2060,10 @@ TranslationUnit_includes.argtypes = [TranslationUnit,
|
|||
py_object]
|
||||
|
||||
# File Functions
|
||||
File_getFile = lib.clang_getFile
|
||||
File_getFile.argtypes = [TranslationUnit, c_char_p]
|
||||
File_getFile.restype = c_object_p
|
||||
|
||||
File_name = lib.clang_getFileName
|
||||
File_name.argtypes = [File]
|
||||
File_name.restype = _CXString
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
from clang.cindex import Index, CursorKind, TypeKind
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import TypeKind
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
kInput = """\
|
||||
// FIXME: Find nicer way to drop builtins and other cruft.
|
||||
|
|
@ -24,9 +27,8 @@ void f0(int a0, int a1) {
|
|||
"""
|
||||
|
||||
def test_get_children():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
|
||||
|
||||
tu = get_tu(kInput)
|
||||
|
||||
# Skip until past start_decl.
|
||||
it = tu.cursor.get_children()
|
||||
while it.next().spelling != 'start_decl':
|
||||
|
|
@ -36,12 +38,14 @@ def test_get_children():
|
|||
|
||||
assert len(tu_nodes) == 3
|
||||
|
||||
assert tu_nodes[0] != tu_nodes[1]
|
||||
assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
|
||||
assert tu_nodes[0].spelling == 's0'
|
||||
assert tu_nodes[0].is_definition() == True
|
||||
assert tu_nodes[0].location.file.name == 't.c'
|
||||
assert tu_nodes[0].location.line == 4
|
||||
assert tu_nodes[0].location.column == 8
|
||||
assert tu_nodes[0].hash > 0
|
||||
|
||||
s0_nodes = list(tu_nodes[0].get_children())
|
||||
assert len(s0_nodes) == 2
|
||||
|
|
@ -61,3 +65,28 @@ def test_get_children():
|
|||
assert tu_nodes[2].spelling == 'f0'
|
||||
assert tu_nodes[2].displayname == 'f0(int, int)'
|
||||
assert tu_nodes[2].is_definition() == True
|
||||
|
||||
def test_underlying_type():
|
||||
tu = get_tu('typedef int foo;')
|
||||
typedef = get_cursor(tu, 'foo')
|
||||
assert typedef is not None
|
||||
|
||||
assert typedef.kind.is_declaration()
|
||||
underlying = typedef.underlying_typedef_type
|
||||
assert underlying.kind == TypeKind.INT
|
||||
|
||||
def test_enum_type():
|
||||
tu = get_tu('enum TEST { FOO=1, BAR=2 };')
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
enum_type = enum.enum_type
|
||||
assert enum_type.kind == TypeKind.UINT
|
||||
|
||||
def test_objc_type_encoding():
|
||||
tu = get_tu('int i;', lang='objc')
|
||||
i = get_cursor(tu, 'i')
|
||||
|
||||
assert i is not None
|
||||
assert i.objc_type_encoding == 'i'
|
||||
|
|
|
|||
|
|
@ -16,6 +16,15 @@ def test_kind_groups():
|
|||
assert CursorKind.UNEXPOSED_STMT.is_statement()
|
||||
assert CursorKind.INVALID_FILE.is_invalid()
|
||||
|
||||
assert CursorKind.TRANSLATION_UNIT.is_translation_unit()
|
||||
assert not CursorKind.TYPE_REF.is_translation_unit()
|
||||
|
||||
assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing()
|
||||
assert not CursorKind.TYPE_REF.is_preprocessing()
|
||||
|
||||
assert CursorKind.UNEXPOSED_DECL.is_unexposed()
|
||||
assert not CursorKind.TYPE_REF.is_unexposed()
|
||||
|
||||
for k in CursorKind.get_all_kinds():
|
||||
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
|
||||
'is_statement', 'is_invalid', 'is_attribute')
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
from clang.cindex import *
|
||||
|
||||
def tu_from_source(source):
|
||||
index = Index.create()
|
||||
tu = index.parse('INPUT.c', unsaved_files = [('INPUT.c', source)])
|
||||
return tu
|
||||
from .util import get_tu
|
||||
|
||||
# FIXME: We need support for invalid translation units to test better.
|
||||
|
||||
def test_diagnostic_warning():
|
||||
tu = tu_from_source("""int f0() {}\n""")
|
||||
tu = get_tu('int f0() {}\n')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
|
|
@ -18,8 +14,7 @@ def test_diagnostic_warning():
|
|||
|
||||
def test_diagnostic_note():
|
||||
# FIXME: We aren't getting notes here for some reason.
|
||||
index = Index.create()
|
||||
tu = tu_from_source("""#define A x\nvoid *A = 1;\n""")
|
||||
tu = get_tu('#define A x\nvoid *A = 1;\n')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 2
|
||||
|
|
@ -31,8 +26,7 @@ def test_diagnostic_note():
|
|||
# assert tu.diagnostics[1].spelling == 'instantiated from'
|
||||
|
||||
def test_diagnostic_fixit():
|
||||
index = Index.create()
|
||||
tu = tu_from_source("""struct { int f0; } x = { f0 : 1 };""")
|
||||
tu = get_tu('struct { int f0; } x = { f0 : 1 };')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
|
|
@ -46,8 +40,7 @@ def test_diagnostic_fixit():
|
|||
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
|
||||
|
||||
def test_diagnostic_range():
|
||||
index = Index.create()
|
||||
tu = tu_from_source("""void f() { int i = "a" + 1; }""")
|
||||
tu = get_tu('void f() { int i = "a" + 1; }')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
|
|
@ -65,5 +58,25 @@ def test_diagnostic_range():
|
|||
assert True
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
||||
def test_diagnostic_category():
|
||||
"""Ensure that category properties work."""
|
||||
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
|
||||
assert len(tu.diagnostics) == 1
|
||||
d = tu.diagnostics[0]
|
||||
|
||||
assert d.severity == Diagnostic.Warning
|
||||
assert d.location.line == 1
|
||||
assert d.location.column == 11
|
||||
|
||||
assert d.category_number == 2
|
||||
assert d.category_name == 'Semantic Issue'
|
||||
|
||||
def test_diagnostic_option():
|
||||
"""Ensure that category option properties work."""
|
||||
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
|
||||
assert len(tu.diagnostics) == 1
|
||||
d = tu.diagnostics[0]
|
||||
|
||||
assert d.option == '-Wunused-parameter'
|
||||
assert d.disable_option == '-Wno-unused-parameter'
|
||||
|
|
|
|||
9
bindings/python/tests/cindex/test_file.py
Normal file
9
bindings/python/tests/cindex/test_file.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from clang.cindex import Index, File
|
||||
|
||||
def test_file():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c', "")])
|
||||
file = File.from_name(tu, "t.c")
|
||||
assert str(file) == "t.c"
|
||||
assert file.name == "t.c"
|
||||
assert repr(file) == "<File: t.c>"
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
from clang.cindex import Index
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import File
|
||||
from clang.cindex import SourceLocation
|
||||
from clang.cindex import SourceRange
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
baseInput="int one;\nint two;\n"
|
||||
|
||||
|
|
@ -8,43 +13,74 @@ def assert_location(loc, line, column, offset):
|
|||
assert loc.offset == offset
|
||||
|
||||
def test_location():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
|
||||
tu = get_tu(baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.location,line=1,column=5,offset=4)
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.location,line=2,column=5,offset=13)
|
||||
assert one is not None
|
||||
assert two is not None
|
||||
|
||||
assert_location(one.location,line=1,column=5,offset=4)
|
||||
assert_location(two.location,line=2,column=5,offset=13)
|
||||
|
||||
# adding a linebreak at top should keep columns same
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',"\n"+baseInput)])
|
||||
tu = get_tu('\n' + baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.location,line=2,column=5,offset=5)
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.location,line=3,column=5,offset=14)
|
||||
assert one is not None
|
||||
assert two is not None
|
||||
|
||||
assert_location(one.location,line=2,column=5,offset=5)
|
||||
assert_location(two.location,line=3,column=5,offset=14)
|
||||
|
||||
# adding a space should affect column on first line only
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c'," "+baseInput)])
|
||||
tu = get_tu(' ' + baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.location,line=1,column=6,offset=5)
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.location,line=2,column=5,offset=14)
|
||||
assert_location(one.location,line=1,column=6,offset=5)
|
||||
assert_location(two.location,line=2,column=5,offset=14)
|
||||
|
||||
# define the expected location ourselves and see if it matches
|
||||
# the returned location
|
||||
tu = get_tu(baseInput)
|
||||
|
||||
file = File.from_name(tu, 't.c')
|
||||
location = SourceLocation.from_position(tu, file, 1, 5)
|
||||
cursor = Cursor.from_location(tu, location)
|
||||
|
||||
one = get_cursor(tu, 'one')
|
||||
assert one is not None
|
||||
assert one == cursor
|
||||
|
||||
# Ensure locations referring to the same entity are equivalent.
|
||||
location2 = SourceLocation.from_position(tu, file, 1, 5)
|
||||
assert location == location2
|
||||
location3 = SourceLocation.from_position(tu, file, 1, 4)
|
||||
assert location2 != location3
|
||||
|
||||
def test_extent():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
|
||||
tu = get_tu(baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'one':
|
||||
assert_location(n.extent.start,line=1,column=1,offset=0)
|
||||
assert_location(n.extent.end,line=1,column=8,offset=7)
|
||||
assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int one"
|
||||
if n.spelling == 'two':
|
||||
assert_location(n.extent.start,line=2,column=1,offset=9)
|
||||
assert_location(n.extent.end,line=2,column=8,offset=16)
|
||||
assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int two"
|
||||
assert_location(one.extent.start,line=1,column=1,offset=0)
|
||||
assert_location(one.extent.end,line=1,column=8,offset=7)
|
||||
assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one"
|
||||
|
||||
assert_location(two.extent.start,line=2,column=1,offset=9)
|
||||
assert_location(two.extent.end,line=2,column=8,offset=16)
|
||||
assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two"
|
||||
|
||||
file = File.from_name(tu, 't.c')
|
||||
location1 = SourceLocation.from_position(tu, file, 1, 1)
|
||||
location2 = SourceLocation.from_position(tu, file, 1, 8)
|
||||
|
||||
range1 = SourceRange.from_locations(location1, location2)
|
||||
range2 = SourceRange.from_locations(location1, location2)
|
||||
assert range1 == range2
|
||||
|
||||
location3 = SourceLocation.from_position(tu, file, 1, 6)
|
||||
range3 = SourceRange.from_locations(location1, location3)
|
||||
assert range1 != range3
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
from clang.cindex import Index, CursorKind, TypeKind
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import Index
|
||||
from clang.cindex import TypeKind
|
||||
from nose.tools import raises
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
kInput = """\
|
||||
|
||||
|
|
@ -18,63 +23,55 @@ struct teststruct {
|
|||
"""
|
||||
|
||||
def test_a_struct():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
|
||||
tu = get_tu(kInput)
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'teststruct':
|
||||
fields = list(n.get_children())
|
||||
teststruct = get_cursor(tu, 'teststruct')
|
||||
assert teststruct is not None, "Could not find teststruct."
|
||||
fields = list(teststruct.get_children())
|
||||
assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
|
||||
|
||||
assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
|
||||
assert fields[0].spelling == 'a'
|
||||
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].spelling == 'a'
|
||||
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[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].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[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].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[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].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[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].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[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].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[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[7].spelling == 'h'
|
||||
assert not fields[7].type.is_const_qualified()
|
||||
assert fields[7].type.kind == TypeKind.POINTER
|
||||
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
|
||||
|
||||
break
|
||||
|
||||
else:
|
||||
assert False, "Didn't find teststruct??"
|
||||
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[7].spelling == 'h'
|
||||
assert not fields[7].type.is_const_qualified()
|
||||
assert fields[7].type.kind == TypeKind.POINTER
|
||||
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
|
||||
|
||||
constarrayInput="""
|
||||
struct teststruct {
|
||||
|
|
@ -82,14 +79,191 @@ struct teststruct {
|
|||
};
|
||||
"""
|
||||
def testConstantArray():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',constarrayInput)])
|
||||
tu = get_tu(constarrayInput)
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'teststruct':
|
||||
fields = list(n.get_children())
|
||||
assert fields[0].spelling == 'A'
|
||||
assert fields[0].type.kind == TypeKind.CONSTANTARRAY
|
||||
break
|
||||
else:
|
||||
assert False, "Didn't find teststruct??"
|
||||
teststruct = get_cursor(tu, 'teststruct')
|
||||
assert teststruct is not None, "Didn't find teststruct??"
|
||||
fields = list(teststruct.get_children())
|
||||
assert fields[0].spelling == 'A'
|
||||
assert fields[0].type.kind == TypeKind.CONSTANTARRAY
|
||||
assert fields[0].type.get_array_element_type() is not None
|
||||
assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
|
||||
assert fields[0].type.get_array_size() == 2
|
||||
|
||||
def test_equal():
|
||||
"""Ensure equivalence operators work on Type."""
|
||||
source = 'int a; int b; void *v;'
|
||||
tu = get_tu(source)
|
||||
|
||||
a = get_cursor(tu, 'a')
|
||||
b = get_cursor(tu, 'b')
|
||||
v = get_cursor(tu, 'v')
|
||||
|
||||
assert a is not None
|
||||
assert b is not None
|
||||
assert v is not None
|
||||
|
||||
assert a.type == b.type
|
||||
assert a.type != v.type
|
||||
|
||||
assert a.type != None
|
||||
assert a.type != 'foo'
|
||||
|
||||
def test_function_argument_types():
|
||||
"""Ensure that Type.argument_types() works as expected."""
|
||||
tu = get_tu('void f(int, int);')
|
||||
f = get_cursor(tu, 'f')
|
||||
assert f is not None
|
||||
|
||||
args = f.type.argument_types()
|
||||
assert args is not None
|
||||
assert len(args) == 2
|
||||
|
||||
t0 = args[0]
|
||||
assert t0 is not None
|
||||
assert t0.kind == TypeKind.INT
|
||||
|
||||
t1 = args[1]
|
||||
assert t1 is not None
|
||||
assert t1.kind == TypeKind.INT
|
||||
|
||||
args2 = list(args)
|
||||
assert len(args2) == 2
|
||||
assert t0 == args2[0]
|
||||
assert t1 == args2[1]
|
||||
|
||||
@raises(TypeError)
|
||||
def test_argument_types_string_key():
|
||||
"""Ensure that non-int keys raise a TypeError."""
|
||||
tu = get_tu('void f(int, int);')
|
||||
f = get_cursor(tu, 'f')
|
||||
assert f is not None
|
||||
|
||||
args = f.type.argument_types()
|
||||
assert len(args) == 2
|
||||
|
||||
args['foo']
|
||||
|
||||
@raises(IndexError)
|
||||
def test_argument_types_negative_index():
|
||||
"""Ensure that negative indexes on argument_types Raises an IndexError."""
|
||||
tu = get_tu('void f(int, int);')
|
||||
f = get_cursor(tu, 'f')
|
||||
args = f.type.argument_types()
|
||||
|
||||
args[-1]
|
||||
|
||||
@raises(IndexError)
|
||||
def test_argument_types_overflow_index():
|
||||
"""Ensure that indexes beyond the length of Type.argument_types() raise."""
|
||||
tu = get_tu('void f(int, int);')
|
||||
f = get_cursor(tu, 'f')
|
||||
args = f.type.argument_types()
|
||||
|
||||
args[2]
|
||||
|
||||
@raises(Exception)
|
||||
def test_argument_types_invalid_type():
|
||||
"""Ensure that obtaining argument_types on a Type without them raises."""
|
||||
tu = get_tu('int i;')
|
||||
i = get_cursor(tu, 'i')
|
||||
assert i is not None
|
||||
|
||||
i.type.argument_types()
|
||||
|
||||
def test_is_pod():
|
||||
"""Ensure Type.is_pod() works."""
|
||||
tu = get_tu('int i; void f();')
|
||||
i = get_cursor(tu, 'i')
|
||||
f = get_cursor(tu, 'f')
|
||||
|
||||
assert i is not None
|
||||
assert f is not None
|
||||
|
||||
assert i.type.is_pod()
|
||||
assert not f.type.is_pod()
|
||||
|
||||
def test_function_variadic():
|
||||
"""Ensure Type.is_function_variadic works."""
|
||||
|
||||
source ="""
|
||||
#include <stdarg.h>
|
||||
|
||||
void foo(int a, ...);
|
||||
void bar(int a, int b);
|
||||
"""
|
||||
|
||||
tu = get_tu(source)
|
||||
foo = get_cursor(tu, 'foo')
|
||||
bar = get_cursor(tu, 'bar')
|
||||
|
||||
assert foo is not None
|
||||
assert bar is not None
|
||||
|
||||
assert isinstance(foo.type.is_function_variadic(), bool)
|
||||
assert foo.type.is_function_variadic()
|
||||
assert not bar.type.is_function_variadic()
|
||||
|
||||
def test_element_type():
|
||||
"""Ensure Type.element_type works."""
|
||||
tu = get_tu('int i[5];')
|
||||
i = get_cursor(tu, 'i')
|
||||
assert i is not None
|
||||
|
||||
assert i.type.kind == TypeKind.CONSTANTARRAY
|
||||
assert i.type.element_type.kind == TypeKind.INT
|
||||
|
||||
@raises(Exception)
|
||||
def test_invalid_element_type():
|
||||
"""Ensure Type.element_type raises if type doesn't have elements."""
|
||||
tu = get_tu('int i;')
|
||||
i = get_cursor(tu, 'i')
|
||||
assert i is not None
|
||||
i.element_type
|
||||
|
||||
def test_element_count():
|
||||
"""Ensure Type.element_count works."""
|
||||
tu = get_tu('int i[5]; int j;')
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert i.type.element_count == 5
|
||||
|
||||
try:
|
||||
j.type.element_count
|
||||
assert False
|
||||
except:
|
||||
assert True
|
||||
|
||||
def test_is_volatile_qualified():
|
||||
"""Ensure Type.is_volatile_qualified works."""
|
||||
|
||||
tu = get_tu('volatile int i = 4; int j = 2;')
|
||||
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert isinstance(i.type.is_volatile_qualified(), bool)
|
||||
assert i.type.is_volatile_qualified()
|
||||
assert not j.type.is_volatile_qualified()
|
||||
|
||||
def test_is_restrict_qualified():
|
||||
"""Ensure Type.is_restrict_qualified works."""
|
||||
|
||||
tu = get_tu('struct s { void * restrict i; void * j };')
|
||||
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert isinstance(i.type.is_restrict_qualified(), bool)
|
||||
assert i.type.is_restrict_qualified()
|
||||
assert not j.type.is_restrict_qualified()
|
||||
|
|
|
|||
65
bindings/python/tests/cindex/util.py
Normal file
65
bindings/python/tests/cindex/util.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# This file provides common utility functions for the test suite.
|
||||
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import Index
|
||||
|
||||
def get_tu(source, lang='c', all_warnings=False):
|
||||
"""Obtain a translation unit from source and language.
|
||||
|
||||
By default, the translation unit is created from source file "t.<ext>"
|
||||
where <ext> is the default file extension for the specified language. By
|
||||
default it is C, so "t.c" is the default file name.
|
||||
|
||||
Supported languages are {c, cpp, objc}.
|
||||
|
||||
all_warnings is a convenience argument to enable all compiler warnings.
|
||||
"""
|
||||
name = 't.c'
|
||||
if lang == 'cpp':
|
||||
name = 't.cpp'
|
||||
elif lang == 'objc':
|
||||
name = 't.m'
|
||||
elif lang != 'c':
|
||||
raise Exception('Unknown language: %s' % lang)
|
||||
|
||||
args = []
|
||||
if all_warnings:
|
||||
args = ['-Wall', '-Wextra']
|
||||
|
||||
index = Index.create()
|
||||
tu = index.parse(name, args=args, unsaved_files=[(name, source)])
|
||||
assert tu is not None
|
||||
return tu
|
||||
|
||||
def get_cursor(source, spelling):
|
||||
"""Obtain a cursor from a source object.
|
||||
|
||||
This provides a convenient search mechanism to find a cursor with specific
|
||||
spelling within a source. The first argument can be either a
|
||||
TranslationUnit or Cursor instance.
|
||||
|
||||
If the cursor is not found, None is returned.
|
||||
"""
|
||||
children = []
|
||||
if isinstance(source, Cursor):
|
||||
children = source.get_children()
|
||||
else:
|
||||
# Assume TU
|
||||
children = source.cursor.get_children()
|
||||
|
||||
for cursor in children:
|
||||
if cursor.spelling == spelling:
|
||||
return cursor
|
||||
|
||||
# Recurse into children.
|
||||
result = get_cursor(cursor, spelling)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
|
||||
__all__ = [
|
||||
'get_cursor',
|
||||
'get_tu',
|
||||
]
|
||||
139
docs/AddressSanitizer.html
Normal file
139
docs/AddressSanitizer.html
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
|
||||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>AddressSanitizer, a fast memory error detector</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>AddressSanitizer</h1>
|
||||
<ul>
|
||||
<li> <a href="intro">Introduction</a>
|
||||
<li> <a href="howtobuild">How to Build</a>
|
||||
<li> <a href="usage">Usage</a>
|
||||
<ul><li> <a href="has_feature">__has_feature(address_sanitizer)</a></ul>
|
||||
<li> <a href="platforms">Supported Platforms</a>
|
||||
<li> <a href="limitations">Limitations</a>
|
||||
<li> <a href="status">Current Status</a>
|
||||
<li> <a href="moreinfo">More Information</a>
|
||||
</ul>
|
||||
|
||||
<h2 id="intro">Introduction</h2>
|
||||
AddressSanitizer is a fast memory error detector.
|
||||
It consists of a compiler instrumentation module and a run-time library.
|
||||
The tool can detect the following types of bugs:
|
||||
<ul> <li> Out-of-bounds accesses to heap, stack and globals
|
||||
<li> Use-after-free
|
||||
<li> Use-after-return (to some extent)
|
||||
<li> Double-free, invalid free
|
||||
</ul>
|
||||
Typical slowdown introduced by AddressSanitizer is <b>2x</b>.
|
||||
|
||||
<h2 id="howtobuild">How to build</h2>
|
||||
Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
|
||||
Note: CMake build does not work yet.
|
||||
See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
|
||||
|
||||
<h2 id="usage">Usage</h2>
|
||||
Simply compile and link your program with <tt>-faddress-sanitizer</tt> flag. <BR>
|
||||
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
|
||||
To get nicer stack traces in error messages add
|
||||
<tt>-fno-omit-frame-pointer</tt>. <BR>
|
||||
To get perfect stack traces you may need to disable inlining (just use <tt>-O1</tt>) and tail call
|
||||
elimination (</tt>-fno-optimize-sibling-calls</tt>).
|
||||
|
||||
<pre>
|
||||
% cat example_UseAfterFree.cc
|
||||
int main(int argc, char **argv) {
|
||||
int *array = new int[100];
|
||||
delete [] array;
|
||||
return array[argc]; // BOOM
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
% clang -O1 -g -faddress-sanitizer -fno-omit-frame-pointer example_UseAfterFree.cc
|
||||
</pre>
|
||||
|
||||
If a bug is detected, the program will print an error message to stderr and exit with a
|
||||
non-zero exit code.
|
||||
Currently, AddressSanitizer does not symbolize its output, so you may need to use a
|
||||
separate script to symbolize the result offline (this will be fixed in future).
|
||||
<pre>
|
||||
% ./a.out 2> log
|
||||
% projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt
|
||||
==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
|
||||
READ of size 4 at 0x7f7ddab8c084 thread T0
|
||||
#0 0x403c8c in main example_UseAfterFree.cc:4
|
||||
#1 0x7f7ddabcac4d in __libc_start_main ??:0
|
||||
0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
|
||||
freed by thread T0 here:
|
||||
#0 0x404704 in operator delete[](void*) ??:0
|
||||
#1 0x403c53 in main example_UseAfterFree.cc:4
|
||||
#2 0x7f7ddabcac4d in __libc_start_main ??:0
|
||||
previously allocated by thread T0 here:
|
||||
#0 0x404544 in operator new[](unsigned long) ??:0
|
||||
#1 0x403c43 in main example_UseAfterFree.cc:2
|
||||
#2 0x7f7ddabcac4d in __libc_start_main ??:0
|
||||
==9442== ABORTING
|
||||
</pre>
|
||||
|
||||
<h3 id="has_feature">__has_feature(address_sanitizer)</h3>
|
||||
In some cases one may need to execute different code depending on whether
|
||||
AddressSanitizer is enabled.
|
||||
<a href="LanguageExtensions.html#__has_feature_extension">__has_feature</a>
|
||||
can be used for this purpose.
|
||||
<pre>
|
||||
#if defined(__has_feature) && __has_feature(address_sanitizer)
|
||||
code that runs only under AddressSanitizer
|
||||
#else
|
||||
code that does not run under AddressSanitizer
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
<h2 id="platforms">Supported Platforms</h2>
|
||||
AddressSanitizer is supported on
|
||||
<ul><li>Linux x86_64 (tested on Ubuntu 10.04).
|
||||
<li>MacOS 10.6 i386/x86_64.
|
||||
</ul>
|
||||
Support for Linux i386/ARM and MacOS 10.7 is in progress
|
||||
(it may work, but is not guaranteed too).
|
||||
|
||||
|
||||
<h2 id="limitations">Limitations</h2>
|
||||
<ul>
|
||||
<li> AddressSanitizer uses more real memory than a native run.
|
||||
How much -- depends on the allocations sizes. The smaller the
|
||||
allocations you make the bigger the overhead.
|
||||
<li> On 64-bit platforms AddressSanitizer maps (but not reserves)
|
||||
16+ Terabytes of virtual address space.
|
||||
This means that tools like <tt>ulimit</tt> may not work as usually expected.
|
||||
<li> Static linking is not supported.
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="status">Current Status</h2>
|
||||
AddressSanitizer is fully functional on supported platforms in LLVM head.
|
||||
However, the test suite is not fully integrated yet and we lack the testing
|
||||
process (buildbots).
|
||||
|
||||
<h2 id="moreinfo">More Information</h2>
|
||||
<a href="http://code.google.com/p/address-sanitizer/">http://code.google.com/p/address-sanitizer</a>.
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Static Analyzer Design Document: Memory Regions</title>
|
||||
|
|
@ -59,7 +61,7 @@ of structures) then the StoreManager can simply return 'unknown' (represented by
|
|||
concerns not only isolates the core analysis engine from the details of
|
||||
reasoning about program memory but also facilities the option of a client of the
|
||||
path-sensitive engine to easily swap in different StoreManager implementations
|
||||
that internally reason about program memory in very different ways.</pp>
|
||||
that internally reason about program memory in very different ways.</p>
|
||||
|
||||
<p>The rest of this document is divided into two parts. We first discuss region
|
||||
taxonomy and the semantics of regions. We then discuss the StoreManager
|
||||
|
|
@ -102,7 +104,7 @@ typedef struct s my_type;
|
|||
void *p;
|
||||
int *q = (int*) p;
|
||||
char *r = (char*) p;
|
||||
</pre
|
||||
</pre>
|
||||
|
||||
<p>Thus we need to canonicalize the MemRegion which is used in binding and
|
||||
retrieving.</p>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Objective-C Automatic Reference Counting (ARC)</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
/* Collapse the items in the ToC to the left. */
|
||||
div#toc ul {
|
||||
|
|
@ -18,6 +20,16 @@ div.rationale em {
|
|||
font-style: normal
|
||||
}
|
||||
|
||||
/* Revisions are also italicized. */
|
||||
span.revision {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
span.whenRevised {
|
||||
font-weight: bold;
|
||||
font-style: normal
|
||||
}
|
||||
|
||||
div h1 { font-size: 2em; margin: .67em 0 }
|
||||
div div h1 { font-size: 1.5em; margin: .75em 0 }
|
||||
div div div h1 { font-size: 1.17em; margin: .83em 0 }
|
||||
|
|
@ -26,7 +38,7 @@ div div div div h1 { margin: 1.12em 0 }
|
|||
span.term { font-style: italic; font-weight: bold }
|
||||
</style>
|
||||
|
||||
<script lang="javascript">
|
||||
<script type="text/javascript">
|
||||
/// A little script to recursively build a table of contents.
|
||||
function buildTOC(div, toc, ancestry) {
|
||||
var children = div.childNodes;
|
||||
|
|
@ -207,6 +219,38 @@ adjusting the reference count, not by calling <tt>Block_copy</tt>.</p>
|
|||
|
||||
</div> <!-- meta.background -->
|
||||
|
||||
<div id="meta.evolution">
|
||||
<h1>Evolution</h1>
|
||||
|
||||
<p>ARC is under continual evolution, and this document must be updated
|
||||
as the language progresses.</p>
|
||||
|
||||
<p>If a change increases the expressiveness of the language, for
|
||||
example by lifting a restriction or by adding new syntax, the change
|
||||
will be annotated with a revision marker, like so:</p>
|
||||
|
||||
<blockquote>
|
||||
ARC applies to Objective-C pointer types, block pointer types, and
|
||||
<span class="revision"><span class="whenRevised">[beginning Apple
|
||||
8.0, LLVM 3.8]</span> BPTRs declared within <code>extern
|
||||
"BCPL"</code> blocks</span>.
|
||||
</blockquote>
|
||||
|
||||
<p>For now, it is sensible to version this document by the releases of
|
||||
its sole implementation (and its host project), clang.
|
||||
<q>LLVM X.Y</q> refers to an open-source release of clang from the
|
||||
LLVM project. <q>Apple X.Y</q> refers to an Apple-provided release of
|
||||
the Apple LLVM Compiler. Other organizations that prepare their own,
|
||||
separately-versioned clang releases and wish to maintain similar
|
||||
information in this document should send requests to cfe-dev.</p>
|
||||
|
||||
<p>If a change decreases the expressiveness of the language, for
|
||||
example by imposing a new restriction, this should be taken as an
|
||||
oversight in the original specification and something to be avoided
|
||||
in all versions. Such changes are generally to be avoided.</p>
|
||||
|
||||
</div> <!-- meta.evolution -->
|
||||
|
||||
</div> <!-- meta -->
|
||||
|
||||
<div id="general">
|
||||
|
|
@ -214,8 +258,10 @@ adjusting the reference count, not by calling <tt>Block_copy</tt>.</p>
|
|||
|
||||
<p>Automatic Reference Counting implements automatic memory management
|
||||
for Objective-C objects and blocks, freeing the programmer from the
|
||||
need explicitly insert retains and releases. It does not provide a
|
||||
cycle collector; users must explicitly manage lifetime instead.</p>
|
||||
need to explicitly insert retains and releases. It does not provide a
|
||||
cycle collector; users must explicitly manage the lifetime of their
|
||||
objects, breaking cycles manually or with weak or unsafe
|
||||
references.</p>
|
||||
|
||||
<p>ARC may be explicitly enabled with the compiler
|
||||
flag <tt>-fobjc-arc</tt>. It may also be explicitly disabled with the
|
||||
|
|
@ -227,7 +273,7 @@ appearing on the compile line <q>wins</q>.</p>
|
|||
see the <a href="LanguageExtensions.html#__has_feature_extension">language
|
||||
extensions</a> document.</p>
|
||||
|
||||
</div>
|
||||
</div> <!-- general -->
|
||||
|
||||
<div id="objects">
|
||||
<h1>Retainable object pointers</h1>
|
||||
|
|
@ -444,9 +490,9 @@ The rule about function calls is really just an application of the
|
|||
existing C/C++ rule about calling functions through an incompatible
|
||||
function type, but it's useful to state it explicitly.</p></div>
|
||||
|
||||
</div>
|
||||
</div> <!-- objects.operands.consumed -->
|
||||
|
||||
<div id="objects.operands.retained_returns">
|
||||
<div id="objects.operands.retained-returns">
|
||||
<h1>Retained return values</h1>
|
||||
|
||||
<p>A function or method which returns a retainable object pointer type
|
||||
|
|
@ -481,7 +527,6 @@ and <tt>new</tt> <a href="#family">families</a> are implicitly marked
|
|||
<tt>__attribute__((ns_returns_retained))</tt>. This may be suppressed
|
||||
by explicitly marking the
|
||||
method <tt>__attribute__((ns_returns_not_retained))</tt>.</p>
|
||||
</div>
|
||||
|
||||
<p>It is undefined behavior if the method to which an Objective-C
|
||||
message send statically resolves has different retain semantics on its
|
||||
|
|
@ -496,6 +541,7 @@ Again, the rule about function calls is really just an application of
|
|||
the existing C/C++ rule about calling functions through an
|
||||
incompatible function type.</p></div>
|
||||
|
||||
</div> <!-- objects.operands.retained-returns -->
|
||||
|
||||
<div id="objects.operands.other-returns">
|
||||
<h1>Unretained return values</h1>
|
||||
|
|
@ -528,7 +574,8 @@ that it returns a pointer which is guaranteed to be valid at least as
|
|||
long as the innermost autorelease pool. There are no additional
|
||||
semantics enforced in the definition of such a method; it merely
|
||||
enables optimizations in callers.</p>
|
||||
</div>
|
||||
|
||||
</div> <!-- objects.operands.other-returns -->
|
||||
|
||||
<div id="objects.operands.casts">
|
||||
<h1>Bridged casts</h1>
|
||||
|
|
@ -567,9 +614,9 @@ object pointers</a>.</p>
|
|||
cast purely to convince ARC to emit an unbalanced retain or release,
|
||||
respectively, is poor form.</p>
|
||||
|
||||
</div>
|
||||
</div> <!-- objects.operands.casts -->
|
||||
|
||||
</div>
|
||||
</div> <!-- objects.operands -->
|
||||
|
||||
<div id="objects.restrictions">
|
||||
<h1>Restrictions</h1>
|
||||
|
|
@ -581,7 +628,7 @@ respectively, is poor form.</p>
|
|||
convert a value of retainable object pointer type to any
|
||||
non-retainable type, or vice-versa, is ill-formed. For example, an
|
||||
Objective-C object pointer shall not be converted to <tt>void*</tt>.
|
||||
As an exception, cast to <tt>intptr_t</tt> is allowed becuase such
|
||||
As an exception, cast to <tt>intptr_t</tt> is allowed because such
|
||||
casts are not transferring ownership. The <a href="#objects.operands.casts">bridged
|
||||
casts</a> may be used to perform these conversions where
|
||||
necessary.</p>
|
||||
|
|
@ -591,28 +638,125 @@ management of the lifetime of objects if they may be freely passed
|
|||
around as unmanaged types. The bridged casts are provided so that the
|
||||
programmer may explicitly describe whether the cast transfers control
|
||||
into or out of ARC.</p></div>
|
||||
</div>
|
||||
|
||||
<p>An unbridged cast to a retainable object pointer type of the return
|
||||
value of a Objective-C message send which yields a non-retainable
|
||||
pointer is treated as a <tt>__bridge_transfer</tt> cast
|
||||
if:</p>
|
||||
<p>However, the following exceptions apply.</p>
|
||||
|
||||
</div> <!-- objects.restrictions.conversion -->
|
||||
|
||||
<div id="objects.restrictions.conversion-exception-known">
|
||||
<h1>Conversion to retainable object pointer type of
|
||||
expressions with known semantics</h1>
|
||||
|
||||
<p><span class="revision"><span class="whenRevised">[beginning Apple
|
||||
4.0, LLVM 3.1]</span> These exceptions have been greatly expanded;
|
||||
they previously applied only to a much-reduced subset which is
|
||||
difficult to categorize but which included null pointers, message
|
||||
sends (under the given rules), and the various global constants.</span></p>
|
||||
|
||||
<p>An unbridged conversion to a retainable object pointer type from a
|
||||
type other than a retainable object pointer type is ill-formed, as
|
||||
discussed above, unless the operand of the cast has a syntactic form
|
||||
which is known retained, known unretained, or known
|
||||
retain-agnostic.</p>
|
||||
|
||||
<p>An expression is <span class="term">known retain-agnostic</span> if
|
||||
it is:</p>
|
||||
<ul>
|
||||
<li>the method has the <tt>cf_returns_retained</tt> attribute, or if
|
||||
not that,</li>
|
||||
<li>the method does not have the <tt>cf_returns_not_retained</tt>
|
||||
attribute and</li>
|
||||
<li>the method's <a href="#family">selector family</a> would imply
|
||||
the <tt>ns_returns_retained</tt> attribute on a method which returned
|
||||
a retainable object pointer type.</li>
|
||||
<li>an Objective-C string literal,</li>
|
||||
<li>a load from a <tt>const</tt> system global variable of
|
||||
<a href="#misc.c-retainable">C retainable pointer type</a>, or</li>
|
||||
<li>a null pointer constant.</li>
|
||||
</ul>
|
||||
|
||||
<p>Otherwise the cast is treated as a <tt>__bridge</tt> cast.</p>
|
||||
<p>An expression is <span class="term">known unretained</span> if it
|
||||
is an rvalue of <a href="#misc.c-retainable">C retainable
|
||||
pointer type</a> and it is:</p>
|
||||
<ul>
|
||||
<li>a direct call to a function, and either that function has the
|
||||
<tt>cf_returns_not_retained</tt> attribute or it is an
|
||||
<a href="#misc.c-retainable.audit">audited</a> function that does not
|
||||
have the <tt>cf_returns_retained</tt> attribute and does not follow
|
||||
the create/copy naming convention,</li>
|
||||
<li>a message send, and the declared method either has
|
||||
the <tt>cf_returns_not_retained</tt> attribute or it has neither
|
||||
the <tt>cf_returns_retained</tt> attribute nor a
|
||||
<a href="#family">selector family</a> that implies a retained
|
||||
result.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<p>An expression is <span class="term">known retained</span> if it is
|
||||
an rvalue of <a href="#misc.c-retainable">C retainable pointer type</a>
|
||||
and it is:</p>
|
||||
<ul>
|
||||
<li>a message send, and the declared method either has the
|
||||
<tt>cf_returns_retained</tt> attribute, or it does not have
|
||||
the <tt>cf_returns_not_retained</tt> attribute but it does have a
|
||||
<a href="#family">selector family</a> that implies a retained
|
||||
result.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<p>Furthermore:</p>
|
||||
<ul>
|
||||
<li>a comma expression is classified according to its right-hand side,</li>
|
||||
<li>a statement expression is classified according to its result
|
||||
expression, if it has one,</li>
|
||||
<li>an lvalue-to-rvalue conversion applied to an Objective-C property
|
||||
lvalue is classified according to the underlying message send, and</li>
|
||||
<li>a conditional operator is classified according to its second and
|
||||
third operands, if they agree in classification, or else the other
|
||||
if one is known retain-agnostic.</li>
|
||||
</ul>
|
||||
|
||||
<p>If the cast operand is known retained, the conversion is treated as
|
||||
a <tt>__bridge_transfer</tt> cast. If the cast operand is known
|
||||
unretained or known retain-agnostic, the conversion is treated as
|
||||
a <tt>__bridge</tt> cast.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: Bridging casts are annoying.
|
||||
Absent the ability to completely automate the management of CF
|
||||
objects, however, we are left with relatively poor attempts to reduce
|
||||
the need for a glut of explicit bridges. Hence these rules.</p>
|
||||
|
||||
<p>We've so far consciously refrained from implicitly turning retained
|
||||
CF results from function calls into <tt>__bridge_transfer</tt> casts.
|
||||
The worry is that some code patterns — for example, creating a
|
||||
CF value, assigning it to an ObjC-typed local, and then
|
||||
calling <tt>CFRelease</tt> when done — are a bit too likely to
|
||||
be accidentally accepted, leading to mysterious behavior.</p></div>
|
||||
|
||||
</div> <!-- objects.restrictions.conversion-exception-known -->
|
||||
|
||||
<div id="objects.restrictions.conversion-exception-contextual">
|
||||
<h1>Conversion from retainable object pointer type in certain contexts</h1>
|
||||
|
||||
<p><span class="revision"><span class="whenRevised">[beginning Apple
|
||||
4.0, LLVM 3.1]</span></span></p>
|
||||
|
||||
<p>If an expression of retainable object pointer type is explicitly
|
||||
cast to a <a href="#misc.c-retainable">C retainable pointer type</a>,
|
||||
the program is ill-formed as discussed above unless the result is
|
||||
immediately used:</p>
|
||||
|
||||
<ul>
|
||||
<li>to initialize a parameter in an Objective-C message send where the
|
||||
parameter is not marked with the <tt>cf_consumed</tt> attribute, or</li>
|
||||
<li>to initialize a parameter in a direct call to
|
||||
an <a href="#misc.c-retainable.audit">audited</a> function where the
|
||||
parameter is not marked with the <tt>cf_consumed</tt> attribute.</li>
|
||||
</ul>
|
||||
|
||||
<div class="rationale"><p>Rationale: Consumed parameters are left out
|
||||
because ARC would naturally balance them with a retain, which was
|
||||
judged too treacherous. This is in part because several of the most
|
||||
common consuming functions are in the <tt>Release</tt> family, and it
|
||||
would be quite unfortunate for explicit releases to be silently
|
||||
balanced out in this way.</p></div>
|
||||
|
||||
</div> <!-- objects.restrictions.conversion-exception-contextual -->
|
||||
|
||||
</div> <!-- objects.restrictions -->
|
||||
|
||||
</div> <!-- objects -->
|
||||
|
||||
<div id="ownership">
|
||||
<h1>Ownership qualification</h1>
|
||||
|
|
@ -721,6 +865,29 @@ already exists, then its ownership qualification must equal the
|
|||
ownership of the property; otherwise, the instance variable is created
|
||||
with that ownership qualification.</p>
|
||||
|
||||
<p>A property of retainable object pointer type which is synthesized
|
||||
without a source of ownership has the ownership of its associated
|
||||
instance variable, if it already exists; otherwise,
|
||||
<span class="revision"><span class="whenRevised">[beginning Apple 3.1,
|
||||
LLVM 3.1]</span> its ownership is implicitly <tt>strong</tt></span>.
|
||||
Prior to this revision, it was ill-formed to synthesize such a
|
||||
property.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: using <tt>strong</tt> by default
|
||||
is safe and consistent with the generic ARC rule about
|
||||
<a href="#ownership.inference.variables">inferring ownership</a>. It
|
||||
is, unfortunately, inconsistent with the non-ARC rule which states
|
||||
that such properties are implicitly <tt>assign</tt>. However, that
|
||||
rule is clearly untenable in ARC, since it leads to default-unsafe
|
||||
code. The main merit to banning the properties is to avoid confusion
|
||||
with non-ARC practice, which did not ultimately strike us as
|
||||
sufficient to justify requiring extra syntax and (more importantly)
|
||||
forcing novices to understand ownership rules just to declare a
|
||||
property when the default is so reasonable. Changing the rule away
|
||||
from non-ARC practice was acceptable because we had conservatively
|
||||
banned the synthesis in order to give ourselves exactly this
|
||||
leeway.</p></div>
|
||||
|
||||
</div> <!-- ownership.spelling.property -->
|
||||
|
||||
</div> <!-- ownership.spelling -->
|
||||
|
|
@ -739,7 +906,7 @@ semantics as the respective operation would have on an <tt>void*</tt>
|
|||
lvalue with the same alignment and non-ownership qualification.</p>
|
||||
|
||||
<p><span class="term">Reading</span> occurs when performing a
|
||||
lvalue-to-rvalue conversion on an object lvalue.
|
||||
lvalue-to-rvalue conversion on an object lvalue.</p>
|
||||
|
||||
<ul>
|
||||
<li>For <tt>__weak</tt> objects, the current pointee is retained and
|
||||
|
|
@ -749,10 +916,9 @@ release of the pointee.</li>
|
|||
<li>For all other objects, the lvalue is loaded with primitive
|
||||
semantics.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p><span class="term">Assignment</span> occurs when evaluating
|
||||
an assignment operator. The semantics vary based on the qualification:
|
||||
an assignment operator. The semantics vary based on the qualification:</p>
|
||||
<ul>
|
||||
<li>For <tt>__strong</tt> objects, the new pointee is first retained;
|
||||
second, the lvalue is loaded with primitive semantics; third, the new
|
||||
|
|
@ -761,21 +927,20 @@ finally, the old pointee is released. This is not performed
|
|||
atomically; external synchronization must be used to make this safe in
|
||||
the face of concurrent loads and stores.</li>
|
||||
<li>For <tt>__weak</tt> objects, the lvalue is updated to point to the
|
||||
new pointee, unless that object is currently undergoing deallocation,
|
||||
in which case it the lvalue is updated to a null pointer. This must
|
||||
execute atomically with respect to other assignments to the object, to
|
||||
reads from the object, and to the final release of the new pointed-to
|
||||
value.</li>
|
||||
new pointee, unless the new pointee is an object currently undergoing
|
||||
deallocation, in which case the lvalue is updated to a null pointer.
|
||||
This must execute atomically with respect to other assignments to the
|
||||
object, to reads from the object, and to the final release of the new
|
||||
pointee.</li>
|
||||
<li>For <tt>__unsafe_unretained</tt> objects, the new pointee is
|
||||
stored into the lvalue using primitive semantics.</li>
|
||||
<li>For <tt>__autoreleasing</tt> objects, the new pointee is retained,
|
||||
autoreleased, and stored into the lvalue using primitive semantics.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p><span class="term">Initialization</span> occurs when an object's
|
||||
lifetime begins, which depends on its storage duration.
|
||||
Initialization proceeds in two stages:
|
||||
Initialization proceeds in two stages:</p>
|
||||
<ol>
|
||||
<li>First, a null pointer is stored into the lvalue using primitive
|
||||
semantics. This step is skipped if the object
|
||||
|
|
@ -784,7 +949,6 @@ is <tt>__unsafe_unretained</tt>.</li>
|
|||
evaluated and then assigned into the object using the usual assignment
|
||||
semantics.</li>
|
||||
</ol>
|
||||
</p>
|
||||
|
||||
<p><span class="term">Destruction</span> occurs when an object's
|
||||
lifetime ends. In all cases it is semantically equivalent to
|
||||
|
|
@ -842,7 +1006,9 @@ operation has a weak-unavailable type.</p>
|
|||
<h1>Storage duration of <tt>__autoreleasing</tt> objects</h1>
|
||||
|
||||
<p>A program is ill-formed if it declares an <tt>__autoreleasing</tt>
|
||||
object of non-automatic storage duration.</p>
|
||||
object of non-automatic storage duration. A program is ill-formed
|
||||
if it captures an <tt>__autoreleasing</tt> object in a block or,
|
||||
unless by reference, in a C++11 lambda.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: autorelease pools are tied to the
|
||||
current thread and scope by their nature. While it is possible to
|
||||
|
|
@ -863,7 +1029,7 @@ is left.</p>
|
|||
<p>A program is ill-formed if an expression of type <tt>T*</tt> is
|
||||
converted, explicitly or implicitly, to the type <tt>U*</tt>,
|
||||
where <tt>T</tt> and <tt>U</tt> have different ownership
|
||||
qualification, unless:
|
||||
qualification, unless:</p>
|
||||
<ul>
|
||||
<li><tt>T</tt> is qualified with <tt>__strong</tt>,
|
||||
<tt>__autoreleasing</tt>, or <tt>__unsafe_unretained</tt>, and
|
||||
|
|
@ -876,9 +1042,8 @@ qualification, unless:
|
|||
<li>the conversion is a
|
||||
well-formed <a href="#ownership.restrictions.pass_by_writeback">pass-by-writeback</a>.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>The analogous rule applies to <tt>T&</tt> and <tt>U&</tt> in
|
||||
<p>The analogous rule applies to <tt>T&</tt> and <tt>U&</tt> in
|
||||
Objective-C++.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: these rules provide a reasonable
|
||||
|
|
@ -933,7 +1098,7 @@ where <tt>oq</tt> is an ownership qualifier, then the argument is a
|
|||
candidate for <span class="term">pass-by-writeback</span> if:</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>oq</tt> is <tt>__strong</tt> or <tt>__weak</tt>, and
|
||||
<li><tt>oq</tt> is <tt>__strong</tt> or <tt>__weak</tt>, and</li>
|
||||
<li>it would be legal to initialize a <tt>T __strong *</tt> with
|
||||
a <tt>U __strong *</tt>.</li>
|
||||
</ul>
|
||||
|
|
@ -946,7 +1111,7 @@ implicit conversion sequence not requiring a pass-by-writeback.</p>
|
|||
not have a legal form:</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>&var</tt>, where <tt>var</tt> is a scalar variable of
|
||||
<li><tt>&var</tt>, where <tt>var</tt> is a scalar variable of
|
||||
automatic storage duration with retainable object pointer type</li>
|
||||
<li>a conditional expression where the second and third operands are
|
||||
both legal forms</li>
|
||||
|
|
@ -963,7 +1128,7 @@ that the user will see confusing aliasing problems due to the
|
|||
implementation, below, where their store to the writeback temporary is
|
||||
not immediately seen in the original argument variable.</p></div>
|
||||
|
||||
<p>A pass-by-writeback is evaluated as follows:
|
||||
<p>A pass-by-writeback is evaluated as follows:</p>
|
||||
<ol>
|
||||
<li>The argument is evaluated to yield a pointer <tt>p</tt> of
|
||||
type <tt>U oq *</tt>.</li>
|
||||
|
|
@ -971,14 +1136,14 @@ not immediately seen in the original argument variable.</p></div>
|
|||
the argument, and no further work is required for the pass-by-writeback.</li>
|
||||
<li>Otherwise, a temporary of type <tt>T __autoreleasing</tt> is
|
||||
created and initialized to a null pointer.</li>
|
||||
<li>If the argument is not an Objective-C method parameter marked
|
||||
<li>If the parameter is not an Objective-C method parameter marked
|
||||
<tt>out</tt>, then <tt>*p</tt> is read, and the result is written
|
||||
into the temporary with primitive semantics.</li>
|
||||
<li>The address of the temporary is passed as the argument to the
|
||||
actual call.</li>
|
||||
<li>After the call completes, the temporary is loaded with primitive
|
||||
semantics, and that value is assigned into <tt>*p</tt>.</li>
|
||||
</ol></p>
|
||||
</ol>
|
||||
|
||||
<div class="rationale"><p>Rationale: this is all admittedly
|
||||
convoluted. In an ideal world, we would see that a local variable is
|
||||
|
|
@ -1006,20 +1171,20 @@ with a <tt>void*</tt> or an <tt>__unsafe_unretained</tt>
|
|||
object.</p></div>
|
||||
|
||||
<p>This restriction does not apply in Objective-C++. However,
|
||||
nontrivally ownership-qualified types are considered non-POD: in C++0x
|
||||
nontrivally ownership-qualified types are considered non-POD: in C++11
|
||||
terms, they are not trivially default constructible, copy
|
||||
constructible, move constructible, copy assignable, move assignable,
|
||||
or destructible. It is a violation of C++ One Definition Rule to use
|
||||
a class outside of ARC that, under ARC, would have an
|
||||
or destructible. It is a violation of C++'s One Definition Rule to use
|
||||
a class outside of ARC that, under ARC, would have a nontrivially
|
||||
ownership-qualified member.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: unlike in C, we can express all
|
||||
the necessary ARC semantics for ownership-qualified subobjects as
|
||||
suboperations of the (default) special member functions for the class.
|
||||
These functions then become non-trivial. This has the non-obvious
|
||||
repercussion that the class will have a non-trivial copy constructor
|
||||
and non-trivial destructor; if it wouldn't outside of ARC, this means
|
||||
that objects of the type will be passed and returned in an
|
||||
result that the class will have a non-trivial copy constructor and
|
||||
non-trivial destructor; if this would not normally be true outside of
|
||||
ARC, objects of the type will be passed and returned in an
|
||||
ABI-incompatible manner.</p></div>
|
||||
|
||||
</div>
|
||||
|
|
@ -1055,7 +1220,6 @@ it is implicitly qualified with <tt>__unsafe_unretained</tt>;</li>
|
|||
<li>otherwise, it is implicitly qualified
|
||||
with <tt>__autoreleasing</tt>.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: <tt>__autoreleasing</tt> exists
|
||||
mostly for this case, the Cocoa convention for out-parameters. Since
|
||||
|
|
@ -1101,7 +1265,7 @@ template argument was deduced or explicitly specified. </p>
|
|||
family</span>, which is a conventional set of behaviors ascribed to it
|
||||
by the Cocoa conventions.</p>
|
||||
|
||||
<p>A method is in a certain method family if:
|
||||
<p>A method is in a certain method family if:</p>
|
||||
<ul>
|
||||
<li>it has a <tt>objc_method_family</tt> attribute placing it in that
|
||||
family; or if not that,</li>
|
||||
|
|
@ -1109,7 +1273,7 @@ by the Cocoa conventions.</p>
|
|||
it in a different or no family, and</li>
|
||||
<li>its selector falls into the corresponding selector family, and</li>
|
||||
<li>its signature obeys the added restrictions of the method family.</li>
|
||||
</ul></p>
|
||||
</ul>
|
||||
|
||||
<p>A selector is in a certain selector family if, ignoring any leading
|
||||
underscores, the first component of the selector either consists
|
||||
|
|
@ -1132,7 +1296,7 @@ declares or contains a call to an <tt>init</tt> method whose return
|
|||
type is neither <tt>id</tt> nor a pointer to a super-class or
|
||||
sub-class of the declaring class (if the method was declared on
|
||||
a class) or the static receiver type of the call (if it was declared
|
||||
on a protocol).</p>
|
||||
on a protocol).
|
||||
|
||||
<div class="rationale"><p>Rationale: there are a fair number of existing
|
||||
methods with <tt>init</tt>-like selectors which nonetheless don't
|
||||
|
|
@ -1189,7 +1353,7 @@ mechanical system, they are only imperfectly kept, especially as they
|
|||
haven't always even been precisely defined. While it is possible to
|
||||
define low-level ownership semantics with attributes like
|
||||
<tt>ns_returns_retained</tt>, this attribute allows the user to
|
||||
communicate semantic intent, which of use both to ARC (which, e.g.,
|
||||
communicate semantic intent, which is of use both to ARC (which, e.g.,
|
||||
treats calls to <tt>init</tt> specially) and the static analyzer.</p></div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1281,7 +1445,7 @@ of ARC.</p>
|
|||
more prone than most code to signature errors, i.e. errors where a
|
||||
call was emitted against one method signature, but the implementing
|
||||
method has an incompatible signature. Having more precise type
|
||||
information helps drastically lower this risks, as well as catching
|
||||
information helps drastically lower this risk, as well as catching
|
||||
a number of latent bugs.</p></div>
|
||||
|
||||
</div> <!-- family.semantics.result_type -->
|
||||
|
|
@ -1348,7 +1512,7 @@ clearer.</p></div>
|
|||
|
||||
</div> <!-- optimization.precise -->
|
||||
|
||||
</div>
|
||||
</div> <!-- optimization -->
|
||||
|
||||
<div id="misc">
|
||||
<h1>Miscellaneous</h1>
|
||||
|
|
@ -1361,14 +1525,13 @@ clearer.</p></div>
|
|||
|
||||
<p>A program is ill-formed if it contains a method definition, message
|
||||
send, or <tt>@selector</tt> expression for any of the following
|
||||
selectors:
|
||||
selectors:</p>
|
||||
<ul>
|
||||
<li><tt>autorelease</tt></li>
|
||||
<li><tt>release</tt></li>
|
||||
<li><tt>retain</tt></li>
|
||||
<li><tt>retainCount</tt></li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: <tt>retainCount</tt> is banned
|
||||
because ARC robs it of consistent semantics. The others were banned
|
||||
|
|
@ -1482,9 +1645,12 @@ implementation.</p></div>
|
|||
<p>The <tt>self</tt> parameter variable of an Objective-C method is
|
||||
never actually retained by the implementation. It is undefined
|
||||
behavior, or at least dangerous, to cause an object to be deallocated
|
||||
during a message send to that object. To make this
|
||||
safe, <tt>self</tt> is implicitly <tt>const</tt> unless the method is
|
||||
in the <a href="#family.semantics.init"><tt>init</tt> family</a>.</p>
|
||||
during a message send to that object.</p>
|
||||
|
||||
<p>To make this safe, for Objective-C instance methods <tt>self</tt> is
|
||||
implicitly <tt>const</tt> unless the method is in the <a
|
||||
href="#family.semantics.init"><tt>init</tt> family</a>. Further, <tt>self</tt>
|
||||
is <b>always</b> implicitly <tt>const</tt> within a class method.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: the cost of
|
||||
retaining <tt>self</tt> in all methods was found to be prohibitive, as
|
||||
|
|
@ -1516,9 +1682,9 @@ retained during enumeration, and the collection itself cannot be
|
|||
synchronously modified. It can be overridden by explicitly qualifying
|
||||
the variable with <tt>__strong</tt>, which will make the variable
|
||||
mutable again and cause the loop to retain the objects it
|
||||
encounters.</div>
|
||||
encounters.</p></div>
|
||||
|
||||
</div>
|
||||
</div> <!-- misc.enumeration -->
|
||||
|
||||
<div id="misc.blocks">
|
||||
<h1>Blocks</h1>
|
||||
|
|
@ -1537,7 +1703,7 @@ retain during capture.</p>
|
|||
|
||||
<p><tt>__block</tt> variables of retainable object owner type are
|
||||
moved off the stack by initializing the heap copy with the result of
|
||||
moving from the stack copy.</tt></p>
|
||||
moving from the stack copy.</p>
|
||||
|
||||
<p>With the exception of retains done as part of initializing
|
||||
a <tt>__strong</tt> parameter variable or reading a <tt>__weak</tt>
|
||||
|
|
@ -1552,7 +1718,7 @@ used only as an argument to a call.</p>
|
|||
<h1>Exceptions</h1>
|
||||
|
||||
<p>By default in Objective C, ARC is not exception-safe for normal
|
||||
releases:
|
||||
releases:</p>
|
||||
<ul>
|
||||
<li>It does not end the lifetime of <tt>__strong</tt> variables when
|
||||
their scopes are abnormally terminated by an exception.</li>
|
||||
|
|
@ -1645,6 +1811,87 @@ user with good cheer.</p></div>
|
|||
|
||||
</div> <!-- misc.interior -->
|
||||
|
||||
<div id="misc.c-retainable">
|
||||
<h1>C retainable pointer types</h1>
|
||||
|
||||
<p>A type is a <span class="term">C retainable pointer type</span>
|
||||
if it is a pointer to (possibly qualified) <tt>void</tt> or a
|
||||
pointer to a (possibly qualifier) <tt>struct</tt> or <tt>class</tt>
|
||||
type.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: ARC does not manage pointers of
|
||||
CoreFoundation type (or any of the related families of retainable C
|
||||
pointers which interoperate with Objective-C for retain/release
|
||||
operation). In fact, ARC does not even know how to distinguish these
|
||||
types from arbitrary C pointer types. The intent of this concept is
|
||||
to filter out some obviously non-object types while leaving a hook for
|
||||
later tightening if a means of exhaustively marking CF types is made
|
||||
available.</p></div>
|
||||
|
||||
<div id="misc.c-retainable.audit">
|
||||
<h1>Auditing of C retainable pointer interfaces</h1>
|
||||
|
||||
<p><span class="revision"><span class="whenRevised">[beginning Apple 4.0, LLVM 3.1]</span></span></p>
|
||||
|
||||
<p>A C function may be marked with the <tt>cf_audited_transfer</tt>
|
||||
attribute to express that, except as otherwise marked with attributes,
|
||||
it obeys the parameter (consuming vs. non-consuming) and return
|
||||
(retained vs. non-retained) conventions for a C function of its name,
|
||||
namely:</p>
|
||||
|
||||
<ul>
|
||||
<li>A parameter of C retainable pointer type is assumed to not be
|
||||
consumed unless it is marked with the <tt>cf_consumed</tt> attribute, and</li>
|
||||
<li>A result of C retainable pointer type is assumed to not be
|
||||
returned retained unless the function is either
|
||||
marked <tt>cf_returns_retained</tt> or it follows
|
||||
the create/copy naming convention and is not
|
||||
marked <tt>cf_returns_not_retained</tt>.</li>
|
||||
</ul>
|
||||
|
||||
<p>A function obeys the <span class="term">create/copy</span> naming
|
||||
convention if its name contains as a substring:</p>
|
||||
<ul>
|
||||
<li>either <q>Create</q> or <q>Copy</q> not followed by a lowercase letter, or</li>
|
||||
<li>either <q>create</q> or <q>copy</q> not followed by a lowercase
|
||||
letter and not preceded by any letter, whether uppercase or lowercase.</li>
|
||||
</ul>
|
||||
|
||||
<p>A second attribute, <tt>cf_unknown_transfer</tt>, signifies that a
|
||||
function's transfer semantics cannot be accurately captured using any
|
||||
of these annotations. A program is ill-formed if it annotates the
|
||||
same function with both <tt>cf_audited_transfer</tt>
|
||||
and <tt>cf_unknown_transfer</tt>.</p>
|
||||
|
||||
<p>A pragma is provided to faciliate the mass annotation of interfaces:</p>
|
||||
|
||||
<pre>#pragma arc_cf_code_audited begin
|
||||
...
|
||||
#pragma arc_cf_code_audited end</pre>
|
||||
|
||||
<p>All C functions declared within the extent of this pragma are
|
||||
treated as if annotated with the <tt>cf_audited_transfer</tt>
|
||||
attribute unless they otherwise have the <tt>cf_unknown_transfer</tt>
|
||||
attribute. The pragma is accepted in all language modes. A program
|
||||
is ill-formed if it attempts to change files, whether by including a
|
||||
file or ending the current file, within the extent of this pragma.</p>
|
||||
|
||||
<p>It is possible to test for all the features in this section with
|
||||
<tt>__has_feature(arc_cf_code_audited)</tt>.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: A significant inconvenience in
|
||||
ARC programming is the necessity of interacting with APIs based around
|
||||
C retainable pointers. These features are designed to make it
|
||||
relatively easy for API authors to quickly review and annotate their
|
||||
interfaces, in turn improving the fidelity of tools such as the static
|
||||
analyzer and ARC. The single-file restriction on the pragma is
|
||||
designed to eliminate the risk of accidentally annotating some other
|
||||
header's interfaces.</p></div>
|
||||
|
||||
</div> <!-- misc.c-retainable.audit -->
|
||||
|
||||
</div> <!-- misc.c-retainable -->
|
||||
|
||||
</div> <!-- misc -->
|
||||
|
||||
<div id="runtime">
|
||||
|
|
|
|||
|
|
@ -667,4 +667,3 @@ void _Block_object_assign(void *destAddr, const void *object, const int flags);
|
|||
The same flags used in the copy helper should be used for each call generated to this function:
|
||||
*/
|
||||
void _Block_object_dispose(const void *object, const int flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Driver Manual</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
|
|
@ -19,26 +21,29 @@
|
|||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#features">Features and Goals</a></li>
|
||||
<li><a href="#features">Features and Goals</a>
|
||||
<ul>
|
||||
<li><a href="#gcccompat">GCC Compatibility</a></li>
|
||||
<li><a href="#components">Flexible</a></li>
|
||||
<li><a href="#performance">Low Overhead</a></li>
|
||||
<li><a href="#simple">Simple</a></li>
|
||||
</ul>
|
||||
<li><a href="#design">Design</a></li>
|
||||
</li>
|
||||
<li><a href="#design">Design</a>
|
||||
<ul>
|
||||
<li><a href="#int_intro">Internals Introduction</a></li>
|
||||
<li><a href="#int_overview">Design Overview</a></li>
|
||||
<li><a href="#int_notes">Additional Notes</a></li>
|
||||
<li><a href="#int_notes">Additional Notes</a>
|
||||
<ul>
|
||||
<li><a href="#int_compilation">The Compilation Object</a></li>
|
||||
<li><a href="#int_unified_parsing">Unified Parsing & Pipelining</a></li>
|
||||
<li><a href="#int_toolchain_translation">ToolChain Argument Translation</a></li>
|
||||
<li><a href="#int_unused_warnings">Unused Argument Warnings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
|
@ -168,11 +173,12 @@
|
|||
distinct stages which manipulate these data structures, and
|
||||
the blue components are important helper classes. </p>
|
||||
|
||||
<center>
|
||||
<a href="DriverArchitecture.png" alt="Driver Architecture Diagram">
|
||||
<img width=400 src="DriverArchitecture.png">
|
||||
<div style="text-align:center">
|
||||
<a href="DriverArchitecture.png">
|
||||
<img width=400 src="DriverArchitecture.png"
|
||||
alt="Driver Architecture Diagram">
|
||||
</a>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<!--=======================================================================-->
|
||||
<h3><a name="int_stages">Driver Stages</a></h3>
|
||||
|
|
@ -495,7 +501,7 @@
|
|||
embedded in specs is in the Tool specific argument
|
||||
translation routines. The parts of specs which control the
|
||||
compilation pipeline are generally part of
|
||||
the <ii>Pipeline</ii> stage.</p>
|
||||
the <i>Pipeline</i> stage.</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>"Clang" CFE Internals Manual</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
|
|
@ -19,7 +21,7 @@ td {
|
|||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#libsystem">LLVM System and Support Libraries</a></li>
|
||||
<li><a href="#libsupport">LLVM Support Library</a></li>
|
||||
<li><a href="#libbasic">The Clang 'Basic' Library</a>
|
||||
<ul>
|
||||
<li><a href="#Diagnostics">The Diagnostics Subsystem</a></li>
|
||||
|
|
@ -29,13 +31,9 @@ td {
|
|||
</ul>
|
||||
</li>
|
||||
<li><a href="#libdriver">The Driver Library</a>
|
||||
<ul>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#pch">Precompiled Headers</a>
|
||||
<li><a href="#libfrontend">The Frontend Library</a>
|
||||
<ul>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#liblex">The Lexer and Preprocessor Library</a>
|
||||
<ul>
|
||||
|
|
@ -47,8 +45,6 @@ td {
|
|||
</ul>
|
||||
</li>
|
||||
<li><a href="#libparse">The Parser Library</a>
|
||||
<ul>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#libast">The AST Library</a>
|
||||
<ul>
|
||||
|
|
@ -89,15 +85,13 @@ Clang, not for end-users. The description below is categorized by
|
|||
libraries, and does not describe any of the clients of the libraries.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libsystem">LLVM System and Support Libraries</h2>
|
||||
<h2 id="libsupport">LLVM Support Library</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The LLVM libsystem library provides the basic Clang system abstraction layer,
|
||||
which is used for file system access. The LLVM libsupport library provides many
|
||||
underlying libraries and <a
|
||||
href="http://llvm.org/docs/ProgrammersManual.html">data-structures</a>,
|
||||
including command line option
|
||||
processing and various containers.</p>
|
||||
<p>The LLVM libsupport library provides many underlying libraries and
|
||||
<a href="http://llvm.org/docs/ProgrammersManual.html">data-structures</a>,
|
||||
including command line option processing, various containers and a system
|
||||
abstraction layer, which is used for file system access.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libbasic">The Clang 'Basic' Library</h2>
|
||||
|
|
@ -137,8 +131,8 @@ implemented. A representative example of a diagnostic is:</p>
|
|||
|
||||
<pre>
|
||||
t.c:38:15: error: invalid operands to binary expression ('int *' and '_Complex float')
|
||||
<font color="darkgreen">P = (P-42) + Gamma*4;</font>
|
||||
<font color="blue">~~~~~~ ^ ~~~~~~~</font>
|
||||
<span style="color:darkgreen">P = (P-42) + Gamma*4;</span>
|
||||
<span style="color:blue">~~~~~~ ^ ~~~~~~~</span>
|
||||
</pre>
|
||||
|
||||
<p>In this example, you can see the English translation, the severity (error),
|
||||
|
|
@ -267,7 +261,7 @@ including variable names, types, labels, etc. The 'select' format can be
|
|||
used to achieve this sort of thing in a localizable way, see below.</p>
|
||||
|
||||
<!-- ==================================== -->
|
||||
<h4>Formatting a Diagnostic Argument</a></h4>
|
||||
<h4>Formatting a Diagnostic Argument</h4>
|
||||
<!-- ==================================== -->
|
||||
|
||||
<p>Arguments to diagnostics are fully typed internally, and come from a couple
|
||||
|
|
@ -429,10 +423,10 @@ the problem. For example, it might add the missing semicolon at the
|
|||
end of the statement or rewrite the use of a deprecated construct
|
||||
into something more palatable. Here is one such example from the C++
|
||||
front end, where we warn about the right-shift operator changing
|
||||
meaning from C++98 to C++0x:</p>
|
||||
meaning from C++98 to C++11:</p>
|
||||
|
||||
<pre>
|
||||
test.cpp:3:7: warning: use of right-shift operator ('>>') in template argument will require parentheses in C++0x
|
||||
test.cpp:3:7: warning: use of right-shift operator ('>>') in template argument will require parentheses in C++11
|
||||
A<100 >> 2> *a;
|
||||
^
|
||||
( )
|
||||
|
|
@ -577,7 +571,7 @@ the <code>CharSourceRange</code> class.</p>
|
|||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The clang Driver and library are documented <a
|
||||
href="DriverInternals.html">here<a>.<p>
|
||||
href="DriverInternals.html">here</a>.<p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="pch">Precompiled Headers</h2>
|
||||
|
|
@ -687,7 +681,6 @@ lexer/preprocessor system on a per-token basis:
|
|||
<li><b>NeedsCleaning</b> - This flag is set if the original spelling for the
|
||||
token includes a trigraph or escaped newline. Since this is uncommon,
|
||||
many pieces of code can fast-path on tokens that did not need cleaning.
|
||||
</p>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -907,13 +900,13 @@ on the annotated lines. In this example, we expect to get:</p>
|
|||
<pre>
|
||||
<b>test.c:6:1: error: indirection requires pointer operand ('foo' invalid)</b>
|
||||
*X; // error
|
||||
<font color="blue">^~</font>
|
||||
<span style="color:blue">^~</span>
|
||||
<b>test.c:7:1: error: indirection requires pointer operand ('foo' invalid)</b>
|
||||
**Y; // error
|
||||
<font color="blue">^~~</font>
|
||||
<span style="color:blue">^~~</span>
|
||||
<b>test.c:8:1: error: indirection requires pointer operand ('foo' invalid)</b>
|
||||
**Z; // error
|
||||
<font color="blue">^~~</font>
|
||||
<span style="color:blue">^~~</span>
|
||||
</pre>
|
||||
|
||||
<p>While this example is somewhat silly, it illustrates the point: we want to
|
||||
|
|
@ -930,7 +923,7 @@ typedef for foo.
|
|||
<p>Representing types like this is great for diagnostics, because the
|
||||
user-specified type is always immediately available. There are two problems
|
||||
with this: first, various semantic checks need to make judgements about the
|
||||
<em>actual structure</em> of a type, ignoring typdefs. Second, we need an
|
||||
<em>actual structure</em> of a type, ignoring typedefs. Second, we need an
|
||||
efficient way to query whether two types are structurally identical to each
|
||||
other, ignoring typedefs. The solution to both of these problems is the idea of
|
||||
canonical types.</p>
|
||||
|
|
@ -1325,7 +1318,7 @@ extern "C" {
|
|||
|
||||
<p>The transparent <code>DeclContexts</code> are:</p>
|
||||
<ul>
|
||||
<li>Enumerations (but not C++0x "scoped enumerations"):
|
||||
<li>Enumerations (but not C++11 "scoped enumerations"):
|
||||
<pre>
|
||||
enum Color {
|
||||
Red,
|
||||
|
|
@ -1356,7 +1349,7 @@ LookupTable LT;
|
|||
LT.Vector = 0; // Okay: finds Vector inside the unnamed union
|
||||
</pre>
|
||||
</li>
|
||||
<li>C++0x inline namespaces:
|
||||
<li>C++11 inline namespaces:
|
||||
<pre>
|
||||
namespace mylib {
|
||||
inline namespace debug {
|
||||
|
|
@ -1694,7 +1687,10 @@ interacts with constant evaluation:</p>
|
|||
any evaluatable subexpression to be accepted as an integer constant
|
||||
expression.</li>
|
||||
<li><b><tt>__builtin_constant_p</tt></b>: This returns true (as a integer
|
||||
constant expression) if the operand is any evaluatable constant. As a
|
||||
constant expression) if the operand evaluates to either a numeric value
|
||||
(that is, not a pointer cast to integral type) of integral, enumeration,
|
||||
floating or complex type, or if it evaluates to the address of the first
|
||||
character of a string literal (possibly cast to some other type). As a
|
||||
special case, if <tt>__builtin_constant_p</tt> is the (potentially
|
||||
parenthesized) condition of a conditional operator expression ("?:"), only
|
||||
the true side of the conditional operator is considered, and it is evaluated
|
||||
|
|
@ -1709,7 +1705,9 @@ interacts with constant evaluation:</p>
|
|||
floating-point literal.</li>
|
||||
<li><b><tt>__builtin_abs,copysign,..</tt></b>: These are constant folded as
|
||||
general constant expressions.</li>
|
||||
<li><b><tt>__builtin_strlen</tt></b> and <b><tt>strlen</tt></b>: These are constant folded as integer constant expressions if the argument is a string literal.</li>
|
||||
<li><b><tt>__builtin_strlen</tt></b> and <b><tt>strlen</tt></b>: These are
|
||||
constant folded as integer constant expressions if the argument is a string
|
||||
literal.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
|
@ -1723,7 +1721,7 @@ interacts with constant evaluation:</p>
|
|||
|
||||
<p>To add an attribute, you'll have to add it to the list of attributes, add it
|
||||
to the parsing phase, and look for it in the AST scan.
|
||||
<a href="http://llvm.org/viewvc/llvm-project?view=rev&revision=124217">r124217</a>
|
||||
<a href="http://llvm.org/viewvc/llvm-project?view=rev&revision=124217">r124217</a>
|
||||
has a good example of adding a warning attribute.</p>
|
||||
|
||||
<p>(Beware that this hasn't been reviewed/fixed by the people who designed the
|
||||
|
|
@ -1738,7 +1736,7 @@ to subsequent declarations of the same name.</p>
|
|||
|
||||
<p><tt>Spellings</tt> lists the strings that can appear in
|
||||
<tt>__attribute__((here))</tt> or <tt>[[here]]</tt>. All such strings
|
||||
will be synonymous. If you want to allow the <tt>[[]]</tt> C++0x
|
||||
will be synonymous. If you want to allow the <tt>[[]]</tt> C++11
|
||||
syntax, you have to define a list of <tt>Namespaces</tt>, which will
|
||||
let users write <tt>[[namespace:spelling]]</tt>. Using the empty
|
||||
string for a namespace will allow users to write just the spelling
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
th { background-color: #ffddaa; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -29,54 +30,59 @@
|
|||
<li><a href="#vectors">Vectors and Extended Vectors</a></li>
|
||||
<li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li>
|
||||
<li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li>
|
||||
<li><a href="#user_specified_system_framework">'User-Specified' System Frameworks</a></li>
|
||||
<li><a href="#availability">Availability attribute</a></li>
|
||||
<li><a href="#checking_language_features">Checks for Standard Language Features</a>
|
||||
<ul>
|
||||
<li><a href="#cxx_exceptions">C++ exceptions</a></li>
|
||||
<li><a href="#cxx_rtti">C++ RTTI</a></li>
|
||||
<li><a href="#cxx98">C++98</a>
|
||||
<ul>
|
||||
<li><a href="#cxx_exceptions">C++ exceptions</a></li>
|
||||
<li><a href="#cxx_rtti">C++ RTTI</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a>
|
||||
<ul>
|
||||
<li><a href="#cxx0x">C++0x</a>
|
||||
<li><a href="#cxx11">C++11</a>
|
||||
<ul>
|
||||
<li><a href="#cxx_access_control_sfinae">C++0x SFINAE includes access control</a></li>
|
||||
<li><a href="#cxx_alias_templates">C++0x alias templates</a></li>
|
||||
<li><a href="#cxx_alignas">C++0x alignment specifiers</a></li>
|
||||
<li><a href="#cxx_attributes">C++0x attributes</a></li>
|
||||
<li><a href="#cxx_constexpr">C++0x generalized constant expressions</a></li>
|
||||
<li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
|
||||
<li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
|
||||
<li><a href="#cxx_delegating_constructor">C++0x delegating constructors</a></li>
|
||||
<li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
|
||||
<li><a href="#cxx_explicit_conversions">C++0x explicit conversion functions</a></li>
|
||||
<li><a href="#cxx_generalized_initializers">C++0x generalized initializers</a></li>
|
||||
<li><a href="#cxx_implicit_moves">C++0x implicit move constructors/assignment operators</a></li>
|
||||
<li><a href="#cxx_inheriting_constructors">C++0x inheriting constructors</a></li>
|
||||
<li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
|
||||
<li><a href="#cxx_lambdas">C++0x lambdas</a></li>
|
||||
<li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
|
||||
<li><a href="#cxx_nonstatic_member_init">C++0x in-class non-static data member initialization</a></li>
|
||||
<li><a href="#cxx_nullptr">C++0x nullptr</a></li>
|
||||
<li><a href="#cxx_override_control">C++0x override control</a></li>
|
||||
<li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
|
||||
<li><a href="#cxx_raw_string_literals">C++0x raw string literals</a></li>
|
||||
<li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
|
||||
<li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
|
||||
<li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
|
||||
<li><a href="#cxx_auto_type">C++0x type inference</a></li>
|
||||
<li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
|
||||
<li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
|
||||
<li><a href="#cxx_unicode_literals">C++0x Unicode string literals</a></li>
|
||||
<li><a href="#cxx_unrestricted_unions">C++0x unrestricted unions</a></li>
|
||||
<li><a href="#cxx_user_literals">C++0x user-defined literals</a></li>
|
||||
<li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#c1x">C1X</a>
|
||||
<li><a href="#cxx_access_control_sfinae">C++11 SFINAE includes access control</a></li>
|
||||
<li><a href="#cxx_alias_templates">C++11 alias templates</a></li>
|
||||
<li><a href="#cxx_alignas">C++11 alignment specifiers</a></li>
|
||||
<li><a href="#cxx_attributes">C++11 attributes</a></li>
|
||||
<li><a href="#cxx_constexpr">C++11 generalized constant expressions</a></li>
|
||||
<li><a href="#cxx_decltype">C++11 <tt>decltype()</tt></a></li>
|
||||
<li><a href="#cxx_default_function_template_args">C++11 default template arguments in function templates</a></li>
|
||||
<li><a href="#cxx_defaulted_functions">C++11 defaulted functions</a></li>
|
||||
<li><a href="#cxx_delegating_constructor">C++11 delegating constructors</a></li>
|
||||
<li><a href="#cxx_deleted_functions">C++11 deleted functions</a></li>
|
||||
<li><a href="#cxx_explicit_conversions">C++11 explicit conversion functions</a></li>
|
||||
<li><a href="#cxx_generalized_initializers">C++11 generalized initializers</a></li>
|
||||
<li><a href="#cxx_implicit_moves">C++11 implicit move constructors/assignment operators</a></li>
|
||||
<li><a href="#cxx_inheriting_constructors">C++11 inheriting constructors</a></li>
|
||||
<li><a href="#cxx_inline_namespaces">C++11 inline namespaces</a></li>
|
||||
<li><a href="#cxx_lambdas">C++11 lambdas</a></li>
|
||||
<li><a href="#cxx_local_type_template_args">C++11 local and unnamed types as template arguments</a></li>
|
||||
<li><a href="#cxx_noexcept">C++11 noexcept specification</a></li>
|
||||
<li><a href="#cxx_nonstatic_member_init">C++11 in-class non-static data member initialization</a></li>
|
||||
<li><a href="#cxx_nullptr">C++11 nullptr</a></li>
|
||||
<li><a href="#cxx_override_control">C++11 override control</a></li>
|
||||
<li><a href="#cxx_range_for">C++11 range-based for loop</a></li>
|
||||
<li><a href="#cxx_raw_string_literals">C++11 raw string literals</a></li>
|
||||
<li><a href="#cxx_rvalue_references">C++11 rvalue references</a></li>
|
||||
<li><a href="#cxx_reference_qualified_functions">C++11 reference-qualified functions</a></li>
|
||||
<li><a href="#cxx_static_assert">C++11 <tt>static_assert()</tt></a></li>
|
||||
<li><a href="#cxx_auto_type">C++11 type inference</a></li>
|
||||
<li><a href="#cxx_strong_enums">C++11 strongly-typed enumerations</a></li>
|
||||
<li><a href="#cxx_trailing_return">C++11 trailing return type</a></li>
|
||||
<li><a href="#cxx_unicode_literals">C++11 Unicode string literals</a></li>
|
||||
<li><a href="#cxx_unrestricted_unions">C++11 unrestricted unions</a></li>
|
||||
<li><a href="#cxx_user_literals">C++11 user-defined literals</a></li>
|
||||
<li><a href="#cxx_variadic_templates">C++11 variadic templates</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#c11">C11</a>
|
||||
<ul>
|
||||
<li><a href="#c_alignas">C1X alignment specifiers</a></li>
|
||||
<li><a href="#c_generic_selections">C1X generic selections</a></li>
|
||||
<li><a href="#c_static_assert">C1X <tt>_Static_assert()</tt></a></li>
|
||||
</ul></li>
|
||||
</ul> </li>
|
||||
<li><a href="#c_alignas">C11 alignment specifiers</a></li>
|
||||
<li><a href="#c_atomic">C11 atomic operations</a></li>
|
||||
<li><a href="#c_generic_selections">C11 generic selections</a></li>
|
||||
<li><a href="#c_static_assert">C11 <tt>_Static_assert()</tt></a></li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
|
||||
<li><a href="#blocks">Blocks</a></li>
|
||||
<li><a href="#objc_features">Objective-C Features</a>
|
||||
|
|
@ -84,6 +90,8 @@
|
|||
<li><a href="#objc_instancetype">Related result types</a></li>
|
||||
<li><a href="#objc_arc">Automatic reference counting</a></li>
|
||||
<li><a href="#objc_fixed_enum">Enumerations with a fixed underlying type</a></li>
|
||||
<li><a href="#objc_lambdas">Interoperability with C++11 lambdas</a></li>
|
||||
<li><a href="#object-literals-subscripting">Object Literals and Subscripting</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
|
||||
|
|
@ -101,7 +109,12 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
|
||||
<li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
|
||||
<li><a href="#dynamicanalyzerspecific">Dynamic Analysis-Specific Extensions</a>
|
||||
<ul>
|
||||
<li><a href="#address_sanitizer">AddressSanitizer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#threadsafety">Thread Safety Annotation Checking</a>
|
||||
<ul>
|
||||
<li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>
|
||||
<li><a href="#ts_lockable"><tt>lockable</tt></a></li>
|
||||
|
|
@ -122,6 +135,7 @@
|
|||
<li><a href="#ts_elr"><tt>exclusive_locks_required(...)</tt></a></li>
|
||||
<li><a href="#ts_slr"><tt>shared_locks_required(...)</tt></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -192,12 +206,12 @@ language feature) or 0 if not. They can be used like this:</p>
|
|||
|
||||
...
|
||||
#if __has_feature(cxx_rvalue_references)
|
||||
// This code will only be compiled with the -std=c++0x and -std=gnu++0x
|
||||
// options, because rvalue references are only standardized in C++0x.
|
||||
// This code will only be compiled with the -std=c++11 and -std=gnu++11
|
||||
// options, because rvalue references are only standardized in C++11.
|
||||
#endif
|
||||
|
||||
#if __has_extension(cxx_rvalue_references)
|
||||
// This code will be compiled with the -std=c++0x, -std=gnu++0x, -std=c++98
|
||||
// This code will be compiled with the -std=c++11, -std=gnu++11, -std=c++98
|
||||
// and -std=gnu++98 options, because rvalue references are supported as a
|
||||
// language extension in C++98.
|
||||
#endif
|
||||
|
|
@ -209,11 +223,21 @@ language feature) or 0 if not. They can be used like this:</p>
|
|||
non-standardized features, i.e. features not prefixed <code>c_</code>,
|
||||
<code>cxx_</code> or <code>objc_</code>.</p>
|
||||
|
||||
<p id="has_feature_for_non_language_features">
|
||||
Another use of <code>__has_feature</code> is to check for compiler features
|
||||
not related to the language standard, such as e.g.
|
||||
<a href="AddressSanitizer.html">AddressSanitizer</a>.
|
||||
|
||||
<p>If the <code>-pedantic-errors</code> option is given,
|
||||
<code>__has_extension</code> is equivalent to <code>__has_feature</code>.</p>
|
||||
|
||||
<p>The feature tag is described along with the language feature below.</p>
|
||||
|
||||
<p>The feature name or extension name can also be specified with a preceding and
|
||||
following <code>__</code> (double underscore) to avoid interference from a macro
|
||||
with the same name. For instance, <code>__cxx_rvalue_references__</code> can be
|
||||
used instead of <code>cxx_rvalue_references</code>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3><a name="__has_attribute">__has_attribute</a></h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -238,6 +262,11 @@ can be used like this:</p>
|
|||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The attribute name can also be specified with a preceding and
|
||||
following <code>__</code> (double underscore) to avoid interference from a macro
|
||||
with the same name. For instance, <code>__always_inline__</code> can be used
|
||||
instead of <code>always_inline</code>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="has_include">Include File Checking Macros</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -346,30 +375,36 @@ is used in the file argument.</p>
|
|||
<dd>Defined when compiling with Clang</dd>
|
||||
|
||||
<dt><code>__clang_major__</code></dt>
|
||||
<dd>Defined to the major version number of Clang (e.g., the 2 in
|
||||
2.0.1).</dd>
|
||||
<dd>Defined to the major marketing version number of Clang (e.g., the
|
||||
2 in 2.0.1). Note that marketing version numbers should not be used to
|
||||
check for language features, as different vendors use different numbering
|
||||
schemes. Instead, use the <a href="#feature_check">feature checking
|
||||
macros</a>.</dd>
|
||||
|
||||
<dt><code>__clang_minor__</code></dt>
|
||||
<dd>Defined to the minor version number of Clang (e.g., the 0 in
|
||||
2.0.1).</dd>
|
||||
2.0.1). Note that marketing version numbers should not be used to
|
||||
check for language features, as different vendors use different numbering
|
||||
schemes. Instead, use the <a href="#feature_check">feature checking
|
||||
macros</a>.</dd>
|
||||
|
||||
<dt><code>__clang_patchlevel__</code></dt>
|
||||
<dd>Defined to the patch level of Clang (e.g., the 1 in 2.0.1).</dd>
|
||||
<dd>Defined to the marketing patch level of Clang (e.g., the 1 in 2.0.1).</dd>
|
||||
|
||||
<dt><code>__clang_version__</code></dt>
|
||||
<dd>Defined to a string that captures the Clang version, including
|
||||
the Subversion tag or revision number, e.g., "1.5 (trunk
|
||||
102332)".</dd>
|
||||
<dd>Defined to a string that captures the Clang marketing version, including
|
||||
the Subversion tag or revision number, e.g., "1.5 (trunk 102332)".</dd>
|
||||
</dl>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="vectors">Vectors and Extended Vectors</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Supports the GCC vector extensions, plus some stuff like V[1].</p>
|
||||
<p>Supports the GCC, OpenCL, AltiVec and NEON vector extensions.</p>
|
||||
|
||||
<p>Also supports <tt>ext_vector</tt>, which additionally support for V.xyzw
|
||||
syntax and other tidbits as seen in OpenCL. An example is:</p>
|
||||
<p>OpenCL vector types are created using <tt>ext_vector_type</tt> attribute. It
|
||||
support for <tt>V.xyzw</tt> syntax and other tidbits as seen in OpenCL. An
|
||||
example is:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
|
@ -385,7 +420,161 @@ float4 foo(float2 a, float2 b) {
|
|||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Query for this feature with __has_extension(attribute_ext_vector_type).</p>
|
||||
<p>Query for this feature with
|
||||
<tt>__has_extension(attribute_ext_vector_type)</tt>.</p>
|
||||
|
||||
<p>Giving <tt>-faltivec</tt> option to clang enables support for AltiVec vector
|
||||
syntax and functions. For example:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
vector float foo(vector int a) {
|
||||
vector int b;
|
||||
b = vec_add(a, a) + a;
|
||||
return (vector float)b;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>NEON vector types are created using <tt>neon_vector_type</tt> and
|
||||
<tt>neon_polyvector_type</tt> attributes. For example:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef <b>__attribute__((neon_vector_type(8)))</b> int8_t int8x8_t;
|
||||
typedef <b>__attribute__((neon_polyvector_type(16)))</b> poly8_t poly8x16_t;
|
||||
|
||||
int8x8_t foo(int8x8_t a) {
|
||||
int8x8_t v;
|
||||
v = a;
|
||||
return v;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3><a name="vector_literals">Vector Literals</a></h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Vector literals can be used to create vectors from a set of scalars, or
|
||||
vectors. Either parentheses or braces form can be used. In the parentheses form
|
||||
the number of literal values specified must be one, i.e. referring to a scalar
|
||||
value, or must match the size of the vector type being created. If a single
|
||||
scalar literal value is specified, the scalar literal value will be replicated
|
||||
to all the components of the vector type. In the brackets form any number of
|
||||
literals can be specified. For example:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef int v4si __attribute__((__vector_size__(16)));
|
||||
typedef float float4 __attribute__((ext_vector_type(4)));
|
||||
typedef float float2 __attribute__((ext_vector_type(2)));
|
||||
|
||||
v4si vsi = (v4si){1, 2, 3, 4};
|
||||
float4 vf = (float4)(1.0f, 2.0f, 3.0f, 4.0f);
|
||||
vector int vi1 = (vector int)(1); // vi1 will be (1, 1, 1, 1).
|
||||
vector int vi2 = (vector int){1}; // vi2 will be (1, 0, 0, 0).
|
||||
vector int vi3 = (vector int)(1, 2); // error
|
||||
vector int vi4 = (vector int){1, 2}; // vi4 will be (1, 2, 0, 0).
|
||||
vector int vi5 = (vector int)(1, 2, 3, 4);
|
||||
float4 vf = (float4)((float2)(1.0f, 2.0f), (float2)(3.0f, 4.0f));
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3><a name="vector_operations">Vector Operations</a></h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The table below shows the support for each operation by vector extension.
|
||||
A dash indicates that an operation is not accepted according to a corresponding
|
||||
specification.</p>
|
||||
|
||||
<table width="500" border="1" cellspacing="0">
|
||||
<tr>
|
||||
<th>Operator</th>
|
||||
<th>OpenCL</th>
|
||||
<th>AltiVec</th>
|
||||
<th>GCC</th>
|
||||
<th>NEON</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[]</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>unary operators +, -</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>++, --</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>+, -, *, /, %</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bitwise operators &, |, ^, ~</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>>>, <<</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>!, &&,||</td>
|
||||
<td align="center">no</td>
|
||||
<td align="center">-</td>
|
||||
<td align="center">-</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>==,!=, >, <, >=, <=</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>=</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:?</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">-</td>
|
||||
<td align="center">-</td>
|
||||
<td align="center">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sizeof</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
<td align="center">yes</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>See also <a href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
|
||||
|
||||
|
|
@ -404,7 +593,8 @@ and <tt>unavailable</tt> attributes. For example:</p>
|
|||
will be incorporated into the appropriate diagnostic:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!! [-Wdeprecated-declarations]
|
||||
<pre>harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!!
|
||||
[-Wdeprecated-declarations]
|
||||
explode();
|
||||
^</pre>
|
||||
</blockquote>
|
||||
|
|
@ -436,234 +626,335 @@ individual enumerators.</p>
|
|||
|
||||
<p>Query for this feature with <tt>__has_extension(enumerator_attributes)</tt>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="user_specified_system_framework">'User-Specified' System Frameworks</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides a mechanism by which frameworks can be built in such a way
|
||||
that they will always be treated as being 'system frameworks', even if they are
|
||||
not present in a system framework directory. This can be useful to system
|
||||
framework developers who want to be able to test building other applications
|
||||
with development builds of their framework, including the manner in which the
|
||||
compiler changes warning behavior for system headers.</p>
|
||||
|
||||
<p>Framework developers can opt-in to this mechanism by creating a
|
||||
'.system_framework' file at the top-level of their framework. That is, the
|
||||
framework should have contents like:</p>
|
||||
|
||||
<pre>
|
||||
.../TestFramework.framework
|
||||
.../TestFramework.framework/.system_framework
|
||||
.../TestFramework.framework/Headers
|
||||
.../TestFramework.framework/Headers/TestFramework.h
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>Clang will treat the presence of this file as an indicator that the framework
|
||||
should be treated as a system framework, regardless of how it was found in the
|
||||
framework search path. For consistency, we recommend that such files never be
|
||||
included in installed versions of the framework.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="availability">Availability attribute</h2
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang introduces the <code>availability</code> attribute, which can
|
||||
be placed on declarations to describe the lifecycle of that
|
||||
declaration relative to operating system versions. Consider the function declaration for a hypothetical function <code>f</code>:</p>
|
||||
|
||||
<pre>
|
||||
void f(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
|
||||
</pre>
|
||||
|
||||
<p>The availability attribute states that <code>f</code> 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 is used by Clang to determine when it is safe to use <code>f</code>: for example, if Clang is instructed to compile code for Mac OS X 10.5, a call to <code>f()</code> succeeds. If Clang is instructed to compile code for Mac OS X 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 fails because <code>f()</code> is no longer available.</p>
|
||||
|
||||
<p>The availablility attribute is a comma-separated list starting with the platform name and then including clauses specifying important milestones in the declaration's lifetime (in any order) along with additional information. Those clauses can be:</p>
|
||||
|
||||
<dl>
|
||||
<dt>introduced=<i>version</i></dt>
|
||||
<dd>The first version in which this declaration was introduced.</dd>
|
||||
|
||||
<dt>deprecated=<i>version</i></dt>
|
||||
<dd>The first version in which this declaration was deprecated, meaning that users should migrate away from this API.</dd>
|
||||
|
||||
<dt>obsoleted=<i>version</i></dt>
|
||||
<dd>The first version in which this declaration was obsoleted, meaning that it was removed completely and can no longer be used.</dd>
|
||||
|
||||
<dt>unavailable</dt>
|
||||
<dd>This declaration is never available on this platform.</dd>
|
||||
|
||||
<dt>message=<i>string-literal</i></dt>
|
||||
<dd>Additional message text that Clang will provide when emitting a warning or error about use of a deprecated or obsoleted declaration. Useful to direct users to replacement APIs.</dd>
|
||||
</dl>
|
||||
|
||||
<p>Multiple availability attributes can be placed on a declaration, which may correspond to different platforms. Only the availability attribute with the platform corresponding to the target platform will be used; any others will be ignored. If no availability attribute specifies availability for the current target platform, the availability attributes are ignored. Supported platforms are:</p>
|
||||
|
||||
<dl>
|
||||
<dt>ios</dt>
|
||||
<dd>Apple's iOS operating system. The minimum deployment target is specified by the <code>-mios-version-min=<i>version</i></code> or <code>-miphoneos-version-min=<i>version</i></code> command-line arguments.</dd>
|
||||
|
||||
<dt>macosx</dt>
|
||||
<dd>Apple's Mac OS X operating system. The minimum deployment target is specified by the <code>-mmacosx-version-min=<i>version</i></code> command-line argument.</dd>
|
||||
</dl>
|
||||
|
||||
<p>A declaration can be used even when deploying back to a platform
|
||||
version prior to when the declaration was introduced. When this
|
||||
happens, the declaration is <a
|
||||
href="https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html">weakly
|
||||
linked</a>, as if the <code>weak_import</code> attribute were added to the declaration. A weakly-linked declaration may or may not be present a run-time, and a program can determine whether the declaration is present by checking whether the address of that declaration is non-NULL.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="checking_language_features">Checks for Standard Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The <tt>__has_feature</tt> macro can be used to query if certain standard language features are
|
||||
enabled. Those features are listed here.</p>
|
||||
<p>The <tt>__has_feature</tt> macro can be used to query if certain standard
|
||||
language features are enabled. The <tt>__has_extension</tt> macro can be used
|
||||
to query if language features are available as an extension when compiling for
|
||||
a standard which does not provide them. The features which can be tested are
|
||||
listed here.</p>
|
||||
|
||||
<h3 id="cxx_exceptions">C++ exceptions</h3>
|
||||
<h3 id="cxx98">C++98</h3>
|
||||
|
||||
<p>The features listed below are part of the C++98 standard. These features are
|
||||
enabled by default when compiling C++ code.</p>
|
||||
|
||||
<h4 id="cxx_exceptions">C++ exceptions</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_exceptions)</tt> to determine if C++ exceptions have been enabled. For
|
||||
example, compiling code with <tt>-fexceptions</tt> enables C++ exceptions.</p>
|
||||
example, compiling code with <tt>-fno-exceptions</tt> disables C++ exceptions.</p>
|
||||
|
||||
<h3 id="cxx_rtti">C++ RTTI</h3>
|
||||
<h4 id="cxx_rtti">C++ RTTI</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_rtti)</tt> to determine if C++ RTTI has been enabled. For example,
|
||||
compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="checking_upcoming_features">Checks for Upcoming Standard Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="cxx11">C++11</h3>
|
||||
|
||||
<p>The <tt>__has_feature</tt> or <tt>__has_extension</tt> macros can be used
|
||||
to query if certain upcoming standard language features are enabled. Those
|
||||
features are listed here. Features that are not yet implemented will be
|
||||
noted.</p>
|
||||
<p>The features listed below are part of the C++11 standard. As a result, all
|
||||
these features are enabled with the <tt>-std=c++11</tt> or <tt>-std=gnu++11</tt>
|
||||
option when compiling C++ code.</p>
|
||||
|
||||
<h3 id="cxx0x">C++0x</h3>
|
||||
|
||||
<p>The features listed below are slated for inclusion in the upcoming
|
||||
C++0x standard. As a result, all these features are enabled
|
||||
with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
|
||||
|
||||
<h4 id="cxx_access_control_sfinae">C++0x SFINAE includes access control</h4>
|
||||
<h4 id="cxx_access_control_sfinae">C++11 SFINAE includes access control</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_access_control_sfinae)</tt> or <tt>__has_extension(cxx_access_control_sfinae)</tt> to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1170">C++ DR1170</a>.</p>
|
||||
|
||||
<h4 id="cxx_alias_templates">C++0x alias templates</h4>
|
||||
<h4 id="cxx_alias_templates">C++11 alias templates</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_alias_templates)</tt> or
|
||||
<tt>__has_extension(cxx_alias_templates)</tt> to determine if support for
|
||||
C++0x's alias declarations and alias templates is enabled.</p>
|
||||
C++11's alias declarations and alias templates is enabled.</p>
|
||||
|
||||
<h4 id="cxx_alignas">C++0x alignment specifiers</h4>
|
||||
<h4 id="cxx_alignas">C++11 alignment specifiers</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_alignas)</tt> or
|
||||
<tt>__has_extension(cxx_alignas)</tt> to determine if support for alignment
|
||||
specifiers using <tt>alignas</tt> is enabled.</p>
|
||||
|
||||
<h4 id="cxx_attributes">C++0x attributes</h4>
|
||||
<h4 id="cxx_attributes">C++11 attributes</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_attributes)</tt> or
|
||||
<tt>__has_extension(cxx_attributes)</tt> to determine if support for attribute
|
||||
parsing with C++0x's square bracket notation is enabled.</p>
|
||||
parsing with C++11's square bracket notation is enabled.</p>
|
||||
|
||||
<h4 id="cxx_constexpr">C++0x generalized constant expressions</h4>
|
||||
<h4 id="cxx_constexpr">C++11 generalized constant expressions</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_constexpr)</tt> to determine if support
|
||||
for generalized constant expressions (e.g., <tt>constexpr</tt>) is
|
||||
enabled. Clang does not currently implement this feature.</p>
|
||||
enabled.</p>
|
||||
|
||||
<h4 id="cxx_decltype">C++0x <tt>decltype()</tt></h4>
|
||||
<h4 id="cxx_decltype">C++11 <tt>decltype()</tt></h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_decltype)</tt> or
|
||||
<tt>__has_extension(cxx_decltype)</tt> to determine if support for the
|
||||
<tt>decltype()</tt> specifier is enabled.</p>
|
||||
<tt>decltype()</tt> specifier is enabled. C++11's <tt>decltype</tt>
|
||||
does not require type-completeness of a function call expression.
|
||||
Use <tt>__has_feature(cxx_decltype_incomplete_return_types)</tt>
|
||||
or <tt>__has_extension(cxx_decltype_incomplete_return_types)</tt>
|
||||
to determine if support for this feature is enabled.</p>
|
||||
|
||||
<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h4>
|
||||
<h4 id="cxx_default_function_template_args">C++11 default template arguments in function templates</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
|
||||
<tt>__has_extension(cxx_default_function_template_args)</tt> to determine
|
||||
if support for default template arguments in function templates is enabled.</p>
|
||||
|
||||
<h4 id="cxx_delegating_constructors">C++0x delegating constructors</h4>
|
||||
<h4 id="cxx_defaulted_functions">C++11 <tt>default</tt>ed functions</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_defaulted_functions)</tt> or
|
||||
<tt>__has_extension(cxx_defaulted_functions)</tt> to determine if support for
|
||||
defaulted function definitions (with <tt>= default</tt>) is enabled.</p>
|
||||
|
||||
<h4 id="cxx_delegating_constructors">C++11 delegating constructors</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_delegating_constructors)</tt> to determine if
|
||||
support for delegating constructors is enabled.</p>
|
||||
|
||||
<h4 id="cxx_deleted_functions">C++0x <tt>delete</tt>d functions</h4>
|
||||
<h4 id="cxx_deleted_functions">C++11 <tt>delete</tt>d functions</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> or
|
||||
<tt>__has_extension(cxx_deleted_functions)</tt> to determine if support for
|
||||
deleted function definitions (with <tt>= delete</tt>) is enabled.</p>
|
||||
|
||||
<h4 id="cxx_explicit_conversions">C++0x explicit conversion functions</h3>
|
||||
<h4 id="cxx_explicit_conversions">C++11 explicit conversion functions</h4>
|
||||
<p>Use <tt>__has_feature(cxx_explicit_conversions)</tt> to determine if support for <tt>explicit</tt> conversion functions is enabled.</p>
|
||||
|
||||
<h4 id="cxx_generalized_initializers">C++0x generalized initializers</h4>
|
||||
<h4 id="cxx_generalized_initializers">C++11 generalized initializers</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_generalized_initializers)</tt> to determine if
|
||||
support for generalized initializers (using braced lists and
|
||||
<tt>std::initializer_list</tt>) is enabled. Clang does not currently implement
|
||||
this feature.</p>
|
||||
<tt>std::initializer_list</tt>) is enabled.</p>
|
||||
|
||||
<h4 id="cxx_implicit_moves">C++0x implicit move constructors/assignment operators</h4>
|
||||
<h4 id="cxx_implicit_moves">C++11 implicit move constructors/assignment operators</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_implicit_moves)</tt> to determine if Clang will
|
||||
implicitly generate move constructors and move assignment operators where needed.</p>
|
||||
|
||||
<h4 id="cxx_inheriting_constructors">C++0x inheriting constructors</h4>
|
||||
<h4 id="cxx_inheriting_constructors">C++11 inheriting constructors</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_inheriting_constructors)</tt> to determine if support for inheriting constructors is enabled. Clang does not currently implement this feature.</p>
|
||||
|
||||
<h4 id="cxx_inline_namespaces">C++0x inline namespaces</h4>
|
||||
<h4 id="cxx_inline_namespaces">C++11 inline namespaces</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> or
|
||||
<tt>__has_extension(cxx_inline_namespaces)</tt> to determine if support for
|
||||
inline namespaces is enabled.</p>
|
||||
|
||||
<h4 id="cxx_lambdas">C++0x lambdas</h4>
|
||||
<h4 id="cxx_lambdas">C++11 lambdas</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_lambdas)</tt> or
|
||||
<tt>__has_extension(cxx_lambdas)</tt> to determine if support for lambdas
|
||||
is enabled. Clang does not currently implement this feature.</p>
|
||||
is enabled. </p>
|
||||
|
||||
<h4 id="cxx_noexcept">C++0x noexcept</h4>
|
||||
<h4 id="cxx_local_type_template_args">C++11 local and unnamed types as template arguments</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_local_type_template_args)</tt> or
|
||||
<tt>__has_extension(cxx_local_type_template_args)</tt> to determine if
|
||||
support for local and unnamed types as template arguments is enabled.</p>
|
||||
|
||||
<h4 id="cxx_noexcept">C++11 noexcept</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_noexcept)</tt> or
|
||||
<tt>__has_extension(cxx_noexcept)</tt> to determine if support for noexcept
|
||||
exception specifications is enabled.</p>
|
||||
|
||||
<h4 id="cxx_nonstatic_member_init">C++0x in-class non-static data member initialization</h4>
|
||||
<h4 id="cxx_nonstatic_member_init">C++11 in-class non-static data member initialization</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_nonstatic_member_init)</tt> to determine whether in-class initialization of non-static data members is enabled.</p>
|
||||
|
||||
<h4 id="cxx_nullptr">C++0x <tt>nullptr</tt></h4>
|
||||
<h4 id="cxx_nullptr">C++11 <tt>nullptr</tt></h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_nullptr)</tt> or
|
||||
<tt>__has_extension(cxx_nullptr)</tt> to determine if support for
|
||||
<tt>nullptr</tt> is enabled.</p>
|
||||
|
||||
<h4 id="cxx_override_control">C++0x <tt>override control</tt></h4>
|
||||
<h4 id="cxx_override_control">C++11 <tt>override control</tt></h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_override_control)</tt> or
|
||||
<tt>__has_extension(cxx_override_control)</tt> to determine if support for
|
||||
the override control keywords is enabled.</p>
|
||||
|
||||
<h4 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h4>
|
||||
<h4 id="cxx_reference_qualified_functions">C++11 reference-qualified functions</h4>
|
||||
<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> or
|
||||
<tt>__has_extension(cxx_reference_qualified_functions)</tt> to determine
|
||||
if support for reference-qualified functions (e.g., member functions with
|
||||
<code>&</code> or <code>&&</code> applied to <code>*this</code>)
|
||||
is enabled.</p>
|
||||
|
||||
<h4 id="cxx_range_for">C++0x range-based <tt>for</tt> loop</h4>
|
||||
<h4 id="cxx_range_for">C++11 range-based <tt>for</tt> loop</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_range_for)</tt> or
|
||||
<tt>__has_extension(cxx_range_for)</tt> to determine if support for the
|
||||
range-based for loop is enabled. </p>
|
||||
|
||||
<h4 id="cxx_raw_string_literals">C++0x raw string literals</h4>
|
||||
<p>Use <tt>__has_feature(cxx_raw_string_literals)</tt> to determine if support for raw string literals (e.g., <tt>R"foo\bar"</tt>) is enabled.</p>
|
||||
<h4 id="cxx_raw_string_literals">C++11 raw string literals</h4>
|
||||
<p>Use <tt>__has_feature(cxx_raw_string_literals)</tt> to determine if support
|
||||
for raw string literals (e.g., <tt>R"x(foo\bar)x"</tt>) is enabled.</p>
|
||||
|
||||
<h4 id="cxx_rvalue_references">C++0x rvalue references</h4>
|
||||
<h4 id="cxx_rvalue_references">C++11 rvalue references</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
|
||||
<tt>__has_extension(cxx_rvalue_references)</tt> to determine if support for
|
||||
rvalue references is enabled. </p>
|
||||
|
||||
<h4 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h4>
|
||||
<h4 id="cxx_static_assert">C++11 <tt>static_assert()</tt></h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_static_assert)</tt> or
|
||||
<tt>__has_extension(cxx_static_assert)</tt> to determine if support for
|
||||
compile-time assertions using <tt>static_assert</tt> is enabled.</p>
|
||||
|
||||
<h4 id="cxx_auto_type">C++0x type inference</h4>
|
||||
<h4 id="cxx_auto_type">C++11 type inference</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_auto_type)</tt> or
|
||||
<tt>__has_extension(cxx_auto_type)</tt> to determine C++0x type inference is
|
||||
<tt>__has_extension(cxx_auto_type)</tt> to determine C++11 type inference is
|
||||
supported using the <tt>auto</tt> specifier. If this is disabled, <tt>auto</tt>
|
||||
will instead be a storage class specifier, as in C or C++98.</p>
|
||||
|
||||
<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</h4>
|
||||
<h4 id="cxx_strong_enums">C++11 strongly typed enumerations</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_strong_enums)</tt> or
|
||||
<tt>__has_extension(cxx_strong_enums)</tt> to determine if support for
|
||||
strongly typed, scoped enumerations is enabled.</p>
|
||||
|
||||
<h4 id="cxx_trailing_return">C++0x trailing return type</h4>
|
||||
<h4 id="cxx_trailing_return">C++11 trailing return type</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_trailing_return)</tt> or
|
||||
<tt>__has_extension(cxx_trailing_return)</tt> to determine if support for the
|
||||
alternate function declaration syntax with trailing return type is enabled.</p>
|
||||
|
||||
<h4 id="cxx_unicode_literals">C++0x Unicode string literals</h4>
|
||||
<h4 id="cxx_unicode_literals">C++11 Unicode string literals</h4>
|
||||
<p>Use <tt>__has_feature(cxx_unicode_literals)</tt> to determine if
|
||||
support for Unicode string literals is enabled.</p>
|
||||
|
||||
<h4 id="cxx_unrestricted_unions">C++0x unrestricted unions</h4>
|
||||
<h4 id="cxx_unrestricted_unions">C++11 unrestricted unions</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled. Clang does not currently support this feature.</p>
|
||||
<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled.</p>
|
||||
|
||||
<h4 id="cxx_user_literals">C++0x user-defined literals</h4>
|
||||
<h4 id="cxx_user_literals">C++11 user-defined literals</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_user_literals)</tt> to determine if support for user-defined literals is enabled. Clang does not currently support this feature.</p>
|
||||
<p>Use <tt>__has_feature(cxx_user_literals)</tt> to determine if support for user-defined literals is enabled.</p>
|
||||
|
||||
<h4 id="cxx_variadic_templates">C++0x variadic templates</h4>
|
||||
<h4 id="cxx_variadic_templates">C++11 variadic templates</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> or
|
||||
<tt>__has_extension(cxx_variadic_templates)</tt> to determine if support
|
||||
for variadic templates is enabled.</p>
|
||||
|
||||
<h3 id="c1x">C1X</h3>
|
||||
<h3 id="c11">C11</h3>
|
||||
|
||||
<p>The features listed below are slated for inclusion in the upcoming
|
||||
C1X standard. As a result, all these features are enabled
|
||||
with the <tt>-std=c1x</tt> option when compiling C code.</p>
|
||||
<p>The features listed below are part of the C11 standard. As a result, all
|
||||
these features are enabled with the <tt>-std=c11</tt> or <tt>-std=gnu11</tt>
|
||||
option when compiling C code. Additionally, because these features are all
|
||||
backward-compatible, they are available as extensions in all language modes.</p>
|
||||
|
||||
<h4 id="c_alignas">C1X alignment specifiers</h4>
|
||||
<h4 id="c_alignas">C11 alignment specifiers</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(c_alignas)</tt> or <tt>__has_extension(c_alignas)</tt>
|
||||
to determine if support for alignment specifiers using <tt>_Alignas</tt>
|
||||
is enabled.</p>
|
||||
|
||||
<h4 id="c_generic_selections">C1X generic selections</h4>
|
||||
<h4 id="c_atomic">C11 atomic operations</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(c_atomic)</tt> or <tt>__has_extension(c_atomic)</tt>
|
||||
to determine if support for atomic types using <tt>_Atomic</tt> is enabled.
|
||||
Clang also provides <a href="#__c11_atomic">a set of builtins</a> which can be
|
||||
used to implement the <tt><stdatomic.h></tt> operations on _Atomic
|
||||
types.</p>
|
||||
|
||||
<h4 id="c_generic_selections">C11 generic selections</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(c_generic_selections)</tt> or
|
||||
<tt>__has_extension(c_generic_selections)</tt> to determine if support for
|
||||
generic selections is enabled.</p>
|
||||
|
||||
<p>As an extension, the C1X generic selection expression is available in all
|
||||
<p>As an extension, the C11 generic selection expression is available in all
|
||||
languages supported by Clang. The syntax is the same as that given in the
|
||||
C1X draft standard.</p>
|
||||
C11 standard.</p>
|
||||
|
||||
<p>In C, type compatibility is decided according to the rules given in the
|
||||
appropriate standard, but in C++, which lacks the type compatibility rules
|
||||
used in C, types are considered compatible only if they are equivalent.</p>
|
||||
|
||||
<h4 id="c_static_assert">C1X <tt>_Static_assert()</tt></h4>
|
||||
<h4 id="c_static_assert">C11 <tt>_Static_assert()</tt></h4>
|
||||
|
||||
<p>Use <tt>__has_feature(c_static_assert)</tt> or
|
||||
<tt>__has_extension(c_static_assert)</tt> to determine if support for
|
||||
|
|
@ -707,7 +998,10 @@ struct is_convertible_to {
|
|||
<li><code>__is_polymorphic</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_union</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_literal(type)</code>: Determines whether the given type is a literal type</li>
|
||||
<li><code>__underlying_type(type)</code>: Retrieves the underlying type for a given <code>enum</code> type. This trait is required to implement the C++0x standard library.</li>
|
||||
<li><code>__is_final</code>: Determines whether the given type is declared with a <code>final</code> class-virt-specifier.</li>
|
||||
<li><code>__underlying_type(type)</code>: Retrieves the underlying type for a given <code>enum</code> type. This trait is required to implement the C++11 standard library.</li>
|
||||
<li><code>__is_trivially_assignable(totype, fromtype)</code>: Determines whether a value of type <tt>totype</tt> can be assigned to from a value of type <tt>fromtype</tt> such that no non-trivial functions are called as part of that assignment. This trait is required to implement the C++11 standard library.</li>
|
||||
<li><code>__is_trivially_constructible(type, argtypes...)</code>: Determines whether a value of type <tt>type</tt> can be direct-initialized with arguments of types <tt>argtypes...</tt> such that no non-trivial functions are called as part of that initialization. This trait is required to implement the C++11 standard library.</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -771,7 +1065,7 @@ an Objective-C method, e.g.</p>
|
|||
<p>The related result type can also be inferred for some methods.
|
||||
To determine whether a method has an inferred related result type, the first
|
||||
word in the camel-case selector (e.g., "init" in "initWithObjects") is
|
||||
considered, and the method will a related result type if its return
|
||||
considered, and the method will have a related result type if its return
|
||||
type is compatible with the type of its class and if</p>
|
||||
|
||||
<ul>
|
||||
|
|
@ -814,7 +1108,7 @@ the <tt>instancetype</tt> contextual keyword is available.</p>
|
|||
<h2 id="objc_fixed_enum">Enumerations with a fixed underlying type</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides support for C++0x enumerations with a fixed
|
||||
<p>Clang provides support for C++11 enumerations with a fixed
|
||||
underlying type within Objective-C. For example, one can write an
|
||||
enumeration type as:</p>
|
||||
|
||||
|
|
@ -828,6 +1122,72 @@ enumeration value, is <tt>unsigned char</tt>.</p>
|
|||
<p>Use <tt>__has_feature(objc_fixed_enum)</tt> to determine whether
|
||||
support for fixed underlying types is available in Objective-C.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objc_lambdas">Interoperability with C++11 lambdas</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides interoperability between C++11 lambdas and
|
||||
blocks-based APIs, by permitting a lambda to be implicitly converted
|
||||
to a block pointer with the corresponding signature. For example,
|
||||
consider an API such as <code>NSArray</code>'s array-sorting
|
||||
method:</p>
|
||||
|
||||
<pre> - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr; </pre>
|
||||
|
||||
<p><code>NSComparator</code> is simply a typedef for the block pointer
|
||||
<code>NSComparisonResult (^)(id, id)</code>, and parameters of this
|
||||
type are generally provided with block literals as arguments. However,
|
||||
one can also use a C++11 lambda so long as it provides the same
|
||||
signature (in this case, accepting two parameters of type
|
||||
<code>id</code> and returning an <code>NSComparisonResult</code>):</p>
|
||||
|
||||
<pre>
|
||||
NSArray *array = @[@"string 1", @"string 21", @"string 12", @"String 11",
|
||||
@"String 02"];
|
||||
const NSStringCompareOptions comparisonOptions
|
||||
= NSCaseInsensitiveSearch | NSNumericSearch |
|
||||
NSWidthInsensitiveSearch | NSForcedOrderingSearch;
|
||||
NSLocale *currentLocale = [NSLocale currentLocale];
|
||||
NSArray *sorted
|
||||
= [array sortedArrayUsingComparator:<b>[=](id s1, id s2) -> NSComparisonResult {
|
||||
NSRange string1Range = NSMakeRange(0, [s1 length]);
|
||||
return [s1 compare:s2 options:comparisonOptions
|
||||
range:string1Range locale:currentLocale];
|
||||
}</b>];
|
||||
NSLog(@"sorted: %@", sorted);
|
||||
</pre>
|
||||
|
||||
<p>This code relies on an implicit conversion from the type of the
|
||||
lambda expression (an unnamed, local class type called the <i>closure
|
||||
type</i>) to the corresponding block pointer type. The conversion
|
||||
itself is expressed by a conversion operator in that closure type
|
||||
that produces a block pointer with the same signature as the lambda
|
||||
itself, e.g.,</p>
|
||||
|
||||
<pre>
|
||||
operator NSComparisonResult (^)(id, id)() const;
|
||||
</pre>
|
||||
|
||||
<p>This conversion function returns a new block that simply forwards
|
||||
the two parameters to the lambda object (which it captures by copy),
|
||||
then returns the result. The returned block is first copied (with
|
||||
<tt>Block_copy</tt>) and then autoreleased. As an optimization, if a
|
||||
lambda expression is immediately converted to a block pointer (as in
|
||||
the first example, above), then the block is not copied and
|
||||
autoreleased: rather, it is given the same lifetime as a block literal
|
||||
written at that point in the program, which avoids the overhead of
|
||||
copying a block to the heap in the common case.</p>
|
||||
|
||||
<p>The conversion from a lambda to a block pointer is only available
|
||||
in Objective-C++, and not in C++ with blocks, due to its use of
|
||||
Objective-C memory management (autorelease).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="object-literals-subscripting">Object Literals and Subscripting</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals and Subscripting</a> in Objective-C, which simplifies common Objective-C programming patterns, makes programs more concise, and improves the safety of container creation. There are several feature macros associated with object literals and subscripting: <code>__has_feature(objc_array_literals)</code> tests the availability of array literals; <code>__has_feature(objc_dictionary_literals)</code> tests the availability of dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the availability of object subscripting.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="overloading-in-c">Function Overloading in C</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -1103,6 +1463,32 @@ relying on the platform specific implementation details of
|
|||
__sync_lock_test_and_set(). The __sync_swap() builtin is a full barrier.
|
||||
</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3><a name="__c11_atomic">__c11_atomic builtins</a></h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides a set of builtins which are intended to be used to implement
|
||||
C11's <tt><stdatomic.h></tt> header. These builtins provide the semantics
|
||||
of the <tt>_explicit</tt> form of the corresponding C11 operation, and are named
|
||||
with a <tt>__c11_</tt> prefix. The supported operations are:</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>__c11_atomic_init</tt></li>
|
||||
<li><tt>__c11_atomic_thread_fence</tt></li>
|
||||
<li><tt>__c11_atomic_signal_fence</tt></li>
|
||||
<li><tt>__c11_atomic_is_lock_free</tt></li>
|
||||
<li><tt>__c11_atomic_store</tt></li>
|
||||
<li><tt>__c11_atomic_load</tt></li>
|
||||
<li><tt>__c11_atomic_exchange</tt></li>
|
||||
<li><tt>__c11_atomic_compare_exchange_strong</tt></li>
|
||||
<li><tt>__c11_atomic_compare_exchange_weak</tt></li>
|
||||
<li><tt>__c11_atomic_fetch_add</tt></li>
|
||||
<li><tt>__c11_atomic_fetch_sub</tt></li>
|
||||
<li><tt>__c11_atomic_fetch_and</tt></li>
|
||||
<li><tt>__c11_atomic_fetch_or</tt></li>
|
||||
<li><tt>__c11_atomic_fetch_xor</tt></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="targetspecific">Target-Specific Extensions</h2>
|
||||
|
|
@ -1264,6 +1650,18 @@ balance in some way.</p>
|
|||
<p>Query for these features with <tt>__has_attribute(ns_consumed)</tt>,
|
||||
<tt>__has_attribute(ns_returns_retained)</tt>, etc.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="dynamicanalyzerspecific">Dynamic Analysis-Specific Extensions</h2>
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="address_sanitizer">AddressSanitizer</h3>
|
||||
<p> Use <code>__has_feature(address_sanitizer)</code>
|
||||
to check if the code is being built with <a
|
||||
href="AddressSanitizer.html">AddressSanitizer</a>.
|
||||
</p>
|
||||
<p>Use <tt>__attribute__((no_address_safety_analysis))</tt> on a function
|
||||
declaration to specify that address safety instrumentation (e.g.
|
||||
AddressSanitizer) should not be applied to that function.
|
||||
</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="threadsafety">Thread-Safety Annotation Checking</h2>
|
||||
|
|
|
|||
314
docs/ObjectiveCLiterals.html
Normal file
314
docs/ObjectiveCLiterals.html
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
|
||||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=UTF8">
|
||||
<title>Clang Language Extensions</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
th { background-color: #ffddaa; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Objective-C Literals</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
Three new features were introduced into clang at the same time: <i>NSNumber Literals</i> provide a syntax for creating <code>NSNumber</code> from scalar literal expressions; <i>Collection Literals</i> provide a short-hand for creating arrays and dictionaries; <i>Object Subscripting</i> provides a way to use subscripting with Objective-C objects. Users of Apple compiler releases can use these features starting with the Apple LLVM Compiler 4.0. Users of open-source LLVM.org compiler releases can use these features starting with clang v3.1.<p>
|
||||
|
||||
These language additions simplify common Objective-C programming patterns, make programs more concise, and improve the safety of container creation.<p>
|
||||
|
||||
This document describes how the features are implemented in clang, and how to use them in your own programs.<p>
|
||||
|
||||
<h2>NSNumber Literals</h2>
|
||||
|
||||
The framework class <code>NSNumber</code> is used to wrap scalar values inside objects: signed and unsigned integers (<code>char</code>, <code>short</code>, <code>int</code>, <code>long</code>, <code>long long</code>), floating point numbers (<code>float</code>, <code>double</code>), and boolean values (<code>BOOL</code>, C++ <code>bool</code>). Scalar values wrapped in objects are also known as <i>boxed</i> values.<p>
|
||||
|
||||
In Objective-C, any character, numeric or boolean literal prefixed with the <code>'@'</code> character will evaluate to a pointer to an <code>NSNumber</code> object initialized with that value. C's type suffixes may be used to control the size of numeric literals.
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
The following program illustrates the rules for <code>NSNumber</code> literals:<p>
|
||||
|
||||
<pre>
|
||||
void main(int argc, const char *argv[]) {
|
||||
// character literals.
|
||||
NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z']
|
||||
|
||||
// integral literals.
|
||||
NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42]
|
||||
NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
|
||||
NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L]
|
||||
NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
|
||||
|
||||
// floating point literals.
|
||||
NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F]
|
||||
NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535]
|
||||
|
||||
// BOOL literals.
|
||||
NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES]
|
||||
NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO]
|
||||
|
||||
#ifdef __cplusplus
|
||||
NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true]
|
||||
NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false]
|
||||
#endif
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
NSNumber literals only support literal scalar values after the '@'. Consequently, @INT_MAX works, but @INT_MIN does not, because they are defined like this:<p>
|
||||
|
||||
<pre>
|
||||
#define INT_MAX 2147483647 /* max value for an int */
|
||||
#define INT_MIN (-2147483647-1) /* min value for an int */
|
||||
</pre>
|
||||
|
||||
The definition of INT_MIN is not a simple literal, but a parenthesized expression. This is by design, but may be improved in subsequent compiler releases.<p>
|
||||
|
||||
Because <code>NSNumber</code> does not currently support wrapping <code>long double</code> values, the use of a <code>long double NSNumber</code> literal (e.g. <code>@123.23L</code>) will be rejected by the compiler.<p>
|
||||
|
||||
Previously, the <code>BOOL</code> type was simply a typedef for <code>signed char</code>, and <code>YES</code> and <code>NO</code> were macros that expand to <code>(BOOL)1</code> and <code>(BOOL)0</code> respectively. To support <code>@YES</code> and <code>@NO</code> expressions, these macros are now defined using new language keywords in <code><objc/objc.h></code>:<p>
|
||||
|
||||
<pre>
|
||||
#if __has_feature(objc_bool)
|
||||
#define YES __objc_yes
|
||||
#define NO __objc_no
|
||||
#else
|
||||
#define YES ((BOOL)1)
|
||||
#define NO ((BOOL)0)
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
The compiler implicitly converts <code>__objc_yes</code> and <code>__objc_no</code> to <code>(BOOL)1</code> and <code>(BOOL)0</code>. The keywords are used to disambiguate <code>BOOL</code> and integer literals.<p>
|
||||
|
||||
Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.
|
||||
|
||||
|
||||
<h2>Container Literals</h2>
|
||||
|
||||
Objective-C now supports a new expression syntax for creating immutable array and dictionary container objects.
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
Immutable array expression:<p>
|
||||
|
||||
<pre>
|
||||
NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
|
||||
</pre>
|
||||
|
||||
This creates an <code>NSArray</code> with 3 elements. The comma-separated sub-expressions of an array literal can be any Objective-C object pointer typed expression.<p>
|
||||
|
||||
Immutable dictionary expression:<p>
|
||||
|
||||
<pre>
|
||||
NSDictionary *dictionary = @{
|
||||
@"name" : NSUserName(),
|
||||
@"date" : [NSDate date],
|
||||
@"processInfo" : [NSProcessInfo processInfo]
|
||||
};
|
||||
</pre>
|
||||
|
||||
This creates an <code>NSDictionary</code> with 3 key/value pairs. Value sub-expressions of a dictionary literal must be Objective-C object pointer typed, as in array literals. Key sub-expressions must be of an Objective-C object pointer type that implements the <code><NSCopying></code> protocol.<p>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
Neither keys nor values can have the value <code>nil</code> in containers. If the compiler can prove that a key or value is <code>nil</code> at compile time, then a warning will be emitted. Otherwise, a runtime error will occur.<p>
|
||||
|
||||
Using array and dictionary literals is safer than the variadic creation forms commonly in use today. Array literal expressions expand to calls to <code>+[NSArray arrayWithObjects:count:]</code>, which validates that all objects are non-<code>nil</code>. The variadic form, <code>+[NSArray arrayWithObjects:]</code> uses <code>nil</code> as an argument list terminator, which can lead to malformed array objects. Dictionary literals are similarly created with <code>+[NSDictionary dictionaryWithObjects:forKeys:count:]</code> which validates all objects and keys, unlike <code>+[NSDictionary dictionaryWithObjectsAndKeys:]</code> which also uses a <code>nil</code> parameter as an argument list terminator.<p>
|
||||
|
||||
<h2>Object Subscripting</h2>
|
||||
|
||||
Objective-C object pointer values can now be used with C's subscripting operator.<p>
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
The following code demonstrates the use of object subscripting syntax with <code>NSMutableArray</code> and <code>NSMutableDictionary</code> objects:<p>
|
||||
|
||||
<pre>
|
||||
NSMutableArray *array = ...;
|
||||
NSUInteger idx = ...;
|
||||
id newObject = ...;
|
||||
id oldObject = array[idx];
|
||||
array[idx] = newObject; // replace oldObject with newObject
|
||||
|
||||
NSMutableDictionary *dictionary = ...;
|
||||
NSString *key = ...;
|
||||
oldObject = dictionary[key];
|
||||
dictionary[key] = newObject; // replace oldObject with newObject
|
||||
</pre>
|
||||
|
||||
The next section explains how subscripting expressions map to accessor methods.<p>
|
||||
|
||||
<h3>Subscripting Methods</h3>
|
||||
|
||||
Objective-C supports two kinds of subscript expressions: <i>array-style</i> subscript expressions use integer typed subscripts; <i>dictionary-style</i> subscript expressions use Objective-C object pointer typed subscripts. Each type of subscript expression is mapped to a message send using a predefined selector. The advantage of this design is flexibility: class designers are free to introduce subscripting by declaring methods or by adopting protocols. Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.
|
||||
|
||||
<h4>Array-Style Subscripting</h4>
|
||||
|
||||
When the subscript operand has an integral type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. When an expression reads an element using an integral index, as in the following example:<p>
|
||||
|
||||
<pre>
|
||||
NSUInteger idx = ...;
|
||||
id value = object[idx];
|
||||
</pre>
|
||||
|
||||
it is translated into a call to <code>objectAtIndexedSubscript:</code><p>
|
||||
|
||||
<pre>
|
||||
id value = [object objectAtIndexedSubscript:idx];
|
||||
</pre>
|
||||
|
||||
When an expression writes an element using an integral index:<p>
|
||||
|
||||
<pre>
|
||||
object[idx] = newValue;
|
||||
</pre>
|
||||
|
||||
it is translated to a call to <code>setObject:atIndexedSubscript:</code><p>
|
||||
|
||||
<pre>
|
||||
[object setObject:newValue atIndexedSubscript:idx];
|
||||
</pre>
|
||||
|
||||
These message sends are then type-checked and performed just like explicit message sends. The method used for objectAtIndexedSubscript: must be declared with an argument of integral type and a return value of some Objective-C object pointer type. The method used for setObject:atIndexedSubscript: must be declared with its first argument having some Objective-C pointer type and its second argument having integral type.<p>
|
||||
|
||||
The meaning of indexes is left up to the declaring class. The compiler will coerce the index to the appropriate argument type of the method it uses for type-checking. For an instance of <code>NSArray</code>, reading an element using an index outside the range <code>[0, array.count)</code> will raise an exception. For an instance of <code>NSMutableArray</code>, assigning to an element using an index within this range will replace that element, but assigning to an element using an index outside this range will raise an exception; no syntax is provided for inserting, appending, or removing elements for mutable arrays.<p>
|
||||
|
||||
A class need not declare both methods in order to take advantage of this language feature. For example, the class <code>NSArray</code> declares only <code>objectAtIndexedSubscript:</code>, so that assignments to elements will fail to type-check; moreover, its subclass <code>NSMutableArray</code> declares <code>setObject:atIndexedSubscript:</code>.
|
||||
|
||||
<h4>Dictionary-Style Subscripting</h4>
|
||||
|
||||
When the subscript operand has an Objective-C object pointer type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read from or written to. When an expression reads an element using an Objective-C object pointer subscript operand, as in the following example:<p>
|
||||
|
||||
<pre>
|
||||
id key = ...;
|
||||
id value = object[key];
|
||||
</pre>
|
||||
|
||||
it is translated into a call to the <code>objectForKeyedSubscript:</code> method:<p>
|
||||
|
||||
<pre>
|
||||
id value = [object objectForKeyedSubscript:key];
|
||||
</pre>
|
||||
|
||||
When an expression writes an element using an Objective-C object pointer subscript:<p>
|
||||
|
||||
<pre>
|
||||
object[key] = newValue;
|
||||
</pre>
|
||||
|
||||
it is translated to a call to <code>setObject:forKeyedSubscript:</code>
|
||||
|
||||
<pre>
|
||||
[object setObject:newValue forKeyedSubscript:key];
|
||||
</pre>
|
||||
|
||||
The behavior of <code>setObject:forKeyedSubscript:</code> is class-specific; but in general it should replace an existing value if one is already associated with a key, otherwise it should add a new value for the key. No syntax is provided for removing elements from mutable dictionaries.<p>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
An Objective-C subscript expression occurs when the base operand of the C subscript operator has an Objective-C object pointer type. Since this potentially collides with pointer arithmetic on the value, these expressions are only supported under the modern Objective-C runtime, which categorically forbids such arithmetic.<p>
|
||||
|
||||
Currently, only subscripts of integral or Objective-C object pointer type are supported. In C++, a class type can be used if it has a single conversion function to an integral or Objective-C pointer type, in which case that conversion is applied and analysis continues as appropriate. Otherwise, the expression is ill-formed.<p>
|
||||
|
||||
An Objective-C object subscript expression is always an l-value. If the expression appears on the left-hand side of a simple assignment operator (=), the element is written as described below. If the expression appears on the left-hand side of a compound assignment operator (e.g. +=), the program is ill-formed, because the result of reading an element is always an Objective-C object pointer and no binary operators are legal on such pointers. If the expression appears in any other position, the element is read as described below. It is an error to take the address of a subscript expression, or (in C++) to bind a reference to it.<p>
|
||||
|
||||
Programs can use object subscripting with Objective-C object pointers of type <code>id</code>. Normal dynamic message send rules apply; the compiler must see <i>some</i> declaration of the subscripting methods, and will pick the declaration seen first.<p>
|
||||
|
||||
<h2>Grammar Additions</h2>
|
||||
|
||||
To support the new syntax described above, the Objective-C <code>@</code>-expression grammar has the following new productions:<p>
|
||||
|
||||
<pre>
|
||||
objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal)
|
||||
;
|
||||
|
||||
object-literal : ('+' | '-')? numeric-constant
|
||||
| character-constant
|
||||
| boolean-constant
|
||||
| array-literal
|
||||
| dictionary-literal
|
||||
;
|
||||
|
||||
boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */
|
||||
;
|
||||
|
||||
array-literal : '[' assignment-expression-list ']'
|
||||
;
|
||||
|
||||
assignment-expression-list : assignment-expression (',' assignment-expression-list)?
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
dictionary-literal : '{' key-value-list '}'
|
||||
;
|
||||
|
||||
key-value-list : key-value-pair (',' key-value-list)?
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
key-value-pair : assignment-expression ':' assignment-expression
|
||||
;
|
||||
</pre>
|
||||
|
||||
Note: <code>@true</code> and <code>@false</code> are only supported in Objective-C++.<p>
|
||||
|
||||
<h2>Availability Checks</h2>
|
||||
|
||||
Programs test for the new features by using clang's __has_feature checks. Here are examples of their use:<p>
|
||||
|
||||
<pre>
|
||||
#if __has_feature(objc_array_literals)
|
||||
// new way.
|
||||
NSArray *elements = @[ @"H", @"He", @"O", @"C" ];
|
||||
#else
|
||||
// old way (equivalent).
|
||||
id objects[] = { @"H", @"He", @"O", @"C" };
|
||||
NSArray *elements = [NSArray arrayWithObjects:objects count:4];
|
||||
#endif
|
||||
|
||||
#if __has_feature(objc_dictionary_literals)
|
||||
// new way.
|
||||
NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 };
|
||||
#else
|
||||
// old way (equivalent).
|
||||
id keys[] = { @"H", @"He", @"O", @"C" };
|
||||
id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026],
|
||||
[NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] };
|
||||
NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4];
|
||||
#endif
|
||||
|
||||
#if __has_feature(objc_subscripting)
|
||||
NSUInteger i, count = elements.count;
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSString *element = elements[i];
|
||||
NSNumber *mass = masses[element];
|
||||
NSLog(@"the mass of %@ is %@", element, mass);
|
||||
}
|
||||
#else
|
||||
NSUInteger i, count = [elements count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSString *element = [elements objectAtIndex:i];
|
||||
NSNumber *mass = [masses objectForKey:element];
|
||||
NSLog(@"the mass of %@ is %@", element, mass);
|
||||
}
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
Code can use also <code>__has_feature(objc_bool)</code> to check for the availability of numeric literals support. This checks for the new <code>__objc_yes / __objc_no</code> keywords, which enable the use of <code>@YES / @NO</code> literals.<p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Precompiled Headers (PCH)</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
|
|
@ -155,7 +157,7 @@ without duplicating the data from the common headers for every file.</p>
|
|||
|
||||
<h2 id="contents">Precompiled Header Contents</h2>
|
||||
|
||||
<img src="PCHLayout.png" align="right" alt="Precompiled header layout">
|
||||
<img src="PCHLayout.png" style="float:right" alt="Precompiled header layout">
|
||||
|
||||
<p>Clang's precompiled headers are organized into several different
|
||||
blocks, each of which contains the serialized representation of a part
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Pretokenized Headers (PTH)</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
|
|
|
|||
193
docs/ReleaseNotes.html
Normal file
193
docs/ReleaseNotes.html
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang 3.1 Release Notes</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Clang 3.1 Release Notes</h1>
|
||||
|
||||
<img style="float:right" src="http://llvm.org/img/DragonSmall.png"
|
||||
width="136" height="136" alt="LLVM Dragon Logo">
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#whatsnew">What's New in Clang 3.1?</a>
|
||||
<ul>
|
||||
<li><a href="#majorfeatures">Major New Features</a></li>
|
||||
<li><a href="#cchanges">C Language Changes</a></li>
|
||||
<li><a href="#cxxchanges">C++ Language Changes</a></li>
|
||||
<li><a href="#objcchanges">Objective-C Language Changes</a></li>
|
||||
<li><a href="#apichanges">Internal API Changes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#knownproblems">Known Problems</a></li>
|
||||
<li><a href="#additionalinfo">Additional Information</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="doc_author">
|
||||
<p>Written by the <a href="http://llvm.org/">LLVM Team</a></p>
|
||||
</div>
|
||||
|
||||
<h1 style="color:red">These are in-progress notes for the upcoming Clang 3.1
|
||||
release.<br>
|
||||
You may prefer the
|
||||
<a href="http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html">Clang 3.0
|
||||
Release Notes</a>.</h1>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This document contains the release notes for the Clang C/C++/Objective-C
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.1. 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 <a href="http://llvm.org/docs/ReleaseNotes.html">the LLVM
|
||||
documentation</a>. All LLVM releases may be downloaded from the
|
||||
<a href="http://llvm.org/releases/">LLVM releases web site</a>.</p>
|
||||
|
||||
<p>For more information about Clang or LLVM, including information about the
|
||||
latest release, please check out the main please see the
|
||||
<a href="http://clang.llvm.org">Clang Web Site</a> or the
|
||||
<a href="http://llvm.org">LLVM Web Site</a>.
|
||||
|
||||
<p>Note that if you are reading this file from a Subversion checkout or the main
|
||||
Clang web page, this document applies to the <i>next</i> release, not the
|
||||
current one. To see the release notes for a specific release, please see the
|
||||
<a href="http://llvm.org/releases/">releases page</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="whatsnew">What's New in Clang 3.1?</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Some of the major new features and improvements to Clang are listed here.
|
||||
Generic improvements to Clang as a whole or two its underlying infrastructure
|
||||
are described first, followed by language-specific sections with improvements to
|
||||
Clang's support for those languages.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="majorfeatures">Major New Features</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="majorfeature1">Feature 1</h4>
|
||||
...
|
||||
|
||||
<h4 id="diagnostics">New and better diagnostics</h4>
|
||||
|
||||
<p>New: <code>-Wdangling-else</code>, <code>-Wstrncat-size</code>, ...</p>
|
||||
|
||||
<p>Improved: <code>-Wformat</code>, <code>-Wempty-body</code>,
|
||||
<code>-Wliteral-conversion</code>, ...</p>
|
||||
|
||||
<h4 id="tooling">Tooling</h4>
|
||||
<!-- FIXME: add a link to the tooling documentation once that's written. -->
|
||||
<p>Added an API to enable clang-based standalone tools, including initial build
|
||||
system integration.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cchanges">C Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="c11changes">C11 Feature Support</h4>
|
||||
|
||||
<p>Clang 3.1 adds support for anonymous structs and anonymous unions, added in
|
||||
the latest ISO C standard. Use <code>-std=c11</code> or <code>-std=gnu11</code>
|
||||
to enable support for the new language standard. The new C11 features are
|
||||
backwards-compatible and are available as an extension in all language
|
||||
modes.</p>
|
||||
|
||||
<p>All warning and language selection flags which previously accepted
|
||||
<code>c1x</code> have been updated to accept <code>c11</code>. The old
|
||||
<code>c1x</code> forms have been removed.
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cxxchanges">C++ Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="cxx11changes">C++11 Feature Support</h4>
|
||||
<p>Clang 3.1 adds support for
|
||||
<a href="http://clang.llvm.org/cxx_status.html#cxx11">more of the language
|
||||
features</a> added in the latest ISO C++ standard,
|
||||
<a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">C++ 2011</a>.
|
||||
Use <code>-std=c++11</code> or <code>-std=gnu++11</code> to enable support for
|
||||
these features. In addition to the features supported by Clang 3.0, the
|
||||
following are now considered to be of production quality:
|
||||
<ul>
|
||||
<li>Generalized constant expressions</li>
|
||||
<li>Lambda expressions</li>
|
||||
<li>Generalized initializers</li>
|
||||
<li>Unrestricted unions</li>
|
||||
<li>User-defined literals</li>
|
||||
<li>Forward-declared enumerations</li>
|
||||
<li>Atomics (both libc++'s and libstdc++4.7's <tt><atomic></tt> are
|
||||
supported)</li>
|
||||
</ul>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="objcchanges">Objective-C Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
Clang 3.1 introduces several new Objective-C language features and improvements.
|
||||
|
||||
<h4 id="objcwformat">Format string checking for NSString literals</h4>
|
||||
|
||||
<code>-Wformat</code> now checks <code>@"nsstring literals"</code>.
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="apichanges">Internal API Changes</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
These are major API changes that have happened since the 3.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.
|
||||
|
||||
<h4 id="api1">API change 1</h4>
|
||||
...
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="knownproblems">Significant Known Problems</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="additionalinfo">Additional Information</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>A wide variety of additional information is available on the
|
||||
<a href="http://clang.llvm.org/">Clang web page</a>. The web page contains
|
||||
versions of the API documentation which are up-to-date with the Subversion
|
||||
version of the source code. You can access versions of these documents specific
|
||||
to this release by going into the "<tt>clang/doc/</tt>" directory in the Clang
|
||||
tree.</p>
|
||||
|
||||
<p>If you have any questions or comments about Clang, please feel free to
|
||||
contact us via the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">
|
||||
mailing list</a>.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<!-- Likely 3.1 release notes -->
|
||||
<!-- ======================================================================= -->
|
||||
<!--
|
||||
This is just a section to hold things that have already gotten started and
|
||||
should likely pick up proper release notes in 3.1.
|
||||
|
||||
- C1X and C++11 atomics infrastructure and support
|
||||
- CUDA support?
|
||||
|
||||
-->
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Compiler User's Manual</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
|
|
@ -28,6 +30,8 @@ td {
|
|||
<ul>
|
||||
<li><a href="#cl_diagnostics">Options to Control Error and Warning
|
||||
Messages</a></li>
|
||||
<li><a href="#cl_crash_diagnostics">Options to Control Clang Crash
|
||||
Diagnostics</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#general_features">Language and Target-Independent Features</a>
|
||||
|
|
@ -56,6 +60,11 @@ td {
|
|||
<li><a href="#c_ms">Microsoft extensions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#cxx">C++ Language Features</a>
|
||||
<ul>
|
||||
<li><a href="#cxx_implimits">Controlling implementation limits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#target_features">Target-Specific Features and Limitations</a>
|
||||
<ul>
|
||||
<li><a href="#target_arch">CPU Architectures Features and Limitations</a>
|
||||
|
|
@ -92,7 +101,7 @@ Web Site</a> or the <a href="http://llvm.org">LLVM Web Site</a>.</p>
|
|||
an end-user, documenting the supported features, command line options, etc. If
|
||||
you are interested in using Clang to build a tool that processes code, please
|
||||
see <a href="InternalsManual.html">the Clang Internals Manual</a>. If you are
|
||||
interested in the <a href="http://clang.llvm.org/StaticAnalysis.html">Clang
|
||||
interested in the <a href="http://clang-analyzer.llvm.org">Clang
|
||||
Static Analyzer</a>, please see its web page.</p>
|
||||
|
||||
<p>Clang is designed to support the C family of programming languages, which
|
||||
|
|
@ -106,7 +115,7 @@ corresponding language specific section:</p>
|
|||
(C89+AMD1), ISO C99 (+TC1, TC2, TC3). </li>
|
||||
<li><a href="#objc">Objective-C Language</a>: ObjC 1, ObjC 2, ObjC 2.1, plus
|
||||
variants depending on base language.</li>
|
||||
<li><a href="#cxx">C++ Language Features</a></li>
|
||||
<li><a href="#cxx">C++ Language</a></li>
|
||||
<li><a href="#objcxx">Objective C++ Language</a></li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -258,10 +267,10 @@ when this is enabled, Clang will print something like:
|
|||
When this option is enabled, Clang will use colors to highlight
|
||||
specific parts of the diagnostic, e.g.,
|
||||
<pre>
|
||||
<b><font color="black">test.c:28:8: <font color="magenta">warning</font>: extra tokens at end of #endif directive [-Wextra-tokens]</font></b>
|
||||
<b><span style="color:black">test.c:28:8: <span style="color:magenta">warning</span>: extra tokens at end of #endif directive [-Wextra-tokens]</span></b>
|
||||
#endif bad
|
||||
<font color="green">^</font>
|
||||
<font color="green">//</font>
|
||||
<span style="color:green">^</span>
|
||||
<span style="color:green">//</span>
|
||||
</pre>
|
||||
|
||||
<p>When this is disabled, Clang will just print:</p>
|
||||
|
|
@ -300,8 +309,7 @@ Changes diagnostic output format to better match IDEs and command line tools.</d
|
|||
<dt id="opt_fdiagnostics-show-name"><b>-f[no-]diagnostics-show-name</b>:
|
||||
Enable the display of the diagnostic name.</dt>
|
||||
<dd>This option, which defaults to off, controls whether or not
|
||||
Clang prints the associated name.</dd>
|
||||
<br>
|
||||
Clang prints the associated name.<p></p></dd>
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
|
||||
Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
|
||||
|
|
@ -409,7 +417,6 @@ quotes(as "\"") and non-printable characters (as octal
|
|||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ===================================================== -->
|
||||
|
|
@ -480,7 +487,7 @@ constructor. For example:
|
|||
};
|
||||
void foo(const NonCopyable&);
|
||||
void bar() {
|
||||
foo(NonCopyable()); // Disallowed in C++98; allowed in C++0x.
|
||||
foo(NonCopyable()); // Disallowed in C++98; allowed in C++11.
|
||||
}
|
||||
</pre>
|
||||
<pre>
|
||||
|
|
@ -490,7 +497,7 @@ constructor. For example:
|
|||
};
|
||||
void foo(const NonCopyable2&);
|
||||
void bar() {
|
||||
foo(NonCopyable2()); // Disallowed in C++98; allowed in C++0x.
|
||||
foo(NonCopyable2()); // Disallowed in C++98; allowed in C++11.
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
|
@ -503,6 +510,27 @@ off.</p>
|
|||
|
||||
</dl>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cl_crash_diagnostics">Options to Control Clang Crash Diagnostics</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>As unbelievable as it may sound, Clang does crash from time to time.
|
||||
Generally, this only occurs to those living on the
|
||||
<a href="http://llvm.org/releases/download.html#svn">bleeding edge</a>. Clang
|
||||
goes to great lengths to assist you in filing a bug report. Specifically, Clang
|
||||
generates preprocessed source file(s) and associated run script(s) upon a
|
||||
crash. These files should be attached to a bug report to ease reproducibility
|
||||
of the failure. Below are the command line options to control the crash
|
||||
diagnostics.
|
||||
</p>
|
||||
|
||||
<p><b>-fno-crash-diagnostics</b>: Disable auto-generation of preprocessed
|
||||
source files during a clang crash.</p>
|
||||
|
||||
<p>The -fno-crash-diagnostics flag can be helpful for speeding the process of
|
||||
generating a delta reduced test case.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="general_features">Language and Target-Independent Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -529,8 +557,6 @@ it:</p>
|
|||
<li>A categorization of the diagnostic as a note, warning, error, or fatal
|
||||
error.</li>
|
||||
<li>A text string that describes what the problem is.</li>
|
||||
<li>An option that indicates whether to print the diagnostic name [<a
|
||||
href="#opt_fdiagnostics-show-name">-fdiagnostics-show-name</a>].</li>
|
||||
<li>An option that indicates how to control the diagnostic (for diagnostics that
|
||||
support it) [<a
|
||||
href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li>
|
||||
|
|
@ -669,7 +695,7 @@ In general, this usage is discouraged. Instead, we prefer that users file bugs
|
|||
against the analyzer when it flags false positives. There is also active
|
||||
discussion of allowing users in the future to selectively silence specific
|
||||
analyzer warnings (some of which can already be done using <a
|
||||
href="analyzer_annotations">annotations</a>).</li>
|
||||
href="#analyzer_annotations">annotations</a>).</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
|
@ -804,6 +830,14 @@ The checks are:
|
|||
</ul>
|
||||
</dd>
|
||||
|
||||
<dt id="opt_faddress-sanitizer"><b>-f[no-]address-sanitizer</b>:
|
||||
Turn on <a href="AddressSanitizer.html">AddressSanitizer</a>,
|
||||
a memory error detector.
|
||||
|
||||
<dt id="opt_fthread-sanitizer"><b>-f[no-]thread-sanitizer</b>:
|
||||
Turn on ThreadSanitizer, an <em>experimental</em> data race detector.
|
||||
Not ready for widespread use.
|
||||
|
||||
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
|
||||
Don't assume that the C++'s new operator is sane.</dt>
|
||||
<dd>This option tells the compiler to do not assume that C++'s global new
|
||||
|
|
@ -951,10 +985,6 @@ a structure).</li>
|
|||
clang doesn't accept some constructs gcc might accept in contexts where a
|
||||
constant expression is required, like "x-x" where x is a variable.</li>
|
||||
|
||||
<li>clang does not support multiple alternative constraints in inline asm; this
|
||||
is an extremely obscure feature which would be complicated to implement
|
||||
correctly.</li>
|
||||
|
||||
<li>clang does not support __builtin_apply and friends; this extension is
|
||||
extremely obscure and difficult to implement reliably.</li>
|
||||
|
||||
|
|
@ -987,6 +1017,25 @@ however where MSVC and GCC are incompatible clang follows the MSVC
|
|||
definition.</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="cxx">C++ Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>clang fully implements all of standard C++98 except for exported templates
|
||||
(which were removed in C++11), and
|
||||
<a href="http://clang.llvm.org/cxx_status.html">many C++11 features</a> are also
|
||||
implemented.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cxx_implimits">Controlling implementation limits</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p><b>-fconstexpr-depth=N</b>: Sets the limit for recursive constexpr function
|
||||
invocations to N. The default is 512.</p>
|
||||
|
||||
<p><b>-ftemplate-depth=N</b>: Sets the limit for recursively nested template
|
||||
instantiations to N. The default is 1024.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="target_features">Target-Specific Features and Limitations</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -1066,7 +1115,7 @@ Clang assumes directories as below;</p>
|
|||
<li><tt>C:/mingw/lib/gcc/mingw32/4.[3-5].0/include/c++</tt></li>
|
||||
</ul>
|
||||
|
||||
<p>On MSYS, a few tests might fail. It is due to <a href="http://llvm.org/bugs/show_bug.cgi?id=8520">Bug 8520</a> and is fixed in <a href="http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20110314/118106.html">LLVM's r127724</a>.</p>
|
||||
<p>On MSYS, a few tests might fail.</p>
|
||||
|
||||
<h5>MinGW-w64</h5>
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ OUTPUT_DIRECTORY = @abs_builddir@/doxygen
|
|||
# source files, where putting all generated files in the same directory would
|
||||
# otherwise cause performance problems for the file system.
|
||||
|
||||
CREATE_SUBDIRS = YES
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ for include files.
|
|||
=item B<-nostdlibinc>
|
||||
|
||||
Do not search the standard system directories for include files, but do search
|
||||
compiler builting include directories.
|
||||
compiler builtin include directories.
|
||||
|
||||
=item B<-nobuiltininc>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,7 @@
|
|||
if(NOT CLANG_BUILD_EXAMPLES)
|
||||
set(EXCLUDE_FROM_ALL ON)
|
||||
endif()
|
||||
|
||||
add_subdirectory(analyzer-plugin)
|
||||
add_subdirectory(clang-interpreter)
|
||||
add_subdirectory(PrintFunctionNames)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
CLANG_LEVEL := ..
|
||||
|
||||
PARALLEL_DIRS := clang-interpreter PrintFunctionNames
|
||||
PARALLEL_DIRS := analyzer-plugin clang-interpreter PrintFunctionNames
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ namespace {
|
|||
|
||||
class PrintFunctionsConsumer : public ASTConsumer {
|
||||
public:
|
||||
virtual void HandleTopLevelDecl(DeclGroupRef DG) {
|
||||
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
|
||||
for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
|
||||
const Decl *D = *i;
|
||||
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
|
||||
llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ Once the plugin is built, you can run it using:
|
|||
--
|
||||
Linux:
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
|
||||
|
||||
Mac:
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
|
||||
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ set( LLVM_USED_LIBS
|
|||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(SampleAnalyzerPlugin SampleAnalyzerPlugin)
|
||||
add_clang_library(SampleAnalyzerPlugin MainCallChecker.cpp)
|
||||
|
||||
set_target_properties(SampleAnalyzerPlugin
|
||||
PROPERTIES
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ using namespace ento;
|
|||
|
||||
namespace {
|
||||
class MainCallChecker : public Checker < check::PreStmt<CallExpr> > {
|
||||
mutable llvm::OwningPtr<BugType> BT;
|
||||
mutable OwningPtr<BugType> BT;
|
||||
|
||||
public:
|
||||
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
|
||||
|
|
@ -16,9 +16,10 @@ public:
|
|||
} // end anonymous namespace
|
||||
|
||||
void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
|
||||
const ProgramState *state = C.getState();
|
||||
const ProgramStateRef state = C.getState();
|
||||
const LocationContext *LC = C.getLocationContext();
|
||||
const Expr *Callee = CE->getCallee();
|
||||
const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
|
||||
const FunctionDecl *FD = state->getSVal(Callee, LC).getAsFunctionDecl();
|
||||
|
||||
if (!FD)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ CLANG_LEVEL := ../..
|
|||
LIBRARYNAME = SampleAnalyzerPlugin
|
||||
|
||||
LINK_LIBS_IN_SHARED = 0
|
||||
SHARED_LIBRARY = 1
|
||||
LOADABLE_MODULE = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
bitwriter
|
||||
codegen
|
||||
ipo
|
||||
linker
|
||||
selectiondag
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@ NO_INSTALL = 1
|
|||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
selectiondag asmparser instrumentation
|
||||
linker selectiondag asmparser instrumentation
|
||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
||||
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
|
||||
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
|
||||
clangAnalysis.a clangRewrite.a clangAST.a clangLex.a clangBasic.a
|
||||
clangAnalysis.a clangRewrite.a \
|
||||
clangEdit.a clangAST.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
|
|
@ -48,7 +46,7 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
|
|||
llvm::InitializeNativeTarget();
|
||||
|
||||
std::string Error;
|
||||
llvm::OwningPtr<llvm::ExecutionEngine> EE(
|
||||
OwningPtr<llvm::ExecutionEngine> EE(
|
||||
llvm::ExecutionEngine::createJIT(Mod, &Error));
|
||||
if (!EE) {
|
||||
llvm::errs() << "unable to make execution engine: " << Error << "\n";
|
||||
|
|
@ -74,9 +72,9 @@ int main(int argc, const char **argv, char * const *envp) {
|
|||
TextDiagnosticPrinter *DiagClient =
|
||||
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
|
||||
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
DiagnosticsEngine Diags(DiagID, DiagClient);
|
||||
Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
|
||||
Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
|
||||
"a.out", /*IsProduction=*/false, Diags);
|
||||
TheDriver.setTitle("clang interpreter");
|
||||
|
||||
|
|
@ -85,7 +83,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
|||
// (basically, exactly one input, and the operation mode is hard wired).
|
||||
llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
|
||||
Args.push_back("-fsyntax-only");
|
||||
llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
|
||||
OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
|
||||
if (!C)
|
||||
return 0;
|
||||
|
||||
|
|
@ -95,7 +93,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
|||
// failed. Extract that job from the compilation.
|
||||
const driver::JobList &Jobs = C->getJobs();
|
||||
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
|
||||
llvm::SmallString<256> Msg;
|
||||
SmallString<256> Msg;
|
||||
llvm::raw_svector_ostream OS(Msg);
|
||||
C->PrintJob(OS, C->getJobs(), "; ", true);
|
||||
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
|
||||
|
|
@ -110,7 +108,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
|||
|
||||
// Initialize a compiler invocation object from the clang (-cc1) arguments.
|
||||
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
||||
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
|
||||
OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
|
||||
CompilerInvocation::CreateFromArgs(*CI,
|
||||
const_cast<const char **>(CCArgs.data()),
|
||||
const_cast<const char **>(CCArgs.data()) +
|
||||
|
|
@ -142,7 +140,7 @@ int main(int argc, const char **argv, char * const *envp) {
|
|||
CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
|
||||
|
||||
// Create and execute the frontend to generate an LLVM bitcode module.
|
||||
llvm::OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
|
||||
OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
|
||||
if (!Clang.ExecuteAction(*Act))
|
||||
return 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
set(LLVM_USED_LIBS
|
||||
clangIndex
|
||||
clangFrontend
|
||||
clangDriver
|
||||
clangSema
|
||||
clangAnalysis
|
||||
clangSerialization
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangRewrite
|
||||
clangAST
|
||||
clangParse
|
||||
clangLex
|
||||
clangBasic)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS
|
||||
bitreader
|
||||
mc
|
||||
core
|
||||
)
|
||||
|
||||
add_clang_executable(clang-wpa
|
||||
clang-wpa.cpp
|
||||
)
|
||||
add_dependencies(clang-wpa clang-headers)
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
##===- examples/wpa/Makefile -------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ../..
|
||||
|
||||
TOOLNAME = clang-wpa
|
||||
NO_INSTALL = 1
|
||||
|
||||
# No plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
LINK_COMPONENTS := asmparser bitreader mc core
|
||||
USEDLIBS = clangStaticAnalyzerFrontend.a \
|
||||
clangStaticAnalyzerCheckers.a \
|
||||
clangStaticAnalyzerCore.a \
|
||||
clangIndex.a clangFrontend.a clangDriver.a \
|
||||
clangParse.a clangSema.a clangAnalysis.a clangSerialization.a \
|
||||
clangAST.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
//===--- clang-wpa.cpp - clang whole program analyzer ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tool reads a sequence of precompiled AST files, and do various
|
||||
// cross translation unit analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Index/CallGraph.h"
|
||||
#include "clang/Index/Indexer.h"
|
||||
#include "clang/Index/TranslationUnit.h"
|
||||
#include "clang/Index/DeclReferenceMap.h"
|
||||
#include "clang/Index/SelectorMap.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
using namespace idx;
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
ViewCallGraph("view-call-graph", llvm::cl::desc("Display the call graph."));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
AnalyzeFunction("analyze-function",
|
||||
llvm::cl::desc("Specify the entry function."));
|
||||
|
||||
namespace {
|
||||
// A thin wrapper over ASTUnit implementing the TranslationUnit interface.
|
||||
class ASTUnitTU : public TranslationUnit {
|
||||
ASTUnit *AST;
|
||||
DeclReferenceMap DeclRefMap;
|
||||
SelectorMap SelMap;
|
||||
|
||||
public:
|
||||
ASTUnitTU(ASTUnit *ast)
|
||||
: AST(ast), DeclRefMap(AST->getASTContext()), SelMap(AST->getASTContext()) {
|
||||
}
|
||||
|
||||
virtual ASTContext &getASTContext() {
|
||||
return AST->getASTContext();
|
||||
}
|
||||
|
||||
virtual Preprocessor &getPreprocessor() {
|
||||
return AST->getPreprocessor();
|
||||
}
|
||||
|
||||
virtual Diagnostic &getDiagnostic() {
|
||||
return AST->getDiagnostics();
|
||||
}
|
||||
|
||||
virtual DeclReferenceMap &getDeclReferenceMap() {
|
||||
return DeclRefMap;
|
||||
}
|
||||
|
||||
virtual SelectorMap &getSelectorMap() {
|
||||
return SelMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
|
||||
std::vector<ASTUnit*> ASTUnits;
|
||||
|
||||
Program Prog;
|
||||
Indexer Idxer(Prog);
|
||||
|
||||
if (InputFilenames.empty())
|
||||
return 0;
|
||||
|
||||
DiagnosticOptions DiagOpts;
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic> Diags
|
||||
= CompilerInstance::createDiagnostics(DiagOpts, argc, argv);
|
||||
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
||||
const std::string &InFile = InputFilenames[i];
|
||||
llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromASTFile(InFile, Diags,
|
||||
FileSystemOptions(),
|
||||
false, 0, 0, true));
|
||||
if (!AST)
|
||||
return 1;
|
||||
|
||||
ASTUnits.push_back(AST.take());
|
||||
}
|
||||
|
||||
if (ViewCallGraph) {
|
||||
llvm::OwningPtr<CallGraph> CG;
|
||||
CG.reset(new CallGraph(Prog));
|
||||
|
||||
for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
|
||||
CG->addTU(ASTUnits[i]->getASTContext());
|
||||
|
||||
CG->ViewCallGraph();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (AnalyzeFunction.empty())
|
||||
return 0;
|
||||
|
||||
// Feed all ASTUnits to the Indexer.
|
||||
for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i) {
|
||||
ASTUnitTU *TU = new ASTUnitTU(ASTUnits[i]);
|
||||
Idxer.IndexAST(TU);
|
||||
}
|
||||
|
||||
Entity Ent = Entity::get(AnalyzeFunction, Prog);
|
||||
FunctionDecl *FD;
|
||||
TranslationUnit *TU;
|
||||
llvm::tie(FD, TU) = Idxer.getDefinitionFor(Ent);
|
||||
|
||||
if (!FD)
|
||||
return 0;
|
||||
|
||||
// Create an analysis engine.
|
||||
Preprocessor &PP = TU->getPreprocessor();
|
||||
|
||||
AnalyzerOptions Opts;
|
||||
|
||||
// Hard code options and checkers for now.
|
||||
|
||||
Opts.MaxNodes = 300000;
|
||||
Opts.MaxLoop = 3;
|
||||
Opts.InlineCall = true;
|
||||
Opts.CFGAddImplicitDtors = true;
|
||||
Opts.EagerlyTrimEGraph = true;
|
||||
|
||||
Opts.CheckersControlList.push_back(std::make_pair("core", true));
|
||||
if (PP.getTargetInfo().getTriple().getOS() != llvm::Triple::Win32)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("unix", true));
|
||||
if (PP.getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("macosx", true));
|
||||
|
||||
// Checks to perform for Objective-C/Objective-C++.
|
||||
if (PP.getLangOptions().ObjC1)
|
||||
Opts.CheckersControlList.push_back(std::make_pair("cocoa", true));
|
||||
|
||||
llvm::OwningPtr<ento::CheckerManager> checkerMgr;
|
||||
checkerMgr.reset(ento::registerCheckers(Opts, PP.getLangOptions(),
|
||||
PP.getDiagnostics()));
|
||||
|
||||
using namespace clang::ento;
|
||||
AnalysisManager AMgr(TU->getASTContext(), PP.getDiagnostics(),
|
||||
PP.getLangOptions(), /* PathDiagnostic */ 0,
|
||||
CreateRegionStoreManager,
|
||||
CreateRangeConstraintManager, checkerMgr.get(), &Idxer,
|
||||
Opts.MaxNodes, Opts.MaxLoop,
|
||||
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
|
||||
Opts.PurgeDead, Opts.EagerlyAssume,
|
||||
Opts.TrimGraph, Opts.InlineCall,
|
||||
Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
|
||||
Opts.CFGAddInitializers,
|
||||
Opts.EagerlyTrimEGraph);
|
||||
|
||||
TransferFuncs* TF = MakeCFRefCountTF(AMgr.getASTContext(), /*GC*/false,
|
||||
AMgr.getLangOptions());
|
||||
ExprEngine Eng(AMgr, TF);
|
||||
|
||||
Eng.ExecuteWorkList(AMgr.getStackFrame(FD, TU), AMgr.getMaxNodes());
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -3,21 +3,23 @@ DIRS :=
|
|||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
IntIncludeDir = $(DESTDIR)$(PROJ_internal_prefix)/include
|
||||
|
||||
install-local::
|
||||
$(Echo) Installing Clang C API include files
|
||||
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
|
||||
$(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang-c" ; then \
|
||||
cd $(PROJ_SRC_ROOT)/tools/clang/include && \
|
||||
$(Verb) $(MKDIR) $(IntIncludeDir)
|
||||
$(Verb) if test -d "$(PROJ_SRC_DIR)" ; then \
|
||||
cd $(PROJ_SRC_DIR)/.. && \
|
||||
for hdr in `find clang-c -type f '!' '(' -name '*~' \
|
||||
-o -name '.#*' -o -name '*.in' -o -name '*.txt' \
|
||||
-o -name 'Makefile' -o -name '*.td' ')' -print \
|
||||
| grep -v CVS | grep -v .svn | grep -v .dir` ; do \
|
||||
instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
|
||||
instdir=`dirname "$(IntIncludeDir)/$$hdr"` ; \
|
||||
if test \! -d "$$instdir" ; then \
|
||||
$(EchoCmd) Making install directory $$instdir ; \
|
||||
$(MKDIR) $$instdir ;\
|
||||
fi ; \
|
||||
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
|
||||
$(DataInstall) $$hdr $(IntIncludeDir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
|
|
@ -25,7 +27,12 @@ ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
|||
cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
|
||||
for hdr in `find clang-c -type f '!' '(' -name 'Makefile' ')' -print \
|
||||
| grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
|
||||
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
|
||||
instdir=`dirname "$(IntIncludeDir)/$$hdr"` ; \
|
||||
if test \! -d "$$instdir" ; then \
|
||||
$(EchoCmd) Making install directory $$instdir ; \
|
||||
$(MKDIR) $$instdir ;\
|
||||
fi ; \
|
||||
$(DataInstall) $$hdr $(IntIncludeDir)/$$hdr ; \
|
||||
done ; \
|
||||
fi
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace arcmt {
|
|||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool checkForManualIssues(CompilerInvocation &CI,
|
||||
StringRef Filename, InputKind Kind,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
bool emitPremigrationARCErrors = false,
|
||||
StringRef plistOut = StringRef());
|
||||
|
|
@ -47,7 +47,7 @@ bool checkForManualIssues(CompilerInvocation &CI,
|
|||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool applyTransformations(CompilerInvocation &origCI,
|
||||
StringRef Filename, InputKind Kind,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
/// \brief Applies automatic modifications and produces temporary files
|
||||
|
|
@ -62,7 +62,7 @@ bool applyTransformations(CompilerInvocation &origCI,
|
|||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
StringRef Filename, InputKind Kind,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
|
|
@ -76,9 +76,19 @@ bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
|
|||
StringRef outputDir,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
/// \brief Get the set of file remappings from a list of files with remapping
|
||||
/// info.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool getFileRemappingsFromFileList(
|
||||
std::vector<std::pair<std::string,std::string> > &remap,
|
||||
ArrayRef<StringRef> remapFiles,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
typedef void (*TransformFn)(MigrationPass &pass);
|
||||
|
||||
std::vector<TransformFn> getAllTransformations();
|
||||
std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode,
|
||||
bool NoFinalizeRemoval);
|
||||
|
||||
class MigrationProcess {
|
||||
CompilerInvocation OrigCI;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
|
||||
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/ARCMigrate/FileRemapper.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
namespace clang {
|
||||
|
|
@ -32,6 +33,14 @@ public:
|
|||
ModifyAction(FrontendAction *WrappedAction);
|
||||
};
|
||||
|
||||
class MigrateSourceAction : public ASTFrontendAction {
|
||||
FileRemapper Remapper;
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile);
|
||||
};
|
||||
|
||||
class MigrateAction : public WrapperFrontendAction {
|
||||
std::string MigrateDir;
|
||||
std::string PlistOut;
|
||||
|
|
@ -45,6 +54,23 @@ public:
|
|||
bool emitPremigrationARCErrors);
|
||||
};
|
||||
|
||||
/// \brief Migrates to modern ObjC syntax.
|
||||
class ObjCMigrateAction : public WrapperFrontendAction {
|
||||
std::string MigrateDir;
|
||||
bool MigrateLiterals;
|
||||
bool MigrateSubscripting;
|
||||
FileRemapper Remapper;
|
||||
CompilerInstance *CompInst;
|
||||
public:
|
||||
ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
||||
bool migrateLiterals,
|
||||
bool migrateSubscripting);
|
||||
|
||||
protected:
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ namespace clang {
|
|||
class FileManager;
|
||||
class FileEntry;
|
||||
class DiagnosticsEngine;
|
||||
class CompilerInvocation;
|
||||
class PreprocessorOptions;
|
||||
|
||||
namespace arcmt {
|
||||
|
||||
class FileRemapper {
|
||||
// FIXME: Reuse the same FileManager for multiple ASTContexts.
|
||||
llvm::OwningPtr<FileManager> FileMgr;
|
||||
OwningPtr<FileManager> FileMgr;
|
||||
|
||||
typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target;
|
||||
typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy;
|
||||
|
|
@ -44,7 +44,10 @@ public:
|
|||
|
||||
bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
|
||||
bool ignoreIfFilesChanged);
|
||||
bool initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
|
||||
bool ignoreIfFilesChanged);
|
||||
bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag);
|
||||
bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag);
|
||||
|
||||
bool overwriteOriginal(DiagnosticsEngine &Diag,
|
||||
StringRef outputDir = StringRef());
|
||||
|
|
@ -52,9 +55,9 @@ public:
|
|||
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
|
||||
void remap(StringRef filePath, StringRef newPath);
|
||||
|
||||
void applyMappings(CompilerInvocation &CI) const;
|
||||
void applyMappings(PreprocessorOptions &PPOpts) const;
|
||||
|
||||
void transferMappingsAndClear(CompilerInvocation &CI);
|
||||
void transferMappingsAndClear(PreprocessorOptions &PPOpts);
|
||||
|
||||
void clear(StringRef outputDir = StringRef());
|
||||
|
||||
|
|
|
|||
|
|
@ -17,14 +17,24 @@
|
|||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace clang {
|
||||
class AddrLabelExpr;
|
||||
class ASTContext;
|
||||
class CharUnits;
|
||||
class DiagnosticBuilder;
|
||||
class Expr;
|
||||
class FieldDecl;
|
||||
class Decl;
|
||||
class ValueDecl;
|
||||
class CXXRecordDecl;
|
||||
class QualType;
|
||||
|
||||
/// APValue - This class implements a discriminated union of [uninitialized]
|
||||
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset].
|
||||
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
|
||||
/// [Vector: N * APValue], [Array: N * APValue]
|
||||
class APValue {
|
||||
typedef llvm::APSInt APSInt;
|
||||
typedef llvm::APFloat APFloat;
|
||||
|
|
@ -36,8 +46,25 @@ public:
|
|||
ComplexInt,
|
||||
ComplexFloat,
|
||||
LValue,
|
||||
Vector
|
||||
Vector,
|
||||
Array,
|
||||
Struct,
|
||||
Union,
|
||||
MemberPointer,
|
||||
AddrLabelDiff
|
||||
};
|
||||
typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase;
|
||||
typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType;
|
||||
union LValuePathEntry {
|
||||
/// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item
|
||||
/// in the path. An opaque value of type BaseOrMemberType.
|
||||
void *BaseOrMember;
|
||||
/// ArrayIndex - The array index of the next item in the path.
|
||||
uint64_t ArrayIndex;
|
||||
};
|
||||
struct NoLValuePath {};
|
||||
struct UninitArray {};
|
||||
struct UninitStruct {};
|
||||
private:
|
||||
ValueKind Kind;
|
||||
|
||||
|
|
@ -49,13 +76,37 @@ private:
|
|||
APFloat Real, Imag;
|
||||
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
|
||||
};
|
||||
|
||||
struct LV;
|
||||
struct Vec {
|
||||
APValue *Elts;
|
||||
unsigned NumElts;
|
||||
Vec() : Elts(0), NumElts(0) {}
|
||||
~Vec() { delete[] Elts; }
|
||||
};
|
||||
struct Arr {
|
||||
APValue *Elts;
|
||||
unsigned NumElts, ArrSize;
|
||||
Arr(unsigned NumElts, unsigned ArrSize);
|
||||
~Arr();
|
||||
};
|
||||
struct StructData {
|
||||
APValue *Elts;
|
||||
unsigned NumBases;
|
||||
unsigned NumFields;
|
||||
StructData(unsigned NumBases, unsigned NumFields);
|
||||
~StructData();
|
||||
};
|
||||
struct UnionData {
|
||||
const FieldDecl *Field;
|
||||
APValue *Value;
|
||||
UnionData();
|
||||
~UnionData();
|
||||
};
|
||||
struct AddrLabelDiffData {
|
||||
const AddrLabelExpr* LHSExpr;
|
||||
const AddrLabelExpr* RHSExpr;
|
||||
};
|
||||
struct MemberPointerData;
|
||||
|
||||
enum {
|
||||
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
|
||||
|
|
@ -84,18 +135,42 @@ public:
|
|||
APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) {
|
||||
MakeComplexFloat(); setComplexFloat(R, I);
|
||||
}
|
||||
APValue(const APValue &RHS) : Kind(Uninitialized) {
|
||||
*this = RHS;
|
||||
APValue(const APValue &RHS);
|
||||
APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex)
|
||||
: Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O, N, CallIndex);
|
||||
}
|
||||
APValue(const Expr* B, const CharUnits &O) : Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O);
|
||||
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
|
||||
bool OnePastTheEnd, unsigned CallIndex)
|
||||
: Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex);
|
||||
}
|
||||
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
|
||||
MakeArray(InitElts, Size);
|
||||
}
|
||||
APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) {
|
||||
MakeStruct(B, M);
|
||||
}
|
||||
explicit APValue(const FieldDecl *D, const APValue &V = APValue())
|
||||
: Kind(Uninitialized) {
|
||||
MakeUnion(); setUnion(D, V);
|
||||
}
|
||||
APValue(const ValueDecl *Member, bool IsDerivedMember,
|
||||
ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) {
|
||||
MakeMemberPointer(Member, IsDerivedMember, Path);
|
||||
}
|
||||
APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr)
|
||||
: Kind(Uninitialized) {
|
||||
MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr);
|
||||
}
|
||||
APValue(const Expr* B);
|
||||
|
||||
~APValue() {
|
||||
MakeUninit();
|
||||
}
|
||||
|
||||
/// \brief Swaps the contents of this and the given APValue.
|
||||
void swap(APValue &RHS);
|
||||
|
||||
ValueKind getKind() const { return Kind; }
|
||||
bool isUninit() const { return Kind == Uninitialized; }
|
||||
bool isInt() const { return Kind == Int; }
|
||||
|
|
@ -104,9 +179,17 @@ public:
|
|||
bool isComplexFloat() const { return Kind == ComplexFloat; }
|
||||
bool isLValue() const { return Kind == LValue; }
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
bool isArray() const { return Kind == Array; }
|
||||
bool isStruct() const { return Kind == Struct; }
|
||||
bool isUnion() const { return Kind == Union; }
|
||||
bool isMemberPointer() const { return Kind == MemberPointer; }
|
||||
bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; }
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
void dump(raw_ostream &OS) const;
|
||||
|
||||
void printPretty(raw_ostream &OS, ASTContext &Ctx, QualType Ty) const;
|
||||
std::string getAsString(ASTContext &Ctx, QualType Ty) const;
|
||||
|
||||
APSInt &getInt() {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
|
|
@ -124,19 +207,6 @@ public:
|
|||
return const_cast<APValue*>(this)->getFloat();
|
||||
}
|
||||
|
||||
APValue &getVectorElt(unsigned i) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(char*)Data)->Elts[i];
|
||||
}
|
||||
const APValue &getVectorElt(unsigned i) const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((const Vec*)(const char*)Data)->Elts[i];
|
||||
}
|
||||
unsigned getVectorLength() const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((const Vec*)(const void *)Data)->NumElts;
|
||||
}
|
||||
|
||||
APSInt &getComplexIntReal() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(char*)Data)->Real;
|
||||
|
|
@ -169,8 +239,104 @@ public:
|
|||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
}
|
||||
|
||||
const Expr* getLValueBase() const;
|
||||
CharUnits getLValueOffset() const;
|
||||
const LValueBase getLValueBase() const;
|
||||
CharUnits &getLValueOffset();
|
||||
const CharUnits &getLValueOffset() const {
|
||||
return const_cast<APValue*>(this)->getLValueOffset();
|
||||
}
|
||||
bool isLValueOnePastTheEnd() const;
|
||||
bool hasLValuePath() const;
|
||||
ArrayRef<LValuePathEntry> getLValuePath() const;
|
||||
unsigned getLValueCallIndex() const;
|
||||
|
||||
APValue &getVectorElt(unsigned I) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
assert(I < getVectorLength() && "Index out of range");
|
||||
return ((Vec*)(char*)Data)->Elts[I];
|
||||
}
|
||||
const APValue &getVectorElt(unsigned I) const {
|
||||
return const_cast<APValue*>(this)->getVectorElt(I);
|
||||
}
|
||||
unsigned getVectorLength() const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((const Vec*)(const void *)Data)->NumElts;
|
||||
}
|
||||
|
||||
APValue &getArrayInitializedElt(unsigned I) {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
assert(I < getArrayInitializedElts() && "Index out of range");
|
||||
return ((Arr*)(char*)Data)->Elts[I];
|
||||
}
|
||||
const APValue &getArrayInitializedElt(unsigned I) const {
|
||||
return const_cast<APValue*>(this)->getArrayInitializedElt(I);
|
||||
}
|
||||
bool hasArrayFiller() const {
|
||||
return getArrayInitializedElts() != getArraySize();
|
||||
}
|
||||
APValue &getArrayFiller() {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
assert(hasArrayFiller() && "No array filler");
|
||||
return ((Arr*)(char*)Data)->Elts[getArrayInitializedElts()];
|
||||
}
|
||||
const APValue &getArrayFiller() const {
|
||||
return const_cast<APValue*>(this)->getArrayFiller();
|
||||
}
|
||||
unsigned getArrayInitializedElts() const {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
return ((const Arr*)(const void *)Data)->NumElts;
|
||||
}
|
||||
unsigned getArraySize() const {
|
||||
assert(isArray() && "Invalid accessor");
|
||||
return ((const Arr*)(const void *)Data)->ArrSize;
|
||||
}
|
||||
|
||||
unsigned getStructNumBases() const {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((const StructData*)(const char*)Data)->NumBases;
|
||||
}
|
||||
unsigned getStructNumFields() const {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((const StructData*)(const char*)Data)->NumFields;
|
||||
}
|
||||
APValue &getStructBase(unsigned i) {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((StructData*)(char*)Data)->Elts[i];
|
||||
}
|
||||
APValue &getStructField(unsigned i) {
|
||||
assert(isStruct() && "Invalid accessor");
|
||||
return ((StructData*)(char*)Data)->Elts[getStructNumBases() + i];
|
||||
}
|
||||
const APValue &getStructBase(unsigned i) const {
|
||||
return const_cast<APValue*>(this)->getStructBase(i);
|
||||
}
|
||||
const APValue &getStructField(unsigned i) const {
|
||||
return const_cast<APValue*>(this)->getStructField(i);
|
||||
}
|
||||
|
||||
const FieldDecl *getUnionField() const {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
return ((const UnionData*)(const char*)Data)->Field;
|
||||
}
|
||||
APValue &getUnionValue() {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
return *((UnionData*)(char*)Data)->Value;
|
||||
}
|
||||
const APValue &getUnionValue() const {
|
||||
return const_cast<APValue*>(this)->getUnionValue();
|
||||
}
|
||||
|
||||
const ValueDecl *getMemberPointerDecl() const;
|
||||
bool isMemberPointerToDerivedMember() const;
|
||||
ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const;
|
||||
|
||||
const AddrLabelExpr* getAddrLabelDiffLHS() const {
|
||||
assert(isAddrLabelDiff() && "Invalid accessor");
|
||||
return ((const AddrLabelDiffData*)(const char*)Data)->LHSExpr;
|
||||
}
|
||||
const AddrLabelExpr* getAddrLabelDiffRHS() const {
|
||||
assert(isAddrLabelDiff() && "Invalid accessor");
|
||||
return ((const AddrLabelDiffData*)(const char*)Data)->RHSExpr;
|
||||
}
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
|
|
@ -201,12 +367,34 @@ public:
|
|||
((ComplexAPFloat*)(char*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(char*)Data)->Imag = I;
|
||||
}
|
||||
void setLValue(const Expr *B, const CharUnits &O);
|
||||
void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
|
||||
unsigned CallIndex);
|
||||
void setLValue(LValueBase B, const CharUnits &O,
|
||||
ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
|
||||
unsigned CallIndex);
|
||||
void setUnion(const FieldDecl *Field, const APValue &Value) {
|
||||
assert(isUnion() && "Invalid accessor");
|
||||
((UnionData*)(char*)Data)->Field = Field;
|
||||
*((UnionData*)(char*)Data)->Value = Value;
|
||||
}
|
||||
void setAddrLabelDiff(const AddrLabelExpr* LHSExpr,
|
||||
const AddrLabelExpr* RHSExpr) {
|
||||
((AddrLabelDiffData*)(char*)Data)->LHSExpr = LHSExpr;
|
||||
((AddrLabelDiffData*)(char*)Data)->RHSExpr = RHSExpr;
|
||||
}
|
||||
|
||||
const APValue &operator=(const APValue &RHS);
|
||||
/// Assign by swapping from a copy of the RHS.
|
||||
APValue &operator=(APValue RHS) {
|
||||
swap(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void MakeUninit();
|
||||
void DestroyDataAndMakeUninit();
|
||||
void MakeUninit() {
|
||||
if (Kind != Uninitialized)
|
||||
DestroyDataAndMakeUninit();
|
||||
}
|
||||
void MakeInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)Data) APSInt(1);
|
||||
|
|
@ -233,17 +421,26 @@ private:
|
|||
Kind = ComplexFloat;
|
||||
}
|
||||
void MakeLValue();
|
||||
void MakeArray(unsigned InitElts, unsigned Size);
|
||||
void MakeStruct(unsigned B, unsigned M) {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) StructData(B, M);
|
||||
Kind = Struct;
|
||||
}
|
||||
void MakeUnion() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) UnionData();
|
||||
Kind = Union;
|
||||
}
|
||||
void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
|
||||
ArrayRef<const CXXRecordDecl*> Path);
|
||||
void MakeAddrLabelDiff() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) AddrLabelDiffData();
|
||||
Kind = AddrLabelDiff;
|
||||
}
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) {
|
||||
V.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
// Writes a concise representation of V to DB, in a single << operation.
|
||||
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const APValue &V);
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ namespace clang {
|
|||
class SemaConsumer; // layering violation required for safe SemaConsumer
|
||||
class TagDecl;
|
||||
class VarDecl;
|
||||
class FunctionDecl;
|
||||
|
||||
/// ASTConsumer - This is an abstract interface that should be implemented by
|
||||
/// clients that read ASTs. This abstraction layer allows the client to be
|
||||
|
|
@ -48,7 +49,9 @@ public:
|
|||
/// called by the parser to process every top-level Decl*. Note that D can be
|
||||
/// the head of a chain of Decls (e.g. for `int a, b` the chain will have two
|
||||
/// elements). Use Decl::getNextDeclarator() to walk the chain.
|
||||
virtual void HandleTopLevelDecl(DeclGroupRef D);
|
||||
///
|
||||
/// \returns true to continue parsing, or false to abort parsing.
|
||||
virtual bool HandleTopLevelDecl(DeclGroupRef D);
|
||||
|
||||
/// HandleInterestingDecl - Handle the specified interesting declaration. This
|
||||
/// is called by the AST reader when deserializing things that might interest
|
||||
|
|
@ -65,6 +68,17 @@ public:
|
|||
/// can be defined in declspecs).
|
||||
virtual void HandleTagDeclDefinition(TagDecl *D) {}
|
||||
|
||||
/// \brief Invoked when a function is implicitly instantiated.
|
||||
/// Note that at this point point it does not have a body, its body is
|
||||
/// instantiated at the end of the translation unit and passed to
|
||||
/// HandleTopLevelDecl.
|
||||
virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {}
|
||||
|
||||
/// \brief Handle the specified top-level declaration that occurred inside
|
||||
/// and ObjC container.
|
||||
/// The default implementation ignored them.
|
||||
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
|
||||
|
||||
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
|
||||
/// unit to notify the consumer that the given tentative definition should be
|
||||
/// completed.
|
||||
|
|
@ -76,6 +90,10 @@ public:
|
|||
/// modified by the introduction of an implicit zero initializer.
|
||||
virtual void CompleteTentativeDefinition(VarDecl *D) {}
|
||||
|
||||
/// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this
|
||||
// variable has been instantiated.
|
||||
virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *D) {}
|
||||
|
||||
/// \brief Callback involved at the end of a translation unit to
|
||||
/// notify the consumer that a vtable for the given C++ class is
|
||||
/// required.
|
||||
|
|
@ -94,7 +112,9 @@ public:
|
|||
|
||||
/// \brief If the consumer is interested in entities being deserialized from
|
||||
/// AST files, it should return a pointer to a ASTDeserializationListener here
|
||||
virtual ASTDeserializationListener *GetASTDeserializationListener() { return 0; }
|
||||
virtual ASTDeserializationListener *GetASTDeserializationListener() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// PrintStats - If desired, print any statistics.
|
||||
virtual void PrintStats() {}
|
||||
|
|
|
|||
|
|
@ -21,17 +21,18 @@
|
|||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/LambdaMangleContext.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/CanonicalType.h"
|
||||
#include "clang/AST/UsuallyTinyPtrVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -55,6 +56,7 @@ namespace clang {
|
|||
class CXXABI;
|
||||
// Decls
|
||||
class DeclContext;
|
||||
class CXXConversionDecl;
|
||||
class CXXMethodDecl;
|
||||
class CXXRecordDecl;
|
||||
class Decl;
|
||||
|
|
@ -80,7 +82,7 @@ namespace clang {
|
|||
|
||||
/// ASTContext - This class holds long-lived AST nodes (such as types and
|
||||
/// decls) that can be referred to throughout the semantic analysis of a file.
|
||||
class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
class ASTContext : public RefCountedBase<ASTContext> {
|
||||
ASTContext &this_() { return *this; }
|
||||
|
||||
mutable std::vector<Type*> Types;
|
||||
|
|
@ -145,6 +147,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
|||
mutable llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>
|
||||
ObjCLayouts;
|
||||
|
||||
/// TypeInfoMap - A cache from types to size and alignment information.
|
||||
typedef llvm::DenseMap<const Type*,
|
||||
std::pair<uint64_t, unsigned> > TypeInfoMap;
|
||||
mutable TypeInfoMap MemoizedTypeInfo;
|
||||
|
||||
/// KeyFunctions - A cache mapping from CXXRecordDecls to key functions.
|
||||
llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions;
|
||||
|
||||
|
|
@ -202,12 +209,12 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
|||
/// \brief The typedef for the predefined 'SEL' type.
|
||||
mutable TypedefDecl *ObjCSelDecl;
|
||||
|
||||
QualType ObjCProtoType;
|
||||
const RecordType *ProtoStructType;
|
||||
|
||||
/// \brief The typedef for the predefined 'Class' type.
|
||||
mutable TypedefDecl *ObjCClassDecl;
|
||||
|
||||
|
||||
/// \brief The typedef for the predefined 'Protocol' class in Objective-C.
|
||||
mutable ObjCInterfaceDecl *ObjCProtocolClassDecl;
|
||||
|
||||
// Typedefs which may be provided defining the structure of Objective-C
|
||||
// pseudo-builtins
|
||||
QualType ObjCIdRedefinitionType;
|
||||
|
|
@ -216,6 +223,8 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
|||
|
||||
QualType ObjCConstantStringType;
|
||||
mutable RecordDecl *CFConstantStringTypeDecl;
|
||||
|
||||
QualType ObjCNSStringType;
|
||||
|
||||
/// \brief The typedef declaration for the Objective-C "instancetype" type.
|
||||
TypedefDecl *ObjCInstanceTypeDecl;
|
||||
|
|
@ -229,6 +238,9 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
|||
/// \brief The type for the C sigjmp_buf type.
|
||||
TypeDecl *sigjmp_bufDecl;
|
||||
|
||||
/// \brief The type for the C ucontext_t type.
|
||||
TypeDecl *ucontext_tDecl;
|
||||
|
||||
/// \brief Type for the Block descriptor for Blocks CodeGen.
|
||||
///
|
||||
/// Since this is only used for generation of debug info, it is not
|
||||
|
|
@ -315,15 +327,22 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
|||
/// Since most C++ member functions aren't virtual and therefore
|
||||
/// don't override anything, we store the overridden functions in
|
||||
/// this map on the side rather than within the CXXMethodDecl structure.
|
||||
typedef UsuallyTinyPtrVector<const CXXMethodDecl> CXXMethodVector;
|
||||
typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
|
||||
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
|
||||
|
||||
/// \brief Mapping from each declaration context to its corresponding lambda
|
||||
/// mangling context.
|
||||
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
|
||||
|
||||
/// \brief Mapping 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;
|
||||
|
||||
ImportDecl *FirstLocalImport;
|
||||
ImportDecl *LastLocalImport;
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
|
||||
/// SourceMgr - The associated SourceManager object.
|
||||
|
|
@ -343,7 +362,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
|||
PartialDiagnostic::StorageAllocator DiagAllocator;
|
||||
|
||||
/// \brief The current C++ ABI.
|
||||
llvm::OwningPtr<CXXABI> ABI;
|
||||
OwningPtr<CXXABI> ABI;
|
||||
CXXABI *createCXXABI(const TargetInfo &T);
|
||||
|
||||
/// \brief The logical -> physical address space map.
|
||||
|
|
@ -352,7 +371,8 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
|||
friend class ASTDeclReader;
|
||||
friend class ASTReader;
|
||||
friend class ASTWriter;
|
||||
|
||||
friend class CXXRecordDecl;
|
||||
|
||||
const TargetInfo *Target;
|
||||
clang::PrintingPolicy PrintingPolicy;
|
||||
|
||||
|
|
@ -361,7 +381,7 @@ public:
|
|||
SelectorTable &Selectors;
|
||||
Builtin::Context &BuiltinInfo;
|
||||
mutable DeclarationNameTable DeclarationNames;
|
||||
llvm::OwningPtr<ExternalASTSource> ExternalSource;
|
||||
OwningPtr<ExternalASTSource> ExternalSource;
|
||||
ASTMutationListener *Listener;
|
||||
|
||||
clang::PrintingPolicy getPrintingPolicy() const { return PrintingPolicy; }
|
||||
|
|
@ -391,7 +411,7 @@ public:
|
|||
|
||||
const TargetInfo &getTargetInfo() const { return *Target; }
|
||||
|
||||
const LangOptions& getLangOptions() const { return LangOpts; }
|
||||
const LangOptions& getLangOpts() const { return LangOpts; }
|
||||
|
||||
DiagnosticsEngine &getDiagnostics() const;
|
||||
|
||||
|
|
@ -465,7 +485,7 @@ public:
|
|||
const FieldDecl *LastFD) const;
|
||||
|
||||
// Access to the set of methods overridden by the given C++ method.
|
||||
typedef CXXMethodVector::iterator overridden_cxx_method_iterator;
|
||||
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
|
||||
overridden_cxx_method_iterator
|
||||
overridden_methods_begin(const CXXMethodDecl *Method) const;
|
||||
|
||||
|
|
@ -479,6 +499,56 @@ public:
|
|||
void addOverriddenMethod(const CXXMethodDecl *Method,
|
||||
const CXXMethodDecl *Overridden);
|
||||
|
||||
/// \brief Notify the AST context that a new import declaration has been
|
||||
/// parsed or implicitly created within this translation unit.
|
||||
void addedLocalImportDecl(ImportDecl *Import);
|
||||
|
||||
static ImportDecl *getNextLocalImport(ImportDecl *Import) {
|
||||
return Import->NextLocalImport;
|
||||
}
|
||||
|
||||
/// \brief Iterator that visits import declarations.
|
||||
class import_iterator {
|
||||
ImportDecl *Import;
|
||||
|
||||
public:
|
||||
typedef ImportDecl *value_type;
|
||||
typedef ImportDecl *reference;
|
||||
typedef ImportDecl *pointer;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
import_iterator() : Import() { }
|
||||
explicit import_iterator(ImportDecl *Import) : Import(Import) { }
|
||||
|
||||
reference operator*() const { return Import; }
|
||||
pointer operator->() const { return Import; }
|
||||
|
||||
import_iterator &operator++() {
|
||||
Import = ASTContext::getNextLocalImport(Import);
|
||||
return *this;
|
||||
}
|
||||
|
||||
import_iterator operator++(int) {
|
||||
import_iterator Other(*this);
|
||||
++(*this);
|
||||
return Other;
|
||||
}
|
||||
|
||||
friend bool operator==(import_iterator X, import_iterator Y) {
|
||||
return X.Import == Y.Import;
|
||||
}
|
||||
|
||||
friend bool operator!=(import_iterator X, import_iterator Y) {
|
||||
return X.Import != Y.Import;
|
||||
}
|
||||
};
|
||||
|
||||
import_iterator local_import_begin() const {
|
||||
return import_iterator(FirstLocalImport);
|
||||
}
|
||||
import_iterator local_import_end() const { return import_iterator(); }
|
||||
|
||||
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
|
||||
|
||||
|
||||
|
|
@ -497,7 +567,9 @@ public:
|
|||
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
CanQualType VoidPtrTy, NullPtrTy;
|
||||
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
|
||||
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
|
||||
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
|
||||
CanQualType ObjCBuiltinBoolTy;
|
||||
|
||||
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
|
||||
mutable QualType AutoDeductTy; // Deduction against 'auto'.
|
||||
|
|
@ -516,7 +588,7 @@ public:
|
|||
/// The external AST source provides the ability to load parts of
|
||||
/// the abstract syntax tree as needed from some external storage,
|
||||
/// e.g., a precompiled header.
|
||||
void setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source);
|
||||
void setExternalSource(OwningPtr<ExternalASTSource> &Source);
|
||||
|
||||
/// \brief Retrieve a pointer to the external AST source associated
|
||||
/// with this AST context, if any.
|
||||
|
|
@ -797,7 +869,8 @@ public:
|
|||
QualType getPackExpansionType(QualType Pattern,
|
||||
llvm::Optional<unsigned> NumExpansions);
|
||||
|
||||
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const;
|
||||
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
|
||||
ObjCInterfaceDecl *PrevDecl = 0) const;
|
||||
|
||||
QualType getObjCObjectType(QualType Base,
|
||||
ObjCProtocolDecl * const *Protocols,
|
||||
|
|
@ -812,7 +885,7 @@ public:
|
|||
QualType getTypeOfType(QualType t) const;
|
||||
|
||||
/// getDecltypeType - C++0x decltype.
|
||||
QualType getDecltypeType(Expr *e) const;
|
||||
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
|
||||
|
||||
/// getUnaryTransformType - unary type transforms
|
||||
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
|
||||
|
|
@ -835,6 +908,14 @@ public:
|
|||
/// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4).
|
||||
CanQualType getSizeType() const;
|
||||
|
||||
/// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5),
|
||||
/// defined in <stdint.h>.
|
||||
CanQualType getIntMaxType() const;
|
||||
|
||||
/// getUIntMaxType - Return the unique type for "uintmax_t" (C99 7.18.1.5),
|
||||
/// defined in <stdint.h>.
|
||||
CanQualType getUIntMaxType() const;
|
||||
|
||||
/// getWCharType - In C++, this returns the unique wchar_t type. In C99, this
|
||||
/// returns a type compatible with the type defined in <stddef.h> as defined
|
||||
/// by the target.
|
||||
|
|
@ -848,7 +929,7 @@ public:
|
|||
/// Used when in C++, as a GCC extension.
|
||||
QualType getUnsignedWCharType() const;
|
||||
|
||||
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
|
||||
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
|
||||
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
|
||||
QualType getPointerDiffType() const;
|
||||
|
||||
|
|
@ -871,6 +952,14 @@ public:
|
|||
return ObjCConstantStringType;
|
||||
}
|
||||
|
||||
QualType getObjCNSStringType() const {
|
||||
return ObjCNSStringType;
|
||||
}
|
||||
|
||||
void setObjCNSStringType(QualType T) {
|
||||
ObjCNSStringType = T;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type that 'id' has been defined to, which may be
|
||||
/// different from the built-in 'id' if 'id' has been typedef'd.
|
||||
QualType getObjCIdRedefinitionType() const {
|
||||
|
|
@ -955,9 +1044,21 @@ public:
|
|||
return QualType();
|
||||
}
|
||||
|
||||
/// \brief Set the type for the C ucontext_t type.
|
||||
void setucontext_tDecl(TypeDecl *ucontext_tDecl) {
|
||||
this->ucontext_tDecl = ucontext_tDecl;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the C ucontext_t type.
|
||||
QualType getucontext_tType() const {
|
||||
if (ucontext_tDecl)
|
||||
return getTypeDeclType(ucontext_tDecl);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
/// \brief The result type of logical operations, '<', '>', '!=', etc.
|
||||
QualType getLogicalOperationType() const {
|
||||
return getLangOptions().CPlusPlus ? BoolTy : IntTy;
|
||||
return getLangOpts().CPlusPlus ? BoolTy : IntTy;
|
||||
}
|
||||
|
||||
/// getObjCEncodingForType - Emit the ObjC type encoding for the
|
||||
|
|
@ -984,7 +1085,8 @@ public:
|
|||
///
|
||||
/// \returns true if an error occurred (e.g., because one of the parameter
|
||||
/// types is incomplete), false otherwise.
|
||||
bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S)
|
||||
bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S,
|
||||
bool Extended = false)
|
||||
const;
|
||||
|
||||
/// getObjCEncodingForBlock - Return the encoded type for this block
|
||||
|
|
@ -1026,9 +1128,6 @@ public:
|
|||
return getTypeDeclType(getObjCSelDecl());
|
||||
}
|
||||
|
||||
void setObjCProtoType(QualType QT);
|
||||
QualType getObjCProtoType() const { return ObjCProtoType; }
|
||||
|
||||
/// \brief Retrieve the typedef declaration corresponding to the predefined
|
||||
/// Objective-C 'Class' type.
|
||||
TypedefDecl *getObjCClassDecl() const;
|
||||
|
|
@ -1040,6 +1139,15 @@ public:
|
|||
return getTypeDeclType(getObjCClassDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the Objective-C class declaration corresponding to
|
||||
/// the predefined 'Protocol' class.
|
||||
ObjCInterfaceDecl *getObjCProtocolDecl() const;
|
||||
|
||||
/// \brief Retrieve the type of the Objective-C "Protocol" class.
|
||||
QualType getObjCProtoType() const {
|
||||
return getObjCInterfaceType(getObjCProtocolDecl());
|
||||
}
|
||||
|
||||
void setBuiltinVaListType(QualType T);
|
||||
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
|
||||
|
||||
|
|
@ -1049,6 +1157,11 @@ public:
|
|||
return getQualifiedType(T, Qualifiers::fromCVRMask(CVR));
|
||||
}
|
||||
|
||||
/// getQualifiedType - Un-split a SplitQualType.
|
||||
QualType getQualifiedType(SplitQualType split) const {
|
||||
return getQualifiedType(split.Ty, split.Quals);
|
||||
}
|
||||
|
||||
/// getQualifiedType - Returns a type with additional qualifiers.
|
||||
QualType getQualifiedType(QualType T, Qualifiers Qs) const {
|
||||
if (!Qs.hasNonFastQualifiers())
|
||||
|
|
@ -1099,7 +1212,8 @@ public:
|
|||
enum GetBuiltinTypeError {
|
||||
GE_None, //< No error
|
||||
GE_Missing_stdio, //< Missing a type from <stdio.h>
|
||||
GE_Missing_setjmp //< Missing a type from <setjmp.h>
|
||||
GE_Missing_setjmp, //< Missing a type from <setjmp.h>
|
||||
GE_Missing_ucontext //< Missing a type from <ucontext.h>
|
||||
};
|
||||
|
||||
/// GetBuiltinType - Return the type for the specified builtin. If
|
||||
|
|
@ -1111,6 +1225,7 @@ public:
|
|||
|
||||
private:
|
||||
CanQualType getFromTargetType(unsigned Type) const;
|
||||
std::pair<uint64_t, unsigned> getTypeInfoImpl(const Type *T) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Predicates.
|
||||
|
|
@ -1214,7 +1329,8 @@ public:
|
|||
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D)
|
||||
const;
|
||||
|
||||
void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS) const;
|
||||
void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
|
||||
bool Simple = false) const;
|
||||
|
||||
/// getASTObjCImplementationLayout - Get or compute information about
|
||||
/// the layout of the specified Objective-C implementation. This may
|
||||
|
|
@ -1230,6 +1346,9 @@ public:
|
|||
/// of class definition.
|
||||
const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD);
|
||||
|
||||
/// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
|
||||
uint64_t getFieldOffset(const ValueDecl *FD) const;
|
||||
|
||||
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
|
||||
|
||||
MangleContext *createMangleContext();
|
||||
|
|
@ -1266,7 +1385,7 @@ public:
|
|||
CanQualType getCanonicalParamType(QualType T) const;
|
||||
|
||||
/// \brief Determine whether the given types are equivalent.
|
||||
bool hasSameType(QualType T1, QualType T2) {
|
||||
bool hasSameType(QualType T1, QualType T2) const {
|
||||
return getCanonicalType(T1) == getCanonicalType(T2);
|
||||
}
|
||||
|
||||
|
|
@ -1286,7 +1405,7 @@ public:
|
|||
|
||||
/// \brief Determine whether the given types are equivalent after
|
||||
/// cvr-qualifiers have been removed.
|
||||
bool hasSameUnqualifiedType(QualType T1, QualType T2) {
|
||||
bool hasSameUnqualifiedType(QualType T1, QualType T2) const {
|
||||
return getCanonicalType(T1).getTypePtr() ==
|
||||
getCanonicalType(T2).getTypePtr();
|
||||
}
|
||||
|
|
@ -1574,6 +1693,8 @@ public:
|
|||
return Res;
|
||||
}
|
||||
|
||||
bool isSentinelNullExpr(const Expr *E);
|
||||
|
||||
/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists.
|
||||
ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D);
|
||||
/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
|
||||
|
|
@ -1606,6 +1727,11 @@ public:
|
|||
const ObjCMethodDecl *Redecl) {
|
||||
ObjCMethodRedecls[MD] = Redecl;
|
||||
}
|
||||
|
||||
/// \brief Returns the objc interface that \arg ND belongs to if it is a
|
||||
/// objc method/property/ivar etc. that is part of an interface,
|
||||
/// otherwise returns null.
|
||||
ObjCInterfaceDecl *getObjContainingInterface(NamedDecl *ND) const;
|
||||
|
||||
/// \brief Set the copy inialization expression of a block var decl.
|
||||
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
|
||||
|
|
@ -1655,6 +1781,8 @@ public:
|
|||
/// it is not used.
|
||||
bool DeclMustBeEmitted(const Decl *D);
|
||||
|
||||
/// \brief Retrieve the lambda mangling number for a lambda expression.
|
||||
unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator);
|
||||
|
||||
/// \brief Used by ParmVarDecl to store on the side the
|
||||
/// index of the parameter when it exceeds the size of the normal bitfield.
|
||||
|
|
@ -1735,13 +1863,20 @@ private:
|
|||
const FieldDecl *Field,
|
||||
bool OutermostType = false,
|
||||
bool EncodingProperty = false,
|
||||
bool StructField = false) const;
|
||||
bool StructField = false,
|
||||
bool EncodeBlockParameters = false,
|
||||
bool EncodeClassNames = false) const;
|
||||
|
||||
// Adds the encoding of the structure's members.
|
||||
void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S,
|
||||
const FieldDecl *Field,
|
||||
bool includeVBases = true) const;
|
||||
|
||||
|
||||
// Adds the encoding of a method parameter or return type.
|
||||
void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
|
||||
QualType T, std::string& S,
|
||||
bool Extended) const;
|
||||
|
||||
const ASTRecordLayout &
|
||||
getObjCLayout(const ObjCInterfaceDecl *D,
|
||||
const ObjCImplementationDecl *Impl) const;
|
||||
|
|
@ -1779,13 +1914,19 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
|
|||
} // end namespace clang
|
||||
|
||||
// operator new and delete aren't allowed inside namespaces.
|
||||
// The throw specifications are mandated by the standard.
|
||||
|
||||
/// @brief Placement new for using the ASTContext's allocator.
|
||||
///
|
||||
/// This placement form of operator new uses the ASTContext's allocator for
|
||||
/// obtaining memory. It is a non-throwing new, which means that it returns
|
||||
/// null on error. (If that is what the allocator does. The current does, so if
|
||||
/// this ever changes, this operator will have to be changed, too.)
|
||||
/// obtaining memory.
|
||||
///
|
||||
/// IMPORTANT: These are also declared in clang/AST/Attr.h! Any changes here
|
||||
/// need to also be made there.
|
||||
///
|
||||
/// We intentionally avoid using a nothrow specification here so that the calls
|
||||
/// to this operator will not perform a null check on the result -- the
|
||||
/// underlying allocator never returns null pointers.
|
||||
///
|
||||
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
|
||||
/// @code
|
||||
/// // Default alignment (8)
|
||||
|
|
@ -1803,7 +1944,7 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
|
|||
/// allocator supports it).
|
||||
/// @return The allocated memory. Could be NULL.
|
||||
inline void *operator new(size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment) throw () {
|
||||
size_t Alignment) {
|
||||
return C.Allocate(Bytes, Alignment);
|
||||
}
|
||||
/// @brief Placement delete companion to the new above.
|
||||
|
|
@ -1812,14 +1953,17 @@ inline void *operator new(size_t Bytes, const clang::ASTContext &C,
|
|||
/// invoking it directly; see the new operator for more details. This operator
|
||||
/// is called implicitly by the compiler if a placement new expression using
|
||||
/// the ASTContext throws in the object constructor.
|
||||
inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t)
|
||||
throw () {
|
||||
inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) {
|
||||
C.Deallocate(Ptr);
|
||||
}
|
||||
|
||||
/// This placement form of operator new[] uses the ASTContext's allocator for
|
||||
/// obtaining memory. It is a non-throwing new[], which means that it returns
|
||||
/// null on error.
|
||||
/// obtaining memory.
|
||||
///
|
||||
/// We intentionally avoid using a nothrow specification here so that the calls
|
||||
/// to this operator will not perform a null check on the result -- the
|
||||
/// underlying allocator never returns null pointers.
|
||||
///
|
||||
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
|
||||
/// @code
|
||||
/// // Default alignment (8)
|
||||
|
|
@ -1837,7 +1981,7 @@ inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t)
|
|||
/// allocator supports it).
|
||||
/// @return The allocated memory. Could be NULL.
|
||||
inline void *operator new[](size_t Bytes, const clang::ASTContext& C,
|
||||
size_t Alignment = 8) throw () {
|
||||
size_t Alignment = 8) {
|
||||
return C.Allocate(Bytes, Alignment);
|
||||
}
|
||||
|
||||
|
|
@ -1847,8 +1991,7 @@ inline void *operator new[](size_t Bytes, const clang::ASTContext& C,
|
|||
/// invoking it directly; see the new[] operator for more details. This operator
|
||||
/// is called implicitly by the compiler if a placement new[] expression using
|
||||
/// the ASTContext throws in the object constructor.
|
||||
inline void operator delete[](void *Ptr, const clang::ASTContext &C, size_t)
|
||||
throw () {
|
||||
inline void operator delete[](void *Ptr, const clang::ASTContext &C, size_t) {
|
||||
C.Deallocate(Ptr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace clang {
|
|||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||
#undef DIAG
|
||||
|
|
@ -44,7 +44,7 @@ namespace clang {
|
|||
unsigned NumPrevArgs,
|
||||
SmallVectorImpl<char> &Output,
|
||||
void *Cookie,
|
||||
SmallVectorImpl<intptr_t> &QualTypeVals);
|
||||
ArrayRef<intptr_t> QualTypeVals);
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -255,6 +255,12 @@ namespace clang {
|
|||
|
||||
/// \brief Return the set of declarations that we know are not equivalent.
|
||||
NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; }
|
||||
|
||||
/// \brief Called for ObjCInterfaceDecl, ObjCProtocolDecl, and TagDecl.
|
||||
/// Mark the Decl as complete, filling it in as much as possible.
|
||||
///
|
||||
/// \param D A declaration in the "to" context.
|
||||
virtual void CompleteDecl(Decl* D);
|
||||
|
||||
/// \brief Note that we have imported the "from" declaration by mapping it
|
||||
/// to the (potentially-newly-created) "to" declaration.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ namespace clang {
|
|||
class FunctionTemplateDecl;
|
||||
class ObjCCategoryDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCContainerDecl;
|
||||
class ObjCPropertyDecl;
|
||||
|
||||
/// \brief An abstract interface that should be implemented by listeners
|
||||
/// that want to be notified when an AST entity gets modified after its
|
||||
|
|
@ -60,6 +62,21 @@ public:
|
|||
/// \brief A new objc category class was added for an interface.
|
||||
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
|
||||
const ObjCInterfaceDecl *IFD) {}
|
||||
|
||||
/// \brief A objc class extension redeclared or introduced a property.
|
||||
///
|
||||
/// \param Prop the property in the class extension
|
||||
///
|
||||
/// \param OrigProp the property from the original interface that was declared
|
||||
/// or null if the property was introduced.
|
||||
///
|
||||
/// \param ClassExt the class extension.
|
||||
virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
|
||||
const ObjCPropertyDecl *OrigProp,
|
||||
const ObjCCategoryDecl *ClassExt) {}
|
||||
|
||||
// NOTE: If new methods are added they should also be added to
|
||||
// MultiplexASTMutationListener.
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
|
@ -39,19 +40,17 @@ namespace clang {
|
|||
|
||||
// Defined in ASTContext.h
|
||||
void *operator new(size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment = 16) throw ();
|
||||
size_t Alignment = 16);
|
||||
// FIXME: Being forced to not have a default argument here due to redeclaration
|
||||
// rules on default arguments sucks
|
||||
void *operator new[](size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment) throw ();
|
||||
size_t Alignment);
|
||||
|
||||
// It is good practice to pair new/delete operators. Also, MSVC gives many
|
||||
// warnings if a matching delete overload is not declared, even though the
|
||||
// throw() spec guarantees it will not be implicitly called.
|
||||
void operator delete(void *Ptr, const clang::ASTContext &C, size_t)
|
||||
throw ();
|
||||
void operator delete[](void *Ptr, const clang::ASTContext &C, size_t)
|
||||
throw ();
|
||||
void operator delete(void *Ptr, const clang::ASTContext &C, size_t);
|
||||
void operator delete[](void *Ptr, const clang::ASTContext &C, size_t);
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
@ -103,11 +102,17 @@ public:
|
|||
// Clone this attribute.
|
||||
virtual Attr* clone(ASTContext &C) const = 0;
|
||||
|
||||
virtual bool isLateParsed() const { return false; }
|
||||
|
||||
// Pretty print this attribute.
|
||||
virtual void printPretty(llvm::raw_ostream &OS, ASTContext &C) const = 0;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *) { return true; }
|
||||
};
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
InheritableAttr(attr::Kind AK, SourceRange R)
|
||||
: Attr(AK, R) {}
|
||||
|
|
@ -123,6 +128,7 @@ public:
|
|||
};
|
||||
|
||||
class InheritableParamAttr : public InheritableAttr {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
InheritableParamAttr(attr::Kind AK, SourceRange R)
|
||||
: InheritableAttr(AK, R) {}
|
||||
|
|
|
|||
224
include/clang/AST/BuiltinTypes.def
Normal file
224
include/clang/AST/BuiltinTypes.def
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- 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 database about various builtin singleton types.
|
||||
//
|
||||
// BuiltinType::Id is the enumerator defining the type.
|
||||
//
|
||||
// Context.SingletonId is the global singleton of this type. Some global
|
||||
// singletons are shared by multiple types.
|
||||
//
|
||||
// BUILTIN_TYPE(Id, SingletonId) - A builtin type that has not been
|
||||
// covered by any other #define. Defining this macro covers all
|
||||
// the builtins.
|
||||
//
|
||||
// SIGNED_TYPE(Id, SingletonId) - A signed integral type.
|
||||
//
|
||||
// UNSIGNED_TYPE(Id, SingletonId) - An unsigned integral type.
|
||||
//
|
||||
// FLOATING_TYPE(Id, SingletonId) - A floating-point type.
|
||||
//
|
||||
// PLACEHOLDER_TYPE(Id, SingletonId) - A placeholder type. Placeholder
|
||||
// types are used to perform context-sensitive checking of specific
|
||||
// forms of expression.
|
||||
//
|
||||
// SHARED_SINGLETON_TYPE(Expansion) - The given expansion corresponds
|
||||
// to a builtin which uses a shared singleton type.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SIGNED_TYPE
|
||||
#define SIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
|
||||
#endif
|
||||
|
||||
#ifndef UNSIGNED_TYPE
|
||||
#define UNSIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
|
||||
#endif
|
||||
|
||||
#ifndef FLOATING_TYPE
|
||||
#define FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
|
||||
#endif
|
||||
|
||||
#ifndef PLACEHOLDER_TYPE
|
||||
#define PLACEHOLDER_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
|
||||
#endif
|
||||
|
||||
#ifndef SHARED_SINGLETON_TYPE
|
||||
#define SHARED_SINGLETON_TYPE(Expansion) Expansion
|
||||
#endif
|
||||
|
||||
//===- Builtin Types ------------------------------------------------------===//
|
||||
|
||||
// void
|
||||
BUILTIN_TYPE(Void, VoidTy)
|
||||
|
||||
//===- Unsigned Types -----------------------------------------------------===//
|
||||
|
||||
// 'bool' in C++, '_Bool' in C99
|
||||
UNSIGNED_TYPE(Bool, BoolTy)
|
||||
|
||||
// 'char' for targets where it's unsigned
|
||||
SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(Char_U, CharTy))
|
||||
|
||||
// 'unsigned char', explicitly qualified
|
||||
UNSIGNED_TYPE(UChar, UnsignedCharTy)
|
||||
|
||||
// 'wchar_t' for targets where it's unsigned
|
||||
SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(WChar_U, WCharTy))
|
||||
|
||||
// 'char16_t' in C++
|
||||
UNSIGNED_TYPE(Char16, Char16Ty)
|
||||
|
||||
// 'char32_t' in C++
|
||||
UNSIGNED_TYPE(Char32, Char32Ty)
|
||||
|
||||
// 'unsigned short'
|
||||
UNSIGNED_TYPE(UShort, UnsignedShortTy)
|
||||
|
||||
// 'unsigned int'
|
||||
UNSIGNED_TYPE(UInt, UnsignedIntTy)
|
||||
|
||||
// 'unsigned long'
|
||||
UNSIGNED_TYPE(ULong, UnsignedLongTy)
|
||||
|
||||
// 'unsigned long long'
|
||||
UNSIGNED_TYPE(ULongLong, UnsignedLongLongTy)
|
||||
|
||||
// '__uint128_t'
|
||||
UNSIGNED_TYPE(UInt128, UnsignedInt128Ty)
|
||||
|
||||
//===- Signed Types -------------------------------------------------------===//
|
||||
|
||||
// 'char' for targets where it's signed
|
||||
SHARED_SINGLETON_TYPE(SIGNED_TYPE(Char_S, CharTy))
|
||||
|
||||
// 'signed char', explicitly qualified
|
||||
SIGNED_TYPE(SChar, SignedCharTy)
|
||||
|
||||
// 'wchar_t' for targets where it's signed
|
||||
SHARED_SINGLETON_TYPE(SIGNED_TYPE(WChar_S, WCharTy))
|
||||
|
||||
// 'short' or 'signed short'
|
||||
SIGNED_TYPE(Short, ShortTy)
|
||||
|
||||
// 'int' or 'signed int'
|
||||
SIGNED_TYPE(Int, IntTy)
|
||||
|
||||
// 'long' or 'signed long'
|
||||
SIGNED_TYPE(Long, LongTy)
|
||||
|
||||
// 'long long' or 'signed long long'
|
||||
SIGNED_TYPE(LongLong, LongLongTy)
|
||||
|
||||
// '__int128_t'
|
||||
SIGNED_TYPE(Int128, Int128Ty)
|
||||
|
||||
//===- Floating point types -----------------------------------------------===//
|
||||
|
||||
// 'half' in OpenCL, '__fp16' in ARM NEON.
|
||||
FLOATING_TYPE(Half, HalfTy)
|
||||
|
||||
// 'float'
|
||||
FLOATING_TYPE(Float, FloatTy)
|
||||
|
||||
// 'double'
|
||||
FLOATING_TYPE(Double, DoubleTy)
|
||||
|
||||
// 'long double'
|
||||
FLOATING_TYPE(LongDouble, LongDoubleTy)
|
||||
|
||||
//===- Language-specific types --------------------------------------------===//
|
||||
|
||||
// This is the type of C++0x 'nullptr'.
|
||||
BUILTIN_TYPE(NullPtr, NullPtrTy)
|
||||
|
||||
// The primitive Objective C 'id' type. The user-visible 'id'
|
||||
// type is a typedef of an ObjCObjectPointerType to an
|
||||
// ObjCObjectType with this as its base. In fact, this only ever
|
||||
// shows up in an AST as the base type of an ObjCObjectType.
|
||||
BUILTIN_TYPE(ObjCId, ObjCBuiltinIdTy)
|
||||
|
||||
// The primitive Objective C 'Class' type. The user-visible
|
||||
// 'Class' type is a typedef of an ObjCObjectPointerType to an
|
||||
// ObjCObjectType with this as its base. In fact, this only ever
|
||||
// shows up in an AST as the base type of an ObjCObjectType.
|
||||
BUILTIN_TYPE(ObjCClass, ObjCBuiltinClassTy)
|
||||
|
||||
// The primitive Objective C 'SEL' type. The user-visible 'SEL'
|
||||
// type is a typedef of a PointerType to this.
|
||||
BUILTIN_TYPE(ObjCSel, ObjCBuiltinSelTy)
|
||||
|
||||
// This represents the type of an expression whose type is
|
||||
// totally unknown, e.g. 'T::foo'. It is permitted for this to
|
||||
// appear in situations where the structure of the type is
|
||||
// theoretically deducible.
|
||||
BUILTIN_TYPE(Dependent, DependentTy)
|
||||
|
||||
// The type of an unresolved overload set. A placeholder type.
|
||||
// Expressions with this type have one of the following basic
|
||||
// forms, with parentheses generally permitted:
|
||||
// foo # possibly qualified, not if an implicit access
|
||||
// foo # possibly qualified, not if an implicit access
|
||||
// &foo # possibly qualified, not if an implicit access
|
||||
// x->foo # only if might be a static member function
|
||||
// &x->foo # only if might be a static member function
|
||||
// &Class::foo # when a pointer-to-member; sub-expr also has this type
|
||||
// OverloadExpr::find can be used to analyze the expression.
|
||||
//
|
||||
// Overload should be the first placeholder type, or else change
|
||||
// BuiltinType::isNonOverloadPlaceholderType()
|
||||
PLACEHOLDER_TYPE(Overload, OverloadTy)
|
||||
|
||||
// The type of a bound C++ non-static member function.
|
||||
// A placeholder type. Expressions with this type have one of the
|
||||
// following basic forms:
|
||||
// foo # if an implicit access
|
||||
// x->foo # if only contains non-static members
|
||||
PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)
|
||||
|
||||
// The type of an expression which refers to a pseudo-object,
|
||||
// such as those introduced by Objective C's @property or
|
||||
// VS.NET's __property declarations. A placeholder type. The
|
||||
// pseudo-object is actually accessed by emitting a call to
|
||||
// some sort of function or method; typically there is a pair
|
||||
// of a setter and a getter, with the setter used if the
|
||||
// pseudo-object reference is used syntactically as the
|
||||
// left-hand-side of an assignment operator.
|
||||
//
|
||||
// A pseudo-object reference naming an Objective-C @property is
|
||||
// always a dot access with a base of object-pointer type,
|
||||
// e.g. 'x.foo'.
|
||||
//
|
||||
// In VS.NET, a __property declaration creates an implicit
|
||||
// member with an associated name, which can then be named
|
||||
// in any of the normal ways an ordinary member could be.
|
||||
PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
|
||||
|
||||
// __builtin_any_type. A placeholder type. Useful for clients
|
||||
// like debuggers that don't know what type to give something.
|
||||
// Only a small number of operations are valid on expressions of
|
||||
// unknown type, most notably explicit casts.
|
||||
PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
|
||||
|
||||
// The type of a cast which, in ARC, would normally require a
|
||||
// __bridge, but which might be okay depending on the immediate
|
||||
// context.
|
||||
PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy)
|
||||
|
||||
#ifdef LAST_BUILTIN_TYPE
|
||||
LAST_BUILTIN_TYPE(ARCUnbridgedCast)
|
||||
#undef LAST_BUILTIN_TYPE
|
||||
#endif
|
||||
|
||||
#undef SHARED_SINGLETON_TYPE
|
||||
#undef PLACEHOLDER_TYPE
|
||||
#undef FLOATING_TYPE
|
||||
#undef SIGNED_TYPE
|
||||
#undef UNSIGNED_TYPE
|
||||
#undef BUILTIN_TYPE
|
||||
|
|
@ -108,6 +108,8 @@ public:
|
|||
/// or a derived class thereof, a NULL canonical type.
|
||||
template<typename U> CanProxy<U> getAs() const;
|
||||
|
||||
template<typename U> CanProxy<U> castAs() const;
|
||||
|
||||
/// \brief Overloaded arrow operator that produces a canonical type
|
||||
/// proxy.
|
||||
CanProxy<T> operator->() const;
|
||||
|
|
@ -752,6 +754,13 @@ CanProxy<U> CanQual<T>::getAs() const {
|
|||
return CanProxy<U>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
CanProxy<U> CanQual<T>::castAs() const {
|
||||
assert(!Stored.isNull() && isa<U>(Stored.getTypePtr()));
|
||||
return CanQual<U>::CreateUnsafe(Stored);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CanProxy<T> CanQual<T>::operator->() const {
|
||||
return CanProxy<T>(*this);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -17,8 +17,9 @@
|
|||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
|
||||
namespace clang {
|
||||
class DeclContext;
|
||||
|
|
@ -98,7 +99,7 @@ public:
|
|||
/// identifiers. C++ describes lookup completely differently:
|
||||
/// certain lookups merely "ignore" certain kinds of declarations,
|
||||
/// usually based on whether the declaration is of a type, etc.
|
||||
///
|
||||
///
|
||||
/// These are meant as bitmasks, so that searches in
|
||||
/// C++ can look into the "tag" namespace during ordinary lookup.
|
||||
///
|
||||
|
|
@ -180,12 +181,28 @@ public:
|
|||
OBJC_TQ_Oneway = 0x20
|
||||
};
|
||||
|
||||
private:
|
||||
/// NextDeclInContext - The next declaration within the same lexical
|
||||
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
|
||||
};
|
||||
|
||||
/// \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().
|
||||
Decl *NextDeclInContext;
|
||||
///
|
||||
/// The extra two bits are used for the TopLevelDeclInObjCContainer and
|
||||
/// ModulePrivate bits.
|
||||
llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits;
|
||||
|
||||
private:
|
||||
friend class DeclContext;
|
||||
|
||||
struct MultipleDC {
|
||||
|
|
@ -243,7 +260,10 @@ private:
|
|||
/// evaluated context or not, e.g. functions used in uninstantiated templates
|
||||
/// are regarded as "referenced" but not "used".
|
||||
unsigned Referenced : 1;
|
||||
|
||||
|
||||
/// \brief Whether statistic collection is enabled.
|
||||
static bool StatisticsEnabled;
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
|
|
@ -252,14 +272,12 @@ 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;
|
||||
|
||||
/// ChangedAfterLoad - if this declaration has changed since being loaded
|
||||
unsigned ChangedAfterLoad : 1;
|
||||
|
||||
/// \brief Whether this declaration is private to the module in which it was
|
||||
/// defined.
|
||||
unsigned ModulePrivate : 1;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 12;
|
||||
|
||||
|
|
@ -267,14 +285,15 @@ protected:
|
|||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned HasCachedLinkage : 1;
|
||||
|
||||
|
||||
/// \brief If \c HasCachedLinkage, the linkage of this declaration.
|
||||
///
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned CachedLinkage : 2;
|
||||
|
||||
|
||||
friend class ASTDeclWriter;
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTReader;
|
||||
|
||||
private:
|
||||
void CheckAccessDeclContext() const;
|
||||
|
|
@ -282,38 +301,52 @@ private:
|
|||
protected:
|
||||
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
: NextInContextAndBits(), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
|
||||
ModulePrivate(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
if (Decl::CollectingStats()) add(DK);
|
||||
}
|
||||
|
||||
Decl(Kind DK, EmptyShell Empty)
|
||||
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
|
||||
ModulePrivate(0),
|
||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
if (Decl::CollectingStats()) add(DK);
|
||||
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)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
if (StatisticsEnabled) add(DK);
|
||||
}
|
||||
|
||||
virtual ~Decl();
|
||||
|
||||
/// \brief Allocate memory for a deserialized declaration.
|
||||
///
|
||||
/// This routine must be used to allocate memory for any declaration that is
|
||||
/// deserialized from a module file.
|
||||
///
|
||||
/// \param Context The context in which we will allocate memory.
|
||||
/// \param ID The global ID of the deserialized declaration.
|
||||
/// \param Size The size of the allocated object.
|
||||
static void *AllocateDeserializedDecl(const ASTContext &Context,
|
||||
unsigned ID,
|
||||
unsigned Size);
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Source range that this declaration covers.
|
||||
virtual SourceRange getSourceRange() const {
|
||||
virtual SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getLocation(), getLocation());
|
||||
}
|
||||
SourceLocation getLocStart() const { return getSourceRange().getBegin(); }
|
||||
SourceLocation getLocEnd() const { return getSourceRange().getEnd(); }
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return getSourceRange().getBegin();
|
||||
}
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
return getSourceRange().getEnd();
|
||||
}
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
|
@ -321,8 +354,8 @@ public:
|
|||
Kind getKind() const { return static_cast<Kind>(DeclKind); }
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
Decl *getNextDeclInContext() { return NextDeclInContext; }
|
||||
const Decl *getNextDeclInContext() const { return NextDeclInContext; }
|
||||
Decl *getNextDeclInContext() { return NextInContextAndBits.getPointer(); }
|
||||
const Decl *getNextDeclInContext() const {return NextInContextAndBits.getPointer();}
|
||||
|
||||
DeclContext *getDeclContext() {
|
||||
if (isInSemaDC())
|
||||
|
|
@ -347,7 +380,7 @@ public:
|
|||
|
||||
bool isInAnonymousNamespace() const;
|
||||
|
||||
ASTContext &getASTContext() const;
|
||||
ASTContext &getASTContext() const LLVM_READONLY;
|
||||
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
Access = AS;
|
||||
|
|
@ -364,7 +397,9 @@ public:
|
|||
}
|
||||
|
||||
bool hasAttrs() const { return HasAttrs; }
|
||||
void setAttrs(const AttrVec& Attrs);
|
||||
void setAttrs(const AttrVec& Attrs) {
|
||||
return setAttrsImpl(Attrs, getASTContext());
|
||||
}
|
||||
AttrVec &getAttrs() {
|
||||
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
|
||||
}
|
||||
|
|
@ -389,11 +424,11 @@ public:
|
|||
attr_iterator attr_end() const {
|
||||
return hasAttrs() ? getAttrs().end() : 0;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void dropAttr() {
|
||||
if (!HasAttrs) return;
|
||||
|
||||
|
||||
AttrVec &Attrs = getAttrs();
|
||||
for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) {
|
||||
if (isa<T>(Attrs[i])) {
|
||||
|
|
@ -406,7 +441,7 @@ public:
|
|||
if (Attrs.empty())
|
||||
HasAttrs = false;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
specific_attr_iterator<T> specific_attr_begin() const {
|
||||
return specific_attr_iterator<T>(attr_begin());
|
||||
|
|
@ -455,6 +490,48 @@ public:
|
|||
|
||||
void setReferenced(bool R = true) { Referenced = R; }
|
||||
|
||||
/// \brief Whether this declaration is a top-level declaration (function,
|
||||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
bool isTopLevelDeclInObjCContainer() const {
|
||||
return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag;
|
||||
}
|
||||
|
||||
void setTopLevelDeclInObjCContainer(bool V = true) {
|
||||
unsigned Bits = NextInContextAndBits.getInt();
|
||||
if (V)
|
||||
Bits |= TopLevelDeclInObjCContainerFlag;
|
||||
else
|
||||
Bits &= ~TopLevelDeclInObjCContainerFlag;
|
||||
NextInContextAndBits.setInt(Bits);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \brief Whether this declaration was marked as being private to the
|
||||
/// module in which it was defined.
|
||||
bool isModulePrivate() const {
|
||||
return NextInContextAndBits.getInt() & ModulePrivateFlag;
|
||||
}
|
||||
|
||||
/// \brief Specify whether 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);
|
||||
}
|
||||
|
||||
/// \brief Set the owning module ID.
|
||||
void setOwningModuleID(unsigned ID) {
|
||||
assert(isFromASTFile() && "Only works on a deserialized declaration");
|
||||
*((unsigned*)this - 2) = ID;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Determine the availability of the given declaration.
|
||||
///
|
||||
/// This routine will determine the most restrictive availability of
|
||||
|
|
@ -504,20 +581,24 @@ public:
|
|||
/// \brief Determine whether this declaration came from an AST file (such as
|
||||
/// a precompiled header or module) rather than having been parsed.
|
||||
bool isFromASTFile() const { return FromASTFile; }
|
||||
|
||||
/// \brief Query whether this declaration was changed in a significant way
|
||||
/// since being loaded from an AST file.
|
||||
///
|
||||
/// In an epic violation of layering, what is "significant" is entirely
|
||||
/// up to the serialization system, but implemented in AST and Sema.
|
||||
bool isChangedSinceDeserialization() const { return ChangedAfterLoad; }
|
||||
|
||||
/// \brief Mark this declaration as having changed since deserialization, or
|
||||
/// reset the flag.
|
||||
void setChangedSinceDeserialization(bool Changed) {
|
||||
ChangedAfterLoad = Changed;
|
||||
/// \brief Retrieve the global declaration ID associated with this
|
||||
/// declaration, which specifies where in the
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
|
|
@ -587,7 +668,7 @@ public:
|
|||
|
||||
/// \brief Whether this particular Decl is a canonical one.
|
||||
bool isCanonicalDecl() const { return getCanonicalDecl() == this; }
|
||||
|
||||
|
||||
protected:
|
||||
/// \brief Returns the next redeclaration or itself if this is the only decl.
|
||||
///
|
||||
|
|
@ -595,6 +676,14 @@ protected:
|
|||
/// Decl::redecl_iterator can iterate over them.
|
||||
virtual Decl *getNextRedeclaration() { return this; }
|
||||
|
||||
/// \brief Implementation of getPreviousDecl(), to be overridden by any
|
||||
/// subclass that has a redeclaration chain.
|
||||
virtual Decl *getPreviousDeclImpl() { return 0; }
|
||||
|
||||
/// \brief Implementation of getMostRecentDecl(), to be overridden by any
|
||||
/// subclass that has a redeclaration chain.
|
||||
virtual Decl *getMostRecentDeclImpl() { return this; }
|
||||
|
||||
public:
|
||||
/// \brief Iterates through all the redeclarations of the same decl.
|
||||
class redecl_iterator {
|
||||
|
|
@ -645,6 +734,26 @@ public:
|
|||
}
|
||||
redecl_iterator redecls_end() const { return redecl_iterator(); }
|
||||
|
||||
/// \brief Retrieve the previous declaration that declares the same entity
|
||||
/// as this declaration, or NULL if there is no previous declaration.
|
||||
Decl *getPreviousDecl() { return getPreviousDeclImpl(); }
|
||||
|
||||
/// \brief Retrieve the most recent declaration that declares the same entity
|
||||
/// as this declaration, or NULL if there is no previous declaration.
|
||||
const Decl *getPreviousDecl() const {
|
||||
return const_cast<Decl *>(this)->getPreviousDeclImpl();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the most recent declaration that declares the same entity
|
||||
/// as this declaration (which may be this declaration).
|
||||
Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); }
|
||||
|
||||
/// \brief Retrieve the most recent declaration that declares the same entity
|
||||
/// as this declaration (which may be this declaration).
|
||||
const Decl *getMostRecentDecl() const {
|
||||
return const_cast<Decl *>(this)->getMostRecentDeclImpl();
|
||||
}
|
||||
|
||||
/// getBody - If this Decl represents a declaration for a body of code,
|
||||
/// such as a function or method definition, this method returns the
|
||||
/// top-level Stmt* of that body. Otherwise this method returns null.
|
||||
|
|
@ -660,7 +769,7 @@ public:
|
|||
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void add(Kind k);
|
||||
static bool CollectingStats(bool Enable = false);
|
||||
static void EnableStatistics();
|
||||
static void PrintStats();
|
||||
|
||||
/// isTemplateParameter - Determines whether this declaration is a
|
||||
|
|
@ -673,7 +782,7 @@ public:
|
|||
|
||||
/// \brief Whether this declaration is a parameter pack.
|
||||
bool isParameterPack() const;
|
||||
|
||||
|
||||
/// \brief returns true if this declaration is a template
|
||||
bool isTemplateDecl() const;
|
||||
|
||||
|
|
@ -722,7 +831,7 @@ public:
|
|||
unsigned mask
|
||||
= (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
|
||||
if (!mask) return FOK_None;
|
||||
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
|
||||
return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
|
||||
FOK_Declared : FOK_Undeclared);
|
||||
}
|
||||
|
||||
|
|
@ -747,17 +856,31 @@ public:
|
|||
static void printGroup(Decl** Begin, unsigned NumDecls,
|
||||
raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
void dump() const;
|
||||
void dumpXML() const;
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpXML() const;
|
||||
void dumpXML(raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
const Attr *getAttrsImpl() const;
|
||||
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
|
||||
void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
|
||||
ASTContext &Ctx);
|
||||
|
||||
protected:
|
||||
ASTMutationListener *getASTMutationListener() const;
|
||||
};
|
||||
|
||||
/// \brief Determine whether two declarations declare the same entity.
|
||||
inline bool declaresSameEntity(const Decl *D1, const Decl *D2) {
|
||||
if (!D1 || !D2)
|
||||
return false;
|
||||
|
||||
if (D1 == D2)
|
||||
return true;
|
||||
|
||||
return D1->getCanonicalDecl() == D2->getCanonicalDecl();
|
||||
}
|
||||
|
||||
/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when
|
||||
/// doing something to a specific decl.
|
||||
class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
|
||||
|
|
@ -826,8 +949,11 @@ class DeclContext {
|
|||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context (or a DependentStoredDeclsMap if this is a
|
||||
/// dependent context).
|
||||
mutable StoredDeclsMap *LookupPtr;
|
||||
/// dependent context), and a bool indicating whether we have lazily
|
||||
/// omitted any declarations from the map. We maintain the invariant
|
||||
/// that, if the map contains an entry for a DeclarationName, then it
|
||||
/// contains all relevant entries for that name.
|
||||
mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr;
|
||||
|
||||
protected:
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
|
|
@ -841,16 +967,17 @@ protected:
|
|||
mutable Decl *LastDecl;
|
||||
|
||||
friend class ExternalASTSource;
|
||||
friend class ASTWriter;
|
||||
|
||||
/// \brief Build up a chain of declarations.
|
||||
///
|
||||
/// \returns the first/last pair of declarations.
|
||||
static std::pair<Decl *, Decl *>
|
||||
BuildDeclChain(const SmallVectorImpl<Decl*> &Decls, bool FieldsAlreadyLoaded);
|
||||
BuildDeclChain(ArrayRef<Decl*> Decls, bool FieldsAlreadyLoaded);
|
||||
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
|
||||
ExternalVisibleStorage(false), LookupPtr(0, false), FirstDecl(0),
|
||||
LastDecl(0) { }
|
||||
|
||||
public:
|
||||
|
|
@ -886,11 +1013,11 @@ public:
|
|||
}
|
||||
|
||||
DeclContext *getLookupParent();
|
||||
|
||||
|
||||
const DeclContext *getLookupParent() const {
|
||||
return const_cast<DeclContext*>(this)->getLookupParent();
|
||||
}
|
||||
|
||||
|
||||
ASTContext &getParentASTContext() const {
|
||||
return cast<Decl>(this)->getASTContext();
|
||||
}
|
||||
|
|
@ -974,6 +1101,14 @@ public:
|
|||
/// declaration context DC.
|
||||
bool Encloses(const DeclContext *DC) const;
|
||||
|
||||
/// \brief Find the nearest non-closure ancestor of this context,
|
||||
/// i.e. the innermost semantic parent of this context which is not
|
||||
/// a closure. A context may be its own non-closure ancestor.
|
||||
DeclContext *getNonClosureAncestor();
|
||||
const DeclContext *getNonClosureAncestor() const {
|
||||
return const_cast<DeclContext*>(this)->getNonClosureAncestor();
|
||||
}
|
||||
|
||||
/// getPrimaryContext - There may be many different
|
||||
/// declarations of the same entity (including forward declarations
|
||||
/// of classes, multiple definitions of namespaces, etc.), each with
|
||||
|
|
@ -1007,24 +1142,30 @@ public:
|
|||
/// inline, its enclosing namespace, recursively.
|
||||
bool InEnclosingNamespaceSetOf(const DeclContext *NS) const;
|
||||
|
||||
/// getNextContext - If this is a DeclContext that may have other
|
||||
/// DeclContexts that are semantically connected but syntactically
|
||||
/// different, such as C++ namespaces, this routine retrieves the
|
||||
/// next DeclContext in the link. Iteration through the chain of
|
||||
/// DeclContexts should begin at the primary DeclContext and
|
||||
/// continue until this function returns NULL. For example, given:
|
||||
/// @code
|
||||
/// \\brief Collects all of the declaration contexts that are semantically
|
||||
/// connected to this declaration context.
|
||||
///
|
||||
/// For declaration contexts that have multiple semantically connected but
|
||||
/// syntactically distinct contexts, such as C++ namespaces, this routine
|
||||
/// retrieves the complete set of such declaration contexts in source order.
|
||||
/// For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// namespace N {
|
||||
/// int x;
|
||||
/// }
|
||||
/// namespace N {
|
||||
/// int y;
|
||||
/// }
|
||||
/// @endcode
|
||||
/// The first occurrence of namespace N will be the primary
|
||||
/// DeclContext. Its getNextContext will return the second
|
||||
/// occurrence of namespace N.
|
||||
DeclContext *getNextContext();
|
||||
/// \endcode
|
||||
///
|
||||
/// The \c Contexts parameter will contain both definitions of N.
|
||||
///
|
||||
/// \param Contexts Will be cleared and set to the set of declaration
|
||||
/// contexts that are semanticaly connected to this declaration context,
|
||||
/// in source order, including this context (which may be the only result,
|
||||
/// for non-namespace contexts).
|
||||
void collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts);
|
||||
|
||||
/// decl_iterator - Iterates through the declarations stored
|
||||
/// within this context.
|
||||
|
|
@ -1133,13 +1274,13 @@ public:
|
|||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
friend bool operator==(const specific_decl_iterator& x,
|
||||
const specific_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
friend bool operator!=(const specific_decl_iterator& x,
|
||||
const specific_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
|
@ -1207,13 +1348,13 @@ public:
|
|||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
friend bool operator==(const filtered_decl_iterator& x,
|
||||
const filtered_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
friend bool operator!=(const filtered_decl_iterator& x,
|
||||
const filtered_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
|
@ -1232,6 +1373,16 @@ public:
|
|||
/// semantic context via makeDeclVisibleInContext.
|
||||
void addDecl(Decl *D);
|
||||
|
||||
/// @brief Add the declaration D into this context, but suppress
|
||||
/// searches for external declarations with the same name.
|
||||
///
|
||||
/// Although analogous in function to addDecl, this removes an
|
||||
/// important check. This is only useful if the Decl is being
|
||||
/// added in response to an external search; in all other cases,
|
||||
/// addDecl() is the right function to use.
|
||||
/// See the ASTImporter for use cases.
|
||||
void addDeclInternal(Decl *D);
|
||||
|
||||
/// @brief Add the declaration D to this context without modifying
|
||||
/// any lookup tables.
|
||||
///
|
||||
|
|
@ -1265,12 +1416,12 @@ public:
|
|||
/// \brief A simplistic name lookup mechanism that performs name lookup
|
||||
/// into this declaration context without consulting the external source.
|
||||
///
|
||||
/// This function should almost never be used, because it subverts the
|
||||
/// This function should almost never be used, because it subverts the
|
||||
/// usual relationship between a DeclContext and the external source.
|
||||
/// See the ASTImporter for the (few, but important) use cases.
|
||||
void localUncachedLookup(DeclarationName Name,
|
||||
void localUncachedLookup(DeclarationName Name,
|
||||
llvm::SmallVectorImpl<NamedDecl *> &Results);
|
||||
|
||||
|
||||
/// @brief Makes a declaration visible within this context.
|
||||
///
|
||||
/// This routine makes the declaration D visible to name lookup
|
||||
|
|
@ -1285,11 +1436,15 @@ public:
|
|||
/// visible from this context, as determined by
|
||||
/// NamedDecl::declarationReplaces, the previous declaration will be
|
||||
/// replaced with D.
|
||||
///
|
||||
/// @param Recoverable true if it's okay to not add this decl to
|
||||
/// the lookup tables because it can be easily recovered by walking
|
||||
/// the declaration chains.
|
||||
void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true);
|
||||
void makeDeclVisibleInContext(NamedDecl *D);
|
||||
|
||||
/// all_lookups_iterator - An iterator that provides a view over the results
|
||||
/// of looking up every possible name.
|
||||
class all_lookups_iterator;
|
||||
|
||||
all_lookups_iterator lookups_begin() const;
|
||||
|
||||
all_lookups_iterator lookups_end() const;
|
||||
|
||||
/// udir_iterator - Iterates through the using-directives stored
|
||||
/// within this context.
|
||||
|
|
@ -1315,7 +1470,11 @@ public:
|
|||
// Low-level accessors
|
||||
|
||||
/// \brief Retrieve the internal representation of the lookup structure.
|
||||
StoredDeclsMap* getLookupPtr() const { return LookupPtr; }
|
||||
/// This may omit some names if we are lazily building the structure.
|
||||
StoredDeclsMap *getLookupPtr() const { return LookupPtr.getPointer(); }
|
||||
|
||||
/// \brief Ensure the lookup structure is fully-built and return it.
|
||||
StoredDeclsMap *buildLookup();
|
||||
|
||||
/// \brief Whether this DeclContext has external storage containing
|
||||
/// additional declarations that are lexically in this context.
|
||||
|
|
@ -1340,9 +1499,10 @@ public:
|
|||
/// \brief Determine whether the given declaration is stored in the list of
|
||||
/// declarations lexically within this context.
|
||||
bool isDeclInLexicalTraversal(const Decl *D) const {
|
||||
return D && (D->NextDeclInContext || D == FirstDecl || D == LastDecl);
|
||||
return D && (D->NextInContextAndBits.getPointer() || D == FirstDecl ||
|
||||
D == LastDecl);
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Decl *D);
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
#define DECL(NAME, BASE)
|
||||
|
|
@ -1350,16 +1510,26 @@ public:
|
|||
static bool classof(const NAME##Decl *D) { return true; }
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
|
||||
void dumpDeclContext() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
|
||||
|
||||
private:
|
||||
void LoadLexicalDeclsFromExternalStorage() const;
|
||||
|
||||
/// @brief Makes a declaration visible within this context, but
|
||||
/// suppresses searches for external declarations with the same
|
||||
/// name.
|
||||
///
|
||||
/// Analogous to makeDeclVisibleInContext, but for the exclusive
|
||||
/// use of addDeclInternal().
|
||||
void makeDeclVisibleInContextInternal(NamedDecl *D);
|
||||
|
||||
friend class DependentDiagnostic;
|
||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||
|
||||
void buildLookup(DeclContext *DCtx);
|
||||
void makeDeclVisibleInContextImpl(NamedDecl *D);
|
||||
void buildLookupImpl(DeclContext *DCtx);
|
||||
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||
bool Rediscoverable);
|
||||
void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal);
|
||||
};
|
||||
|
||||
inline bool Decl::isTemplateParameter() const {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -16,6 +16,7 @@
|
|||
#define LLVM_CLANG_AST_DECLFRIEND_H
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
@ -35,6 +36,7 @@ namespace clang {
|
|||
///
|
||||
/// The semantic context of a friend decl is its declaring class.
|
||||
class FriendDecl : public Decl {
|
||||
virtual void anchor();
|
||||
public:
|
||||
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
|
||||
|
||||
|
|
@ -77,7 +79,7 @@ public:
|
|||
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, FriendUnion Friend_,
|
||||
SourceLocation FriendL);
|
||||
static FriendDecl *Create(ASTContext &C, EmptyShell Empty);
|
||||
static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
/// If this friend declaration names an (untemplated but possibly
|
||||
/// dependent) type, return the type; otherwise return null. This
|
||||
|
|
@ -99,7 +101,7 @@ public:
|
|||
}
|
||||
|
||||
/// Retrieves the source range for the friend declaration.
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
/* FIXME: consider the case of templates wrt start of range. */
|
||||
if (NamedDecl *ND = getFriendDecl())
|
||||
return SourceRange(getFriendLoc(), ND->getLocEnd());
|
||||
|
|
|
|||
84
include/clang/AST/DeclLookups.h
Normal file
84
include/clang/AST/DeclLookups.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
//===-- DeclLookups.h - Low-level interface to all names in a DC-*- 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 DeclContext::all_lookups_iterator.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLLOOKUPS_H
|
||||
#define LLVM_CLANG_AST_DECLLOOKUPS_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclContextInternals.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// all_lookups_iterator - An iterator that provides a view over the results
|
||||
/// of looking up every possible name.
|
||||
class DeclContext::all_lookups_iterator {
|
||||
StoredDeclsMap::iterator It, End;
|
||||
public:
|
||||
typedef lookup_result value_type;
|
||||
typedef lookup_result reference;
|
||||
typedef lookup_result pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
all_lookups_iterator() {}
|
||||
all_lookups_iterator(StoredDeclsMap::iterator It,
|
||||
StoredDeclsMap::iterator End)
|
||||
: It(It), End(End) {}
|
||||
|
||||
reference operator*() const { return It->second.getLookupResult(); }
|
||||
pointer operator->() const { return It->second.getLookupResult(); }
|
||||
|
||||
all_lookups_iterator& operator++() {
|
||||
// Filter out using directives. They don't belong as results from name
|
||||
// lookup anyways, except as an implementation detail. Users of the API
|
||||
// should not expect to get them (or worse, rely on it).
|
||||
do {
|
||||
++It;
|
||||
} while (It != End &&
|
||||
It->first == DeclarationName::getUsingDirectiveName());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
all_lookups_iterator operator++(int) {
|
||||
all_lookups_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(all_lookups_iterator x, all_lookups_iterator y) {
|
||||
return x.It == y.It;
|
||||
}
|
||||
friend bool operator!=(all_lookups_iterator x, all_lookups_iterator y) {
|
||||
return x.It != y.It;
|
||||
}
|
||||
};
|
||||
|
||||
DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
if (StoredDeclsMap *Map = Primary->buildLookup())
|
||||
return all_lookups_iterator(Map->begin(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
}
|
||||
|
||||
DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
|
||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
if (StoredDeclsMap *Map = Primary->buildLookup())
|
||||
return all_lookups_iterator(Map->end(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -30,12 +30,12 @@ class DeclVisitor {
|
|||
public:
|
||||
RetTy Visit(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
|
||||
#define DECL(DERIVED, BASE) \
|
||||
case Decl::DERIVED: DISPATCH(DERIVED##Decl, DERIVED##Decl);
|
||||
#define ABSTRACT_DECL(DECL)
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
}
|
||||
llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
|
||||
}
|
||||
|
||||
// If the implementation chooses not to implement a certain visit
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/CanonicalType.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> struct DenseMapInfo;
|
||||
|
|
@ -510,8 +511,17 @@ public:
|
|||
/// getEndLoc - Retrieve the location of the last token.
|
||||
SourceLocation getEndLoc() const;
|
||||
/// getSourceRange - The range of the declaration name.
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getBeginLoc(), getEndLoc());
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
SourceLocation BeginLoc = getBeginLoc();
|
||||
SourceLocation EndLoc = getEndLoc();
|
||||
return SourceRange(BeginLoc, EndLoc.isValid() ? EndLoc : BeginLoc);
|
||||
}
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return getBeginLoc();
|
||||
}
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
SourceLocation EndLoc = getEndLoc();
|
||||
return EndLoc.isValid() ? EndLoc : getLocStart();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const {
|
|||
assert(isDependentContext()
|
||||
&& "cannot iterate dependent diagnostics of non-dependent context");
|
||||
const DependentStoredDeclsMap *Map
|
||||
= static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->LookupPtr);
|
||||
= static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
|
||||
|
||||
if (!Map) return ddiag_iterator();
|
||||
return ddiag_iterator(Map->FirstDiagnostic);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -18,6 +18,7 @@
|
|||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/SelectorLocationsKind.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
class IdentifierInfo;
|
||||
|
|
@ -43,7 +44,7 @@ public:
|
|||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, String->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +57,281 @@ public:
|
|||
child_range children() { return child_range(&String, &String+1); }
|
||||
};
|
||||
|
||||
/// ObjCBoolLiteralExpr - Objective-C Boolean Literal.
|
||||
///
|
||||
class ObjCBoolLiteralExpr : public Expr {
|
||||
bool Value;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
ObjCBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) :
|
||||
Expr(ObjCBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false,
|
||||
false, false), Value(val), Loc(l) {}
|
||||
|
||||
explicit ObjCBoolLiteralExpr(EmptyShell Empty)
|
||||
: Expr(ObjCBoolLiteralExprClass, Empty) { }
|
||||
|
||||
bool getValue() const { return Value; }
|
||||
void setValue(bool V) { Value = V; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCBoolLiteralExprClass;
|
||||
}
|
||||
static bool classof(const ObjCBoolLiteralExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// ObjCNumericLiteral - used for objective-c numeric literals;
|
||||
/// as in: @42 or @true (c++/objc++) or @__yes (c/objc)
|
||||
class ObjCNumericLiteral : public Expr {
|
||||
/// Number - expression AST node for the numeric literal
|
||||
Stmt *Number;
|
||||
ObjCMethodDecl *ObjCNumericLiteralMethod;
|
||||
SourceLocation AtLoc;
|
||||
public:
|
||||
ObjCNumericLiteral(Stmt *NL, QualType T, ObjCMethodDecl *method,
|
||||
SourceLocation L)
|
||||
: Expr(ObjCNumericLiteralClass, T, VK_RValue, OK_Ordinary,
|
||||
false, false, false, false), Number(NL),
|
||||
ObjCNumericLiteralMethod(method), AtLoc(L) {}
|
||||
explicit ObjCNumericLiteral(EmptyShell Empty)
|
||||
: Expr(ObjCNumericLiteralClass, Empty) {}
|
||||
|
||||
Expr *getNumber() { return cast<Expr>(Number); }
|
||||
const Expr *getNumber() const { return cast<Expr>(Number); }
|
||||
|
||||
ObjCMethodDecl *getObjCNumericLiteralMethod() const {
|
||||
return ObjCNumericLiteralMethod;
|
||||
}
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, Number->getSourceRange().getEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCNumericLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCNumericLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Number, &Number+1); }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// ObjCArrayLiteral - used for objective-c array containers; as in:
|
||||
/// @[@"Hello", NSApp, [NSNumber numberWithInt:42]];
|
||||
class ObjCArrayLiteral : public Expr {
|
||||
unsigned NumElements;
|
||||
SourceRange Range;
|
||||
ObjCMethodDecl *ArrayWithObjectsMethod;
|
||||
|
||||
ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
|
||||
QualType T, ObjCMethodDecl * Method,
|
||||
SourceRange SR);
|
||||
|
||||
explicit ObjCArrayLiteral(EmptyShell Empty, unsigned NumElements)
|
||||
: Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {}
|
||||
|
||||
public:
|
||||
static ObjCArrayLiteral *Create(ASTContext &C,
|
||||
llvm::ArrayRef<Expr *> Elements,
|
||||
QualType T, ObjCMethodDecl * Method,
|
||||
SourceRange SR);
|
||||
|
||||
static ObjCArrayLiteral *CreateEmpty(ASTContext &C, unsigned NumElements);
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCArrayLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCArrayLiteral *) { return true; }
|
||||
|
||||
/// \brief Retrieve elements of array of literals.
|
||||
Expr **getElements() { return reinterpret_cast<Expr **>(this + 1); }
|
||||
|
||||
/// \brief Retrieve elements of array of literals.
|
||||
const Expr * const *getElements() const {
|
||||
return reinterpret_cast<const Expr * const*>(this + 1);
|
||||
}
|
||||
|
||||
/// getNumElements - Return number of elements of objective-c array literal.
|
||||
unsigned getNumElements() const { return NumElements; }
|
||||
|
||||
/// getExpr - Return the Expr at the specified index.
|
||||
Expr *getElement(unsigned Index) {
|
||||
assert((Index < NumElements) && "Arg access out of range!");
|
||||
return cast<Expr>(getElements()[Index]);
|
||||
}
|
||||
const Expr *getElement(unsigned Index) const {
|
||||
assert((Index < NumElements) && "Arg access out of range!");
|
||||
return cast<Expr>(getElements()[Index]);
|
||||
}
|
||||
|
||||
ObjCMethodDecl *getArrayWithObjectsMethod() const {
|
||||
return ArrayWithObjectsMethod;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
return child_range((Stmt **)getElements(),
|
||||
(Stmt **)getElements() + NumElements);
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// \brief An element in an Objective-C dictionary literal.
|
||||
///
|
||||
struct ObjCDictionaryElement {
|
||||
/// \brief The key for the dictionary element.
|
||||
Expr *Key;
|
||||
|
||||
/// \brief The value of the dictionary element.
|
||||
Expr *Value;
|
||||
|
||||
/// \brief The location of the ellipsis, if this is a pack expansion.
|
||||
SourceLocation EllipsisLoc;
|
||||
|
||||
/// \brief The number of elements this pack expansion will expand to, if
|
||||
/// this is a pack expansion and is known.
|
||||
llvm::Optional<unsigned> NumExpansions;
|
||||
|
||||
/// \brief Determines whether this dictionary element is a pack expansion.
|
||||
bool isPackExpansion() const { return EllipsisLoc.isValid(); }
|
||||
};
|
||||
|
||||
/// ObjCDictionaryLiteral - AST node to represent objective-c dictionary
|
||||
/// literals; as in: @{@"name" : NSUserName(), @"date" : [NSDate date] };
|
||||
class ObjCDictionaryLiteral : public Expr {
|
||||
/// \brief Key/value pair used to store the key and value of a given element.
|
||||
///
|
||||
/// Objects of this type are stored directly after the expression.
|
||||
struct KeyValuePair {
|
||||
Expr *Key;
|
||||
Expr *Value;
|
||||
};
|
||||
|
||||
/// \brief Data that describes an element that is a pack expansion, used if any
|
||||
/// of the elements in the dictionary literal are pack expansions.
|
||||
struct ExpansionData {
|
||||
/// \brief The location of the ellipsis, if this element is a pack
|
||||
/// expansion.
|
||||
SourceLocation EllipsisLoc;
|
||||
|
||||
/// \brief If non-zero, the number of elements that this pack
|
||||
/// expansion will expand to (+1).
|
||||
unsigned NumExpansionsPlusOne;
|
||||
};
|
||||
|
||||
/// \brief The number of elements in this dictionary literal.
|
||||
unsigned NumElements : 31;
|
||||
|
||||
/// \brief Determine whether this dictionary literal has any pack expansions.
|
||||
///
|
||||
/// If the dictionary literal has pack expansions, then there will
|
||||
/// be an array of pack expansion data following the array of
|
||||
/// key/value pairs, which provide the locations of the ellipses (if
|
||||
/// any) and number of elements in the expansion (if known). If
|
||||
/// there are no pack expansions, we optimize away this storage.
|
||||
unsigned HasPackExpansions : 1;
|
||||
|
||||
SourceRange Range;
|
||||
ObjCMethodDecl *DictWithObjectsMethod;
|
||||
|
||||
ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK,
|
||||
bool HasPackExpansions,
|
||||
QualType T, ObjCMethodDecl *method,
|
||||
SourceRange SR);
|
||||
|
||||
explicit ObjCDictionaryLiteral(EmptyShell Empty, unsigned NumElements,
|
||||
bool HasPackExpansions)
|
||||
: Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements),
|
||||
HasPackExpansions(HasPackExpansions) {}
|
||||
|
||||
KeyValuePair *getKeyValues() {
|
||||
return reinterpret_cast<KeyValuePair *>(this + 1);
|
||||
}
|
||||
|
||||
const KeyValuePair *getKeyValues() const {
|
||||
return reinterpret_cast<const KeyValuePair *>(this + 1);
|
||||
}
|
||||
|
||||
ExpansionData *getExpansionData() {
|
||||
if (!HasPackExpansions)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<ExpansionData *>(getKeyValues() + NumElements);
|
||||
}
|
||||
|
||||
const ExpansionData *getExpansionData() const {
|
||||
if (!HasPackExpansions)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<const ExpansionData *>(getKeyValues()+NumElements);
|
||||
}
|
||||
|
||||
public:
|
||||
static ObjCDictionaryLiteral *Create(ASTContext &C,
|
||||
ArrayRef<ObjCDictionaryElement> VK,
|
||||
bool HasPackExpansions,
|
||||
QualType T, ObjCMethodDecl *method,
|
||||
SourceRange SR);
|
||||
|
||||
static ObjCDictionaryLiteral *CreateEmpty(ASTContext &C,
|
||||
unsigned NumElements,
|
||||
bool HasPackExpansions);
|
||||
|
||||
/// getNumElements - Return number of elements of objective-c dictionary
|
||||
/// literal.
|
||||
unsigned getNumElements() const { return NumElements; }
|
||||
|
||||
ObjCDictionaryElement getKeyValueElement(unsigned Index) const {
|
||||
assert((Index < NumElements) && "Arg access out of range!");
|
||||
const KeyValuePair &KV = getKeyValues()[Index];
|
||||
ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(),
|
||||
llvm::Optional<unsigned>() };
|
||||
if (HasPackExpansions) {
|
||||
const ExpansionData &Expansion = getExpansionData()[Index];
|
||||
Result.EllipsisLoc = Expansion.EllipsisLoc;
|
||||
if (Expansion.NumExpansionsPlusOne > 0)
|
||||
Result.NumExpansions = Expansion.NumExpansionsPlusOne - 1;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
ObjCMethodDecl *getDictWithObjectsMethod() const
|
||||
{ return DictWithObjectsMethod; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCDictionaryLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCDictionaryLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
// Note: we're taking advantage of the layout of the KeyValuePair struct
|
||||
// here. If that struct changes, this code will need to change as well.
|
||||
return child_range(reinterpret_cast<Stmt **>(this + 1),
|
||||
reinterpret_cast<Stmt **>(this + 1) + NumElements * 2);
|
||||
}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
};
|
||||
|
||||
|
||||
/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type
|
||||
/// and behavior as StringLiteral except that the string initializer is obtained
|
||||
/// from ASTContext with the encoding type as an argument.
|
||||
|
|
@ -87,7 +363,7 @@ public:
|
|||
EncodedType = EncType;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +397,7 @@ public:
|
|||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +437,7 @@ public:
|
|||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
|
|
@ -176,9 +452,9 @@ public:
|
|||
|
||||
/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
|
||||
class ObjCIvarRefExpr : public Expr {
|
||||
class ObjCIvarDecl *D;
|
||||
SourceLocation Loc;
|
||||
ObjCIvarDecl *D;
|
||||
Stmt *Base;
|
||||
SourceLocation Loc;
|
||||
bool IsArrow:1; // True if this is "X->F", false if this is "X.F".
|
||||
bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
|
||||
|
||||
|
|
@ -190,7 +466,7 @@ public:
|
|||
/*TypeDependent=*/false, base->isValueDependent(),
|
||||
base->isInstantiationDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
D(d), Loc(l), Base(base), IsArrow(arrow), IsFreeIvar(freeIvar) {}
|
||||
D(d), Base(base), Loc(l), IsArrow(arrow), IsFreeIvar(freeIvar) {}
|
||||
|
||||
explicit ObjCIvarRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCIvarRefExprClass, Empty) {}
|
||||
|
|
@ -211,7 +487,7 @@ public:
|
|||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return isFreeIvar() ? SourceRange(Loc)
|
||||
: SourceRange(getBase()->getLocStart(), Loc);
|
||||
}
|
||||
|
|
@ -227,7 +503,6 @@ public:
|
|||
|
||||
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
|
||||
/// property.
|
||||
///
|
||||
class ObjCPropertyRefExpr : public Expr {
|
||||
private:
|
||||
/// If the bool is true, this is an implicit property reference; the
|
||||
|
|
@ -235,7 +510,23 @@ private:
|
|||
/// if the bool is false, this is an explicit property reference;
|
||||
/// the pointer is an ObjCPropertyDecl and Setter is always null.
|
||||
llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter;
|
||||
ObjCMethodDecl *Setter;
|
||||
|
||||
/// \brief Indicates whether the property reference will result in a message
|
||||
/// to the getter, the setter, or both.
|
||||
/// This applies to both implicit and explicit property references.
|
||||
enum MethodRefFlags {
|
||||
MethodRef_None = 0,
|
||||
MethodRef_Getter = 0x1,
|
||||
MethodRef_Setter = 0x2
|
||||
};
|
||||
|
||||
/// \brief Contains the Setter method pointer and MethodRefFlags bit flags.
|
||||
llvm::PointerIntPair<ObjCMethodDecl *, 2, unsigned> SetterAndMethodRefFlags;
|
||||
|
||||
// FIXME: Maybe we should store the property identifier here,
|
||||
// because it's not rederivable from the other data when there's an
|
||||
// implicit property with no getter (because the 'foo' -> 'setFoo:'
|
||||
// transformation is lossy on the first character).
|
||||
|
||||
SourceLocation IdLoc;
|
||||
|
||||
|
|
@ -253,8 +544,9 @@ public:
|
|||
/*TypeDependent=*/false, base->isValueDependent(),
|
||||
base->isInstantiationDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
PropertyOrGetter(PD, false), Setter(0),
|
||||
PropertyOrGetter(PD, false), SetterAndMethodRefFlags(),
|
||||
IdLoc(l), ReceiverLoc(), Receiver(base) {
|
||||
assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
|
|
@ -263,8 +555,9 @@ public:
|
|||
: Expr(ObjCPropertyRefExprClass, t, VK, OK,
|
||||
/*TypeDependent=*/false, false, st->isInstantiationDependentType(),
|
||||
st->containsUnexpandedParameterPack()),
|
||||
PropertyOrGetter(PD, false), Setter(0),
|
||||
PropertyOrGetter(PD, false), SetterAndMethodRefFlags(),
|
||||
IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
|
||||
assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
|
|
@ -273,8 +566,9 @@ public:
|
|||
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false,
|
||||
Base->isValueDependent(), Base->isInstantiationDependent(),
|
||||
Base->containsUnexpandedParameterPack()),
|
||||
PropertyOrGetter(Getter, true), Setter(Setter),
|
||||
PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
|
||||
IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
|
||||
assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
|
|
@ -282,8 +576,9 @@ public:
|
|||
SourceLocation IdLoc,
|
||||
SourceLocation SuperLoc, QualType SuperTy)
|
||||
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
|
||||
PropertyOrGetter(Getter, true), Setter(Setter),
|
||||
PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
|
||||
IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) {
|
||||
assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
|
||||
}
|
||||
|
||||
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
|
|
@ -291,8 +586,9 @@ public:
|
|||
SourceLocation IdLoc,
|
||||
SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver)
|
||||
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
|
||||
PropertyOrGetter(Getter, true), Setter(Setter),
|
||||
PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
|
||||
IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) {
|
||||
assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
|
||||
}
|
||||
|
||||
explicit ObjCPropertyRefExpr(EmptyShell Empty)
|
||||
|
|
@ -313,7 +609,7 @@ public:
|
|||
|
||||
ObjCMethodDecl *getImplicitPropertySetter() const {
|
||||
assert(isImplicitProperty());
|
||||
return Setter;
|
||||
return SetterAndMethodRefFlags.getPointer();
|
||||
}
|
||||
|
||||
Selector getGetterSelector() const {
|
||||
|
|
@ -328,6 +624,28 @@ public:
|
|||
return getExplicitProperty()->getSetterName();
|
||||
}
|
||||
|
||||
/// \brief True if the property reference will result in a message to the
|
||||
/// getter.
|
||||
/// This applies to both implicit and explicit property references.
|
||||
bool isMessagingGetter() const {
|
||||
return SetterAndMethodRefFlags.getInt() & MethodRef_Getter;
|
||||
}
|
||||
|
||||
/// \brief True if the property reference will result in a message to the
|
||||
/// setter.
|
||||
/// This applies to both implicit and explicit property references.
|
||||
bool isMessagingSetter() const {
|
||||
return SetterAndMethodRefFlags.getInt() & MethodRef_Setter;
|
||||
}
|
||||
|
||||
void setIsMessagingGetter(bool val = true) {
|
||||
setMethodRefFlag(MethodRef_Getter, val);
|
||||
}
|
||||
|
||||
void setIsMessagingSetter(bool val = true) {
|
||||
setMethodRefFlag(MethodRef_Setter, val);
|
||||
}
|
||||
|
||||
const Expr *getBase() const {
|
||||
return cast<Expr>(Receiver.get<Stmt*>());
|
||||
}
|
||||
|
|
@ -348,14 +666,15 @@ public:
|
|||
if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
|
||||
ResultType = Getter->getResultType();
|
||||
else
|
||||
ResultType = getType();
|
||||
ResultType = PDecl->getType();
|
||||
} else {
|
||||
const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
|
||||
ResultType = Getter->getResultType(); // with reference!
|
||||
if (Getter)
|
||||
ResultType = Getter->getResultType(); // with reference!
|
||||
}
|
||||
return ResultType;
|
||||
}
|
||||
|
||||
|
||||
QualType getSetterArgType() const {
|
||||
QualType ArgType;
|
||||
if (isImplicitProperty()) {
|
||||
|
|
@ -381,7 +700,7 @@ public:
|
|||
bool isSuperReceiver() const { return Receiver.is<const Type*>(); }
|
||||
bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange((isObjectReceiver() ? getBase()->getLocStart()
|
||||
: getReceiverLocation()),
|
||||
IdLoc);
|
||||
|
|
@ -403,15 +722,19 @@ public:
|
|||
|
||||
private:
|
||||
friend class ASTStmtReader;
|
||||
void setExplicitProperty(ObjCPropertyDecl *D) {
|
||||
friend class ASTStmtWriter;
|
||||
void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) {
|
||||
PropertyOrGetter.setPointer(D);
|
||||
PropertyOrGetter.setInt(false);
|
||||
Setter = 0;
|
||||
SetterAndMethodRefFlags.setPointer(0);
|
||||
SetterAndMethodRefFlags.setInt(methRefFlags);
|
||||
}
|
||||
void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter) {
|
||||
void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
unsigned methRefFlags) {
|
||||
PropertyOrGetter.setPointer(Getter);
|
||||
PropertyOrGetter.setInt(true);
|
||||
this->Setter = Setter;
|
||||
SetterAndMethodRefFlags.setPointer(Setter);
|
||||
SetterAndMethodRefFlags.setInt(methRefFlags);
|
||||
}
|
||||
void setBase(Expr *Base) { Receiver = Base; }
|
||||
void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); }
|
||||
|
|
@ -419,7 +742,98 @@ private:
|
|||
|
||||
void setLocation(SourceLocation L) { IdLoc = L; }
|
||||
void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; }
|
||||
|
||||
void setMethodRefFlag(MethodRefFlags flag, bool val) {
|
||||
unsigned f = SetterAndMethodRefFlags.getInt();
|
||||
if (val)
|
||||
f |= flag;
|
||||
else
|
||||
f &= ~flag;
|
||||
SetterAndMethodRefFlags.setInt(f);
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCSubscriptRefExpr - used for array and dictionary subscripting.
|
||||
/// array[4] = array[3]; dictionary[key] = dictionary[alt_key];
|
||||
///
|
||||
class ObjCSubscriptRefExpr : public Expr {
|
||||
// Location of ']' in an indexing expression.
|
||||
SourceLocation RBracket;
|
||||
// array/dictionary base expression.
|
||||
// for arrays, this is a numeric expression. For dictionaries, this is
|
||||
// an objective-c object pointer expression.
|
||||
enum { BASE, KEY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
|
||||
ObjCMethodDecl *GetAtIndexMethodDecl;
|
||||
|
||||
// For immutable objects this is null. When ObjCSubscriptRefExpr is to read
|
||||
// an indexed object this is null too.
|
||||
ObjCMethodDecl *SetAtIndexMethodDecl;
|
||||
|
||||
public:
|
||||
|
||||
ObjCSubscriptRefExpr(Expr *base, Expr *key, QualType T,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
ObjCMethodDecl *getMethod,
|
||||
ObjCMethodDecl *setMethod, SourceLocation RB)
|
||||
: Expr(ObjCSubscriptRefExprClass, T, VK, OK,
|
||||
base->isTypeDependent() || key->isTypeDependent(),
|
||||
base->isValueDependent() || key->isValueDependent(),
|
||||
base->isInstantiationDependent() || key->isInstantiationDependent(),
|
||||
(base->containsUnexpandedParameterPack() ||
|
||||
key->containsUnexpandedParameterPack())),
|
||||
RBracket(RB),
|
||||
GetAtIndexMethodDecl(getMethod),
|
||||
SetAtIndexMethodDecl(setMethod)
|
||||
{SubExprs[BASE] = base; SubExprs[KEY] = key;}
|
||||
|
||||
explicit ObjCSubscriptRefExpr(EmptyShell Empty)
|
||||
: Expr(ObjCSubscriptRefExprClass, Empty) {}
|
||||
|
||||
static ObjCSubscriptRefExpr *Create(ASTContext &C,
|
||||
Expr *base,
|
||||
Expr *key, QualType T,
|
||||
ObjCMethodDecl *getMethod,
|
||||
ObjCMethodDecl *setMethod,
|
||||
SourceLocation RB);
|
||||
|
||||
SourceLocation getRBracket() const { return RBracket; }
|
||||
void setRBracket(SourceLocation RB) { RBracket = RB; }
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(SubExprs[BASE]->getLocStart(), RBracket);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSubscriptRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSubscriptRefExpr *) { return true; }
|
||||
|
||||
Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); }
|
||||
void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; }
|
||||
|
||||
Expr *getKeyExpr() const { return cast<Expr>(SubExprs[KEY]); }
|
||||
void setKeyExpr(Stmt *S) { SubExprs[KEY] = S; }
|
||||
|
||||
ObjCMethodDecl *getAtIndexMethodDecl() const {
|
||||
return GetAtIndexMethodDecl;
|
||||
}
|
||||
|
||||
ObjCMethodDecl *setAtIndexMethodDecl() const {
|
||||
return SetAtIndexMethodDecl;
|
||||
}
|
||||
|
||||
bool isArraySubscriptRefExpr() const {
|
||||
return getKeyExpr()->getType()->isIntegralOrEnumerationType();
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(SubExprs, SubExprs+END_EXPR);
|
||||
}
|
||||
private:
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
|
||||
/// \brief An expression that sends a message to the given Objective-C
|
||||
/// object or class.
|
||||
|
|
@ -477,7 +891,11 @@ class ObjCMessageExpr : public Expr {
|
|||
/// \brief Whether this message send is a "delegate init call",
|
||||
/// i.e. a call of an init method on self from within an init method.
|
||||
unsigned IsDelegateInitCall : 1;
|
||||
|
||||
|
||||
/// \brief Whether this message send was implicitly generated by
|
||||
/// the implementation rather than explicitly written by the user.
|
||||
unsigned IsImplicit : 1;
|
||||
|
||||
/// \brief Whether the locations of the selector identifiers are in a
|
||||
/// "standard" position, a enum SelectorLocationsKind.
|
||||
unsigned SelLocsKind : 2;
|
||||
|
|
@ -492,7 +910,7 @@ class ObjCMessageExpr : public Expr {
|
|||
|
||||
ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
|
||||
: Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0),
|
||||
HasMethod(0), IsDelegateInitCall(0) {
|
||||
HasMethod(0), IsDelegateInitCall(0), IsImplicit(0), SelLocsKind(0) {
|
||||
setNumArgs(NumArgs);
|
||||
}
|
||||
|
||||
|
|
@ -506,7 +924,8 @@ class ObjCMessageExpr : public Expr {
|
|||
SelectorLocationsKind SelLocsK,
|
||||
ObjCMethodDecl *Method,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
SourceLocation RBracLoc,
|
||||
bool isImplicit);
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
TypeSourceInfo *Receiver,
|
||||
|
|
@ -515,7 +934,8 @@ class ObjCMessageExpr : public Expr {
|
|||
SelectorLocationsKind SelLocsK,
|
||||
ObjCMethodDecl *Method,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
SourceLocation RBracLoc,
|
||||
bool isImplicit);
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
Expr *Receiver,
|
||||
|
|
@ -524,7 +944,8 @@ class ObjCMessageExpr : public Expr {
|
|||
SelectorLocationsKind SelLocsK,
|
||||
ObjCMethodDecl *Method,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
SourceLocation RBracLoc,
|
||||
bool isImplicit);
|
||||
|
||||
void initArgsAndSelLocs(ArrayRef<Expr *> Args,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
|
|
@ -625,7 +1046,8 @@ public:
|
|||
ArrayRef<SourceLocation> SelLocs,
|
||||
ObjCMethodDecl *Method,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
SourceLocation RBracLoc,
|
||||
bool isImplicit);
|
||||
|
||||
/// \brief Create a class message send.
|
||||
///
|
||||
|
|
@ -660,7 +1082,8 @@ public:
|
|||
ArrayRef<SourceLocation> SelLocs,
|
||||
ObjCMethodDecl *Method,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
SourceLocation RBracLoc,
|
||||
bool isImplicit);
|
||||
|
||||
/// \brief Create an instance message send.
|
||||
///
|
||||
|
|
@ -695,7 +1118,8 @@ public:
|
|||
ArrayRef<SourceLocation> SeLocs,
|
||||
ObjCMethodDecl *Method,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
SourceLocation RBracLoc,
|
||||
bool isImplicit);
|
||||
|
||||
/// \brief Create an empty Objective-C message expression, to be
|
||||
/// filled in by subsequent calls.
|
||||
|
|
@ -708,6 +1132,11 @@ public:
|
|||
unsigned NumArgs,
|
||||
unsigned NumStoredSelLocs);
|
||||
|
||||
/// \brief Indicates whether the message send was implicitly
|
||||
/// generated by the implementation. If false, it was written explicitly
|
||||
/// in the source code.
|
||||
bool isImplicit() const { return IsImplicit; }
|
||||
|
||||
/// \brief Determine the kind of receiver that this message is being
|
||||
/// sent to.
|
||||
ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; }
|
||||
|
|
@ -877,7 +1306,11 @@ public:
|
|||
SourceLocation getLeftLoc() const { return LBracLoc; }
|
||||
SourceLocation getRightLoc() const { return RBracLoc; }
|
||||
|
||||
SourceLocation getSelectorStartLoc() const { return getSelectorLoc(0); }
|
||||
SourceLocation getSelectorStartLoc() const {
|
||||
if (isImplicit())
|
||||
return getLocStart();
|
||||
return getSelectorLoc(0);
|
||||
}
|
||||
SourceLocation getSelectorLoc(unsigned Index) const {
|
||||
assert(Index < getNumSelectorLocs() && "Index out of range!");
|
||||
if (hasStandardSelLocs())
|
||||
|
|
@ -892,6 +1325,8 @@ public:
|
|||
void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const;
|
||||
|
||||
unsigned getNumSelectorLocs() const {
|
||||
if (isImplicit())
|
||||
return 0;
|
||||
Selector Sel = getSelector();
|
||||
if (Sel.isUnarySelector())
|
||||
return 1;
|
||||
|
|
@ -902,7 +1337,7 @@ public:
|
|||
LBracLoc = R.getBegin();
|
||||
RBracLoc = R.getEnd();
|
||||
}
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(LBracLoc, RBracLoc);
|
||||
}
|
||||
|
||||
|
|
@ -965,11 +1400,11 @@ public:
|
|||
SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; }
|
||||
void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getBase()->getLocStart(), IsaMemberLoc);
|
||||
}
|
||||
|
||||
SourceLocation getExprLoc() const { return IsaMemberLoc; }
|
||||
SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIsaExprClass;
|
||||
|
|
@ -1038,8 +1473,12 @@ public:
|
|||
child_range children() { return child_range(&Operand, &Operand+1); }
|
||||
|
||||
// Source locations are determined by the subexpression.
|
||||
SourceRange getSourceRange() const { return Operand->getSourceRange(); }
|
||||
SourceLocation getExprLoc() const { return getSubExpr()->getExprLoc(); }
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return Operand->getSourceRange();
|
||||
}
|
||||
SourceLocation getExprLoc() const LLVM_READONLY {
|
||||
return getSubExpr()->getExprLoc();
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *s) {
|
||||
return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass;
|
||||
|
|
@ -1086,7 +1525,7 @@ public:
|
|||
/// \brief The location of the bridge keyword.
|
||||
SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(LParenLoc, getSubExpr()->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
@ -153,6 +155,12 @@ public:
|
|||
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
|
||||
}
|
||||
|
||||
/// \brief Get the decls that are contained in a file in the Offset/Length
|
||||
/// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
|
||||
/// a range.
|
||||
virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
|
||||
SmallVectorImpl<Decl *> &Decls) {}
|
||||
|
||||
/// \brief Gives the external AST source an opportunity to complete
|
||||
/// an incomplete type.
|
||||
virtual void CompleteType(TagDecl *Tag) {}
|
||||
|
|
@ -190,6 +198,44 @@ public:
|
|||
/// The default implementation of this method is a no-op.
|
||||
virtual void PrintStats();
|
||||
|
||||
|
||||
/// \brief Perform layout on the given record.
|
||||
///
|
||||
/// This routine allows the external AST source to provide an specific
|
||||
/// layout for a record, overriding the layout that would normally be
|
||||
/// constructed. It is intended for clients who receive specific layout
|
||||
/// details rather than source code (such as LLDB). The client is expected
|
||||
/// to fill in the field offsets, base offsets, virtual base offsets, and
|
||||
/// complete object size.
|
||||
///
|
||||
/// \param Record The record whose layout is being requested.
|
||||
///
|
||||
/// \param Size The final size of the record, in bits.
|
||||
///
|
||||
/// \param Alignment The final alignment of the record, in bits.
|
||||
///
|
||||
/// \param FieldOffsets The offset of each of the fields within the record,
|
||||
/// expressed in bits. All of the fields must be provided with offsets.
|
||||
///
|
||||
/// \param BaseOffsets The offset of each of the direct, non-virtual base
|
||||
/// classes. If any bases are not given offsets, the bases will be laid
|
||||
/// out according to the ABI.
|
||||
///
|
||||
/// \param VirtualBaseOffsets The offset of each of the virtual base classes
|
||||
/// (either direct or not). If any bases are not given offsets, the bases will be laid
|
||||
/// out according to the ABI.
|
||||
///
|
||||
/// \returns true if the record layout was provided, false otherwise.
|
||||
virtual bool
|
||||
layoutRecordType(const RecordDecl *Record,
|
||||
uint64_t &Size, uint64_t &Alignment,
|
||||
llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
|
||||
llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
|
||||
llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Queries for performance analysis.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
|||
36
include/clang/AST/LambdaMangleContext.h
Normal file
36
include/clang/AST/LambdaMangleContext.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the LambdaMangleContext interface, which keeps track of
|
||||
// the Itanium C++ ABI mangling numbers for lambda expressions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H
|
||||
#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CXXMethodDecl;
|
||||
class FunctionProtoType;
|
||||
|
||||
/// \brief Keeps track of the mangled names of lambda expressions within a
|
||||
/// particular context.
|
||||
class LambdaMangleContext {
|
||||
llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers;
|
||||
|
||||
public:
|
||||
/// \brief Retrieve the mangling number of a new lambda expression with the
|
||||
/// given call operator within this lambda context.
|
||||
unsigned getManglingNumber(CXXMethodDecl *CallOperator);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
|
|
@ -58,12 +58,14 @@ public:
|
|||
|
||||
private:
|
||||
StringRef String;
|
||||
llvm::SmallString<256> Buffer;
|
||||
SmallString<256> Buffer;
|
||||
};
|
||||
|
||||
/// MangleContext - Context for tracking state which persists across multiple
|
||||
/// calls to the C++ name mangler.
|
||||
class MangleContext {
|
||||
virtual void anchor();
|
||||
|
||||
ASTContext &Context;
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
|
|
|
|||
152
include/clang/AST/NSAPI.h
Normal file
152
include/clang/AST/NSAPI.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
//===--- NSAPI.h - NSFoundation APIs ----------------------------*- 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_AST_NSAPI_H
|
||||
#define LLVM_CLANG_AST_NSAPI_H
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
|
||||
// \brief Provides info and caches identifiers/selectors for NSFoundation API.
|
||||
class NSAPI {
|
||||
public:
|
||||
explicit NSAPI(ASTContext &Ctx);
|
||||
|
||||
ASTContext &getASTContext() const { return Ctx; }
|
||||
|
||||
enum NSClassIdKindKind {
|
||||
ClassId_NSObject,
|
||||
ClassId_NSString,
|
||||
ClassId_NSArray,
|
||||
ClassId_NSMutableArray,
|
||||
ClassId_NSDictionary,
|
||||
ClassId_NSMutableDictionary,
|
||||
ClassId_NSNumber
|
||||
};
|
||||
static const unsigned NumClassIds = 7;
|
||||
|
||||
enum NSStringMethodKind {
|
||||
NSStr_stringWithString,
|
||||
NSStr_initWithString
|
||||
};
|
||||
static const unsigned NumNSStringMethods = 2;
|
||||
|
||||
IdentifierInfo *getNSClassId(NSClassIdKindKind K) const;
|
||||
|
||||
/// \brief The Objective-C NSString selectors.
|
||||
Selector getNSStringSelector(NSStringMethodKind MK) const;
|
||||
|
||||
/// \brief Enumerates the NSArray methods used to generate literals.
|
||||
enum NSArrayMethodKind {
|
||||
NSArr_array,
|
||||
NSArr_arrayWithArray,
|
||||
NSArr_arrayWithObject,
|
||||
NSArr_arrayWithObjects,
|
||||
NSArr_arrayWithObjectsCount,
|
||||
NSArr_initWithArray,
|
||||
NSArr_initWithObjects,
|
||||
NSArr_objectAtIndex,
|
||||
NSMutableArr_replaceObjectAtIndex
|
||||
};
|
||||
static const unsigned NumNSArrayMethods = 9;
|
||||
|
||||
/// \brief The Objective-C NSArray selectors.
|
||||
Selector getNSArraySelector(NSArrayMethodKind MK) const;
|
||||
|
||||
/// \brief Return NSArrayMethodKind if \arg Sel is such a selector.
|
||||
llvm::Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
|
||||
|
||||
/// \brief Enumerates the NSDictionary methods used to generate literals.
|
||||
enum NSDictionaryMethodKind {
|
||||
NSDict_dictionary,
|
||||
NSDict_dictionaryWithDictionary,
|
||||
NSDict_dictionaryWithObjectForKey,
|
||||
NSDict_dictionaryWithObjectsForKeys,
|
||||
NSDict_dictionaryWithObjectsForKeysCount,
|
||||
NSDict_dictionaryWithObjectsAndKeys,
|
||||
NSDict_initWithDictionary,
|
||||
NSDict_initWithObjectsAndKeys,
|
||||
NSDict_objectForKey,
|
||||
NSMutableDict_setObjectForKey
|
||||
};
|
||||
static const unsigned NumNSDictionaryMethods = 10;
|
||||
|
||||
/// \brief The Objective-C NSDictionary selectors.
|
||||
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
|
||||
|
||||
/// \brief Return NSDictionaryMethodKind if \arg Sel is such a selector.
|
||||
llvm::Optional<NSDictionaryMethodKind>
|
||||
getNSDictionaryMethodKind(Selector Sel);
|
||||
|
||||
/// \brief Enumerates the NSNumber methods used to generate literals.
|
||||
enum NSNumberLiteralMethodKind {
|
||||
NSNumberWithChar,
|
||||
NSNumberWithUnsignedChar,
|
||||
NSNumberWithShort,
|
||||
NSNumberWithUnsignedShort,
|
||||
NSNumberWithInt,
|
||||
NSNumberWithUnsignedInt,
|
||||
NSNumberWithLong,
|
||||
NSNumberWithUnsignedLong,
|
||||
NSNumberWithLongLong,
|
||||
NSNumberWithUnsignedLongLong,
|
||||
NSNumberWithFloat,
|
||||
NSNumberWithDouble,
|
||||
NSNumberWithBool,
|
||||
NSNumberWithInteger,
|
||||
NSNumberWithUnsignedInteger
|
||||
};
|
||||
static const unsigned NumNSNumberLiteralMethods = 15;
|
||||
|
||||
/// \brief The Objective-C NSNumber selectors used to create NSNumber literals.
|
||||
/// \param Instance if true it will return the selector for the init* method
|
||||
/// otherwise it will return the selector for the number* method.
|
||||
Selector getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
|
||||
bool Instance) const;
|
||||
|
||||
bool isNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
|
||||
Selector Sel) const {
|
||||
return Sel == getNSNumberLiteralSelector(MK, false) ||
|
||||
Sel == getNSNumberLiteralSelector(MK, true);
|
||||
}
|
||||
|
||||
/// \brief Return NSNumberLiteralMethodKind if \arg Sel is such a selector.
|
||||
llvm::Optional<NSNumberLiteralMethodKind>
|
||||
getNSNumberLiteralMethodKind(Selector Sel) const;
|
||||
|
||||
/// \brief Determine the appropriate NSNumber factory method kind for a
|
||||
/// literal of the given type.
|
||||
static llvm::Optional<NSNumberLiteralMethodKind>
|
||||
getNSNumberFactoryMethodKind(QualType T);
|
||||
|
||||
private:
|
||||
ASTContext &Ctx;
|
||||
|
||||
mutable IdentifierInfo *ClassIds[NumClassIds];
|
||||
|
||||
mutable Selector NSStringSelectors[NumNSStringMethods];
|
||||
|
||||
/// \brief The selectors for Objective-C NSArray methods.
|
||||
mutable Selector NSArraySelectors[NumNSArrayMethods];
|
||||
|
||||
/// \brief The selectors for Objective-C NSDictionary methods.
|
||||
mutable Selector NSDictionarySelectors[NumNSDictionaryMethods];
|
||||
|
||||
/// \brief The Objective-C NSNumber selectors used to create NSNumber literals.
|
||||
mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods];
|
||||
mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_NSAPI_H
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
@ -36,8 +37,9 @@ class LangOptions;
|
|||
/// namespaces. For example, "foo::" in "foo::x" is a nested name
|
||||
/// specifier. Nested name specifiers are made up of a sequence of
|
||||
/// specifiers, each of which can be a namespace, type, identifier
|
||||
/// (for dependent names), or the global specifier ('::', must be the
|
||||
/// first specifier).
|
||||
/// (for dependent names), decltype specifier, or the global specifier ('::').
|
||||
/// The last two specifiers can only appear at the start of a
|
||||
/// nested-namespace-specifier.
|
||||
class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
|
||||
/// \brief Enumeration describing
|
||||
|
|
@ -95,7 +97,8 @@ private:
|
|||
Specifier(Other.Specifier) {
|
||||
}
|
||||
|
||||
NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not implement
|
||||
NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not
|
||||
// implement
|
||||
|
||||
/// \brief Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
|
|
@ -221,12 +224,12 @@ class NestedNameSpecifierLoc {
|
|||
public:
|
||||
/// \brief Construct an empty nested-name-specifier.
|
||||
NestedNameSpecifierLoc() : Qualifier(0), Data(0) { }
|
||||
|
||||
|
||||
/// \brief Construct a nested-name-specifier with source location information
|
||||
/// from
|
||||
/// from
|
||||
NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data)
|
||||
: Qualifier(Qualifier), Data(Data) { }
|
||||
|
||||
|
||||
/// \brief Evalutes true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
operator bool() const { return Qualifier; }
|
||||
|
|
@ -239,14 +242,14 @@ public:
|
|||
|
||||
/// \brief Retrieve the opaque pointer that refers to source-location data.
|
||||
void *getOpaqueData() const { return Data; }
|
||||
|
||||
|
||||
/// \brief Retrieve the source range covering the entirety of this
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c ::std::vector<int>::, the returned source range would cover
|
||||
/// from the initial '::' to the last '::'.
|
||||
SourceRange getSourceRange() const;
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
/// \brief Retrieve the source range covering just the last part of
|
||||
/// this nested-name-specifier, not including the prefix.
|
||||
|
|
@ -258,25 +261,25 @@ public:
|
|||
|
||||
/// \brief Retrieve the location of the beginning of this
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getBeginLoc() const {
|
||||
SourceLocation getBeginLoc() const {
|
||||
return getSourceRange().getBegin();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the end of this
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getEndLoc() const {
|
||||
SourceLocation getEndLoc() const {
|
||||
return getSourceRange().getEnd();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the beginning of this
|
||||
/// component of the nested-name-specifier.
|
||||
SourceLocation getLocalBeginLoc() const {
|
||||
SourceLocation getLocalBeginLoc() const {
|
||||
return getLocalSourceRange().getBegin();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the location of the end of this component of the
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getLocalEndLoc() const {
|
||||
SourceLocation getLocalEndLoc() const {
|
||||
return getLocalSourceRange().getEnd();
|
||||
}
|
||||
|
||||
|
|
@ -300,13 +303,13 @@ public:
|
|||
/// \brief Determines the data length for the entire
|
||||
/// nested-name-specifier.
|
||||
unsigned getDataLength() const { return getDataLength(Qualifier); }
|
||||
|
||||
friend bool operator==(NestedNameSpecifierLoc X,
|
||||
|
||||
friend bool operator==(NestedNameSpecifierLoc X,
|
||||
NestedNameSpecifierLoc Y) {
|
||||
return X.Qualifier == Y.Qualifier && X.Data == Y.Data;
|
||||
}
|
||||
|
||||
friend bool operator!=(NestedNameSpecifierLoc X,
|
||||
friend bool operator!=(NestedNameSpecifierLoc X,
|
||||
NestedNameSpecifierLoc Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
|
|
@ -316,39 +319,43 @@ public:
|
|||
/// with source-location information for all of the components of the
|
||||
/// nested-name-specifier.
|
||||
class NestedNameSpecifierLocBuilder {
|
||||
/// \brief The current representation of the nested-name-specifier we're
|
||||
/// \brief The current representation of the nested-name-specifier we're
|
||||
/// building.
|
||||
NestedNameSpecifier *Representation;
|
||||
|
||||
|
||||
/// \brief Buffer used to store source-location information for the
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// Note that we explicitly manage the buffer (rather than using a
|
||||
/// Note that we explicitly manage the buffer (rather than using a
|
||||
/// SmallVector) because \c Declarator expects it to be possible to memcpy()
|
||||
/// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
|
||||
char *Buffer;
|
||||
|
||||
|
||||
/// \brief The size of the buffer used to store source-location information
|
||||
/// for the nested-name-specifier.
|
||||
unsigned BufferSize;
|
||||
|
||||
/// \brief The capacity of the buffer used to store source-location
|
||||
|
||||
/// \brief The capacity of the buffer used to store source-location
|
||||
/// information for the nested-name-specifier.
|
||||
unsigned BufferCapacity;
|
||||
|
||||
public:
|
||||
NestedNameSpecifierLocBuilder();
|
||||
|
||||
NestedNameSpecifierLocBuilder()
|
||||
: Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { }
|
||||
|
||||
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
|
||||
NestedNameSpecifierLocBuilder &
|
||||
operator=(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
~NestedNameSpecifierLocBuilder();
|
||||
|
||||
|
||||
~NestedNameSpecifierLocBuilder() {
|
||||
if (BufferCapacity)
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the representation of the nested-name-specifier.
|
||||
NestedNameSpecifier *getRepresentation() const { return Representation; }
|
||||
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'type::'.
|
||||
///
|
||||
|
|
@ -362,8 +369,8 @@ public:
|
|||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL,
|
||||
SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'identifier::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
|
|
@ -376,8 +383,8 @@ public:
|
|||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, IdentifierInfo *Identifier,
|
||||
SourceLocation IdentifierLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'namespace::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
|
|
@ -390,8 +397,8 @@ public:
|
|||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, NamespaceDecl *Namespace,
|
||||
SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
|
||||
/// \brief Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'namespace-alias::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
|
|
@ -399,35 +406,35 @@ public:
|
|||
///
|
||||
/// \param Alias The namespace alias.
|
||||
///
|
||||
/// \param AliasLoc The location of the namespace alias
|
||||
/// \param AliasLoc The location of the namespace alias
|
||||
/// name.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
|
||||
SourceLocation AliasLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
|
||||
/// \brief Turn this (empty) nested-name-specifier into the global
|
||||
/// nested-name-specifier '::'.
|
||||
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
|
||||
|
||||
|
||||
/// \brief Make a new nested-name-specifier from incomplete source-location
|
||||
/// information.
|
||||
///
|
||||
/// This routine should be used very, very rarely, in cases where we
|
||||
/// need to synthesize a nested-name-specifier. Most code should instead use
|
||||
/// \c Adopt() with a proper \c NestedNameSpecifierLoc.
|
||||
void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
|
||||
void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
|
||||
SourceRange R);
|
||||
|
||||
/// \brief Adopt an existing nested-name-specifier (with source-range
|
||||
|
||||
/// \brief Adopt an existing nested-name-specifier (with source-range
|
||||
/// information).
|
||||
void Adopt(NestedNameSpecifierLoc Other);
|
||||
|
||||
|
||||
/// \brief Retrieve the source range covered by this nested-name-specifier.
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve a nested-name-specifier with location information,
|
||||
/// copied into the given AST context.
|
||||
///
|
||||
|
|
@ -449,7 +456,7 @@ public:
|
|||
Representation = 0;
|
||||
BufferSize = 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the underlying buffer.
|
||||
///
|
||||
/// \returns A pair containing a pointer to the buffer of source-location
|
||||
|
|
@ -459,9 +466,9 @@ public:
|
|||
return std::make_pair(Buffer, BufferSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers
|
||||
/// into a diagnostic with <<.
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending
|
||||
/// NestedNameSpecifiers into a diagnostic with <<.
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
NestedNameSpecifier *NNS) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
|
||||
|
|
|
|||
|
|
@ -52,13 +52,6 @@ enum CastKind {
|
|||
/// conversion is always unqualified.
|
||||
CK_LValueToRValue,
|
||||
|
||||
/// CK_GetObjCProperty - A conversion which calls an Objective-C
|
||||
/// property getter. The operand is an OK_ObjCProperty l-value; the
|
||||
/// result will generally be an r-value, but could be an ordinary
|
||||
/// gl-value if the property reference is to an implicit property
|
||||
/// for a method that returns a reference type.
|
||||
CK_GetObjCProperty,
|
||||
|
||||
/// CK_NoOp - A conversion which does not affect the type other than
|
||||
/// (possibly) adding qualifiers.
|
||||
/// int -> int
|
||||
|
|
@ -124,6 +117,15 @@ enum CastKind {
|
|||
/// against the null member pointer.
|
||||
CK_MemberPointerToBoolean,
|
||||
|
||||
/// CK_ReinterpretMemberPointer - Reinterpret a member pointer as a
|
||||
/// different kind of member pointer. C++ forbids this from
|
||||
/// crossing between function and object types, but otherwise does
|
||||
/// not restrict it. However, the only operation that is permitted
|
||||
/// on a "punned" member pointer is casting it back to the original
|
||||
/// type, which is required to be a lossless operation (although
|
||||
/// many ABIs do not guarantee this on all possible intermediate types).
|
||||
CK_ReinterpretMemberPointer,
|
||||
|
||||
/// CK_UserDefinedConversion - Conversion using a user defined type
|
||||
/// conversion function.
|
||||
/// struct A { operator int(); }; int i = int(A());
|
||||
|
|
@ -274,7 +276,19 @@ enum CastKind {
|
|||
/// in ARC cause blocks to be copied; this is for cases where that
|
||||
/// would not otherwise be guaranteed, such as when casting to a
|
||||
/// non-block pointer type.
|
||||
CK_ARCExtendBlockObject
|
||||
CK_ARCExtendBlockObject,
|
||||
|
||||
/// \brief Converts from _Atomic(T) to T.
|
||||
CK_AtomicToNonAtomic,
|
||||
/// \brief Converts from T to _Atomic(T).
|
||||
CK_NonAtomicToAtomic,
|
||||
|
||||
/// \brief Causes a block literal to by copied to the heap and then
|
||||
/// autoreleased.
|
||||
///
|
||||
/// This particular cast kind is used for the conversion from a C++11
|
||||
/// lambda expression to a block pointer.
|
||||
CK_CopyAndAutoreleaseBlockObject
|
||||
};
|
||||
|
||||
#define CK_Invalid ((CastKind) -1)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct PrintingPolicy {
|
|||
PrintingPolicy(const LangOptions &LO)
|
||||
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
|
||||
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
|
||||
SuppressInitializers(false),
|
||||
SuppressUnwrittenScope(false), SuppressInitializers(false),
|
||||
Dump(false), ConstantArraySizeAsWritten(false),
|
||||
AnonymousTagLocations(true), SuppressStrongLifetime(false),
|
||||
Bool(LO.Bool) { }
|
||||
|
|
@ -86,6 +86,10 @@ struct PrintingPolicy {
|
|||
/// \brief Suppresses printing of scope specifiers.
|
||||
bool SuppressScope : 1;
|
||||
|
||||
/// \brief Suppress printing parts of scope specifiers that don't need
|
||||
/// to be written, e.g., for inline or anonymous namespaces.
|
||||
bool SuppressUnwrittenScope : 1;
|
||||
|
||||
/// \brief Suppress printing of variable initializers.
|
||||
///
|
||||
/// This flag is used when printing the loop variable in a for-range
|
||||
|
|
|
|||
|
|
@ -62,8 +62,11 @@ class ASTRecordLayout {
|
|||
/// (either a base or a member). Will be zero if the class doesn't contain
|
||||
/// any empty subobjects.
|
||||
CharUnits SizeOfLargestEmptySubobject;
|
||||
|
||||
/// VBPtrOffset - Virtual base table offset.
|
||||
|
||||
/// VFPtrOffset - Virtual function table offset (Microsoft-only).
|
||||
CharUnits VFPtrOffset;
|
||||
|
||||
/// VBPtrOffset - Virtual base table offset (Microsoft-only).
|
||||
CharUnits VBPtrOffset;
|
||||
|
||||
/// PrimaryBase - The primary base info for this record.
|
||||
|
|
@ -92,7 +95,8 @@ class ASTRecordLayout {
|
|||
// Constructor for C++ records.
|
||||
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
|
||||
ASTRecordLayout(const ASTContext &Ctx,
|
||||
CharUnits size, CharUnits alignment, CharUnits vbptroffset,
|
||||
CharUnits size, CharUnits alignment,
|
||||
CharUnits vfptroffset, CharUnits vbptroffset,
|
||||
CharUnits datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
|
||||
|
|
@ -204,7 +208,17 @@ public:
|
|||
return CXXInfo->SizeOfLargestEmptySubobject;
|
||||
}
|
||||
|
||||
/// getVFPtrOffset - Get the offset for virtual function table pointer.
|
||||
/// This is only meaningful with the Microsoft ABI.
|
||||
CharUnits getVFPtrOffset() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->VFPtrOffset;
|
||||
}
|
||||
|
||||
/// getVBPtrOffset - Get the offset for virtual base table pointer.
|
||||
/// This is only meaningful with the Microsoft ABI.
|
||||
CharUnits getVBPtrOffset() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->VBPtrOffset;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -147,7 +147,13 @@ public:
|
|||
/// \brief Return whether this visitor should recurse into the types of
|
||||
/// TypeLocs.
|
||||
bool shouldWalkTypesOfTypeLocs() const { return true; }
|
||||
|
||||
|
||||
/// \brief Return whether \param S should be traversed using data recursion
|
||||
/// to avoid a stack overflow with extreme cases.
|
||||
bool shouldUseDataRecursionFor(Stmt *S) const {
|
||||
return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) || isa<CaseStmt>(S);
|
||||
}
|
||||
|
||||
/// \brief Recursively visit a statement or expression, by
|
||||
/// dispatching to Traverse*() based on the argument's dynamic type.
|
||||
///
|
||||
|
|
@ -181,12 +187,17 @@ public:
|
|||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
|
||||
|
||||
/// \brief Recursively visit a C++ nested-name-specifier with location
|
||||
/// \brief Recursively visit a C++ nested-name-specifier with location
|
||||
/// information.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
|
||||
|
||||
/// \brief Recursively visit a name with its location information.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo);
|
||||
|
||||
/// \brief Recursively visit a template name and dispatch to the
|
||||
/// appropriate method.
|
||||
///
|
||||
|
|
@ -223,6 +234,11 @@ public:
|
|||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
|
||||
|
||||
/// \brief Recursively visit a lambda capture.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseLambdaCapture(LambdaExpr::Capture C);
|
||||
|
||||
// ---- Methods on Stmts ----
|
||||
|
||||
// Declare Traverse*() for all concrete Stmt classes.
|
||||
|
|
@ -387,8 +403,102 @@ private:
|
|||
bool TraverseDeclContextHelper(DeclContext *DC);
|
||||
bool TraverseFunctionHelper(FunctionDecl *D);
|
||||
bool TraverseVarHelper(VarDecl *D);
|
||||
|
||||
bool Walk(Stmt *S);
|
||||
|
||||
struct EnqueueJob {
|
||||
Stmt *S;
|
||||
Stmt::child_iterator StmtIt;
|
||||
|
||||
EnqueueJob(Stmt *S) : S(S), StmtIt() {
|
||||
if (Expr *E = dyn_cast_or_null<Expr>(S))
|
||||
S = E->IgnoreParens();
|
||||
}
|
||||
};
|
||||
bool dataTraverse(Stmt *S);
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
|
||||
|
||||
SmallVector<EnqueueJob, 16> Queue;
|
||||
Queue.push_back(S);
|
||||
|
||||
while (!Queue.empty()) {
|
||||
EnqueueJob &job = Queue.back();
|
||||
Stmt *CurrS = job.S;
|
||||
if (!CurrS) {
|
||||
Queue.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getDerived().shouldUseDataRecursionFor(CurrS)) {
|
||||
if (job.StmtIt == Stmt::child_iterator()) {
|
||||
if (!Walk(CurrS)) return false;
|
||||
job.StmtIt = CurrS->child_begin();
|
||||
} else {
|
||||
++job.StmtIt;
|
||||
}
|
||||
|
||||
if (job.StmtIt != CurrS->child_end())
|
||||
Queue.push_back(*job.StmtIt);
|
||||
else
|
||||
Queue.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
Queue.pop_back();
|
||||
TRY_TO(TraverseStmt(CurrS));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) {
|
||||
|
||||
#define DISPATCH_WALK(NAME, CLASS, VAR) \
|
||||
return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR));
|
||||
|
||||
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
#define OPERATOR(NAME) \
|
||||
case BO_##NAME: DISPATCH_WALK(Bin##NAME, BinaryOperator, S);
|
||||
|
||||
BINOP_LIST()
|
||||
#undef OPERATOR
|
||||
|
||||
#define OPERATOR(NAME) \
|
||||
case BO_##NAME##Assign: \
|
||||
DISPATCH_WALK(Bin##NAME##Assign, CompoundAssignOperator, S);
|
||||
|
||||
CAO_LIST()
|
||||
#undef OPERATOR
|
||||
}
|
||||
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
|
||||
switch (UnOp->getOpcode()) {
|
||||
#define OPERATOR(NAME) \
|
||||
case UO_##NAME: DISPATCH_WALK(Unary##NAME, UnaryOperator, S);
|
||||
|
||||
UNARYOP_LIST()
|
||||
#undef OPERATOR
|
||||
}
|
||||
}
|
||||
|
||||
// Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
|
||||
switch (S->getStmtClass()) {
|
||||
case Stmt::NoStmtClass: break;
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#define STMT(CLASS, PARENT) \
|
||||
case Stmt::CLASS##Class: DISPATCH_WALK(CLASS, CLASS, S);
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
}
|
||||
|
||||
#undef DISPATCH_WALK
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DISPATCH(NAME, CLASS, VAR) \
|
||||
return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR))
|
||||
|
||||
|
|
@ -397,6 +507,9 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
|
|||
if (!S)
|
||||
return true;
|
||||
|
||||
if (getDerived().shouldUseDataRecursionFor(S))
|
||||
return dataTraverse(S);
|
||||
|
||||
// If we have a binary expr, dispatch to the subcode of the binop. A smart
|
||||
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
|
||||
// below.
|
||||
|
|
@ -525,23 +638,48 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
|
|||
NestedNameSpecifierLoc NNS) {
|
||||
if (!NNS)
|
||||
return true;
|
||||
|
||||
|
||||
if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(Prefix));
|
||||
|
||||
|
||||
switch (NNS.getNestedNameSpecifier()->getKind()) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
case NestedNameSpecifier::Namespace:
|
||||
case NestedNameSpecifier::NamespaceAlias:
|
||||
case NestedNameSpecifier::Global:
|
||||
return true;
|
||||
|
||||
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
case NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
TRY_TO(TraverseTypeLoc(NNS.getTypeLoc()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
|
||||
DeclarationNameInfo NameInfo) {
|
||||
switch (NameInfo.getName().getNameKind()) {
|
||||
case DeclarationName::CXXConstructorName:
|
||||
case DeclarationName::CXXDestructorName:
|
||||
case DeclarationName::CXXConversionFunctionName:
|
||||
if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo())
|
||||
TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
|
||||
|
||||
break;
|
||||
|
||||
case DeclarationName::Identifier:
|
||||
case DeclarationName::ObjCZeroArgSelector:
|
||||
case DeclarationName::ObjCOneArgSelector:
|
||||
case DeclarationName::ObjCMultiArgSelector:
|
||||
case DeclarationName::CXXOperatorName:
|
||||
case DeclarationName::CXXLiteralOperatorName:
|
||||
case DeclarationName::CXXUsingDirective:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -600,7 +738,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
|
|||
// FIXME: how can TSI ever be NULL?
|
||||
if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo())
|
||||
return getDerived().TraverseTypeLoc(TSI->getTypeLoc());
|
||||
else
|
||||
else
|
||||
return getDerived().TraverseType(Arg.getAsType());
|
||||
}
|
||||
|
||||
|
|
@ -637,12 +775,18 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments(
|
|||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
|
||||
CXXCtorInitializer *Init) {
|
||||
// FIXME: recurse on TypeLoc of the base initializer if isBaseInitializer()?
|
||||
if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
|
||||
|
||||
if (Init->isWritten())
|
||||
TRY_TO(TraverseStmt(Init->getInit()));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------- Type traversal -----------------
|
||||
|
||||
|
|
@ -822,8 +966,8 @@ DEF_TRAVERSE_TYPE(AtomicType, {
|
|||
// ----------------- TypeLoc traversal -----------------
|
||||
|
||||
// This macro makes available a variable TL, the passed-in TypeLoc.
|
||||
// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc,
|
||||
// in addition to WalkUpFrom* for the TypeLoc itself, such that existing
|
||||
// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc,
|
||||
// in addition to WalkUpFrom* for the TypeLoc itself, such that existing
|
||||
// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods
|
||||
// continue to work.
|
||||
#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \
|
||||
|
|
@ -1022,7 +1166,7 @@ DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
|
|||
if (TL.getQualifierLoc()) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
|
||||
}
|
||||
|
||||
|
||||
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
|
||||
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
|
||||
}
|
||||
|
|
@ -1099,6 +1243,8 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
|
|||
TRY_TO(TraverseStmt(D->getAsmString()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ImportDecl, { })
|
||||
|
||||
DEF_TRAVERSE_DECL(FriendDecl, {
|
||||
// Friend is either decl or a type.
|
||||
if (D->getFriendType())
|
||||
|
|
@ -1128,14 +1274,6 @@ DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
|
|||
|
||||
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCClassDecl, {
|
||||
// FIXME: implement this
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCForwardProtocolDecl, {
|
||||
// FIXME: implement this
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {
|
||||
// FIXME: implement this
|
||||
})
|
||||
|
|
@ -1164,8 +1302,8 @@ DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
|
|||
DEF_TRAVERSE_DECL(LabelDecl, {
|
||||
// There is no code in a LabelDecl.
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
DEF_TRAVERSE_DECL(NamespaceDecl, {
|
||||
// Code in an unnamed namespace shows up automatically in
|
||||
// decls_begin()/decls_end(). Thus we don't need to recurse on
|
||||
|
|
@ -1216,6 +1354,7 @@ DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
|||
|
||||
DEF_TRAVERSE_DECL(UsingDecl, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
|
||||
|
|
@ -1312,7 +1451,8 @@ template<typename Derived>
|
|||
bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
||||
FunctionTemplateDecl* D) {
|
||||
FunctionTemplateDecl::spec_iterator end = D->spec_end();
|
||||
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
|
||||
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
|
||||
++it) {
|
||||
FunctionDecl* FD = *it;
|
||||
switch (FD->getTemplateSpecializationKind()) {
|
||||
case TSK_ImplicitInstantiation:
|
||||
|
|
@ -1329,8 +1469,6 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
|||
case TSK_Undeclared: // Declaration of the template definition.
|
||||
case TSK_ExplicitSpecialization:
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unknown specialization kind.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1511,6 +1649,7 @@ DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, {
|
|||
// Like UnresolvedUsingTypenameDecl, but without the 'typename':
|
||||
// template <class T> Class A : public Base<T> { using Base<T>::foo; };
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(IndirectFieldDecl, {})
|
||||
|
|
@ -1529,6 +1668,8 @@ DEF_TRAVERSE_DECL(FieldDecl, {
|
|||
TRY_TO(TraverseDeclaratorHelper(D));
|
||||
if (D->isBitField())
|
||||
TRY_TO(TraverseStmt(D->getBitWidth()));
|
||||
else if (D->hasInClassInitializer())
|
||||
TRY_TO(TraverseStmt(D->getInClassInitializer()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, {
|
||||
|
|
@ -1548,6 +1689,7 @@ DEF_TRAVERSE_DECL(ObjCIvarDecl, {
|
|||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
|
||||
|
||||
// If we're an explicit template specialization, iterate over the
|
||||
// template args that were explicitly specified. If we were doing
|
||||
|
|
@ -1624,7 +1766,9 @@ DEF_TRAVERSE_DECL(CXXDestructorDecl, {
|
|||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) {
|
||||
TRY_TO(TraverseDeclaratorHelper(D));
|
||||
TRY_TO(TraverseStmt(D->getInit()));
|
||||
// Default params are taken care of when we traverse the ParmVarDecl.
|
||||
if (!isa<ParmVarDecl>(D))
|
||||
TRY_TO(TraverseStmt(D->getInit()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1735,6 +1879,10 @@ DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
|
|||
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
|
||||
DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
|
||||
DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
|
||||
})
|
||||
DEF_TRAVERSE_STMT(ReturnStmt, { })
|
||||
DEF_TRAVERSE_STMT(SwitchStmt, { })
|
||||
DEF_TRAVERSE_STMT(WhileStmt, { })
|
||||
|
|
@ -1742,6 +1890,7 @@ DEF_TRAVERSE_STMT(WhileStmt, { })
|
|||
|
||||
DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
S->getTemplateArgs(), S->getNumTemplateArgs()));
|
||||
|
|
@ -1750,12 +1899,14 @@ DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
|
|||
|
||||
DEF_TRAVERSE_STMT(DeclRefExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
S->getTemplateArgs(), S->getNumTemplateArgs()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
S->getExplicitTemplateArgs().getTemplateArgs(),
|
||||
|
|
@ -1765,6 +1916,7 @@ DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
|
|||
|
||||
DEF_TRAVERSE_STMT(MemberExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
S->getTemplateArgs(), S->getNumTemplateArgs()));
|
||||
})
|
||||
|
|
@ -1831,6 +1983,23 @@ TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// PseudoObjectExpr is a special case because of the wierdness with
|
||||
// syntactic expressions and opaque values.
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::
|
||||
TraversePseudoObjectExpr(PseudoObjectExpr *S) {
|
||||
TRY_TO(WalkUpFromPseudoObjectExpr(S));
|
||||
TRY_TO(TraverseStmt(S->getSyntacticForm()));
|
||||
for (PseudoObjectExpr::semantics_iterator
|
||||
i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) {
|
||||
Expr *sub = *i;
|
||||
if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
|
||||
sub = OVE->getSourceExpr();
|
||||
TRY_TO(TraverseStmt(sub));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
|
||||
// This is called for code like 'return T()' where T is a built-in
|
||||
// (i.e. non-class) type.
|
||||
|
|
@ -1880,6 +2049,11 @@ DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, {
|
|||
TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(TypeTraitExpr, {
|
||||
for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I)
|
||||
TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
|
||||
TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
|
@ -1898,6 +2072,37 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
|
|||
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
// Walk only the visible parts of lambda expressions.
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
||||
for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
|
||||
CEnd = S->explicit_capture_end();
|
||||
C != CEnd; ++C) {
|
||||
TRY_TO(TraverseLambdaCapture(*C));
|
||||
}
|
||||
|
||||
if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
|
||||
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
|
||||
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
|
||||
// Visit the whole type.
|
||||
TRY_TO(TraverseTypeLoc(TL));
|
||||
} else if (isa<FunctionProtoTypeLoc>(TL)) {
|
||||
FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
|
||||
if (S->hasExplicitParameters()) {
|
||||
// Visit parameters.
|
||||
for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) {
|
||||
TRY_TO(TraverseDecl(Proto.getArg(I)));
|
||||
}
|
||||
} else {
|
||||
TRY_TO(TraverseTypeLoc(Proto.getResultLoc()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRY_TO(TraverseStmt(S->getBody()));
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
|
||||
// This is called for code like 'T()', where T is a template argument.
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
|
||||
|
|
@ -1913,7 +2118,6 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
|
|||
// over the children.
|
||||
DEF_TRAVERSE_STMT(AddrLabelExpr, { })
|
||||
DEF_TRAVERSE_STMT(ArraySubscriptExpr, { })
|
||||
DEF_TRAVERSE_STMT(BlockDeclRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(BlockExpr, {
|
||||
TRY_TO(TraverseDecl(S->getBlockDecl()));
|
||||
return true; // no child statements to loop through.
|
||||
|
|
@ -1926,7 +2130,7 @@ DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
|
|||
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
|
||||
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
|
||||
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
|
||||
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
|
||||
TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc()));
|
||||
|
|
@ -1935,15 +2139,18 @@ DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
|
|||
})
|
||||
DEF_TRAVERSE_STMT(CXXThisExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXThrowExpr, { })
|
||||
DEF_TRAVERSE_STMT(UserDefinedLiteral, { })
|
||||
DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
|
||||
DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
|
||||
DEF_TRAVERSE_STMT(GNUNullExpr, { })
|
||||
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCEncodeExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCSubscriptRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCProtocolExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCSelectorExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, { })
|
||||
|
|
@ -1958,15 +2165,15 @@ DEF_TRAVERSE_STMT(StmtExpr, { })
|
|||
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
|
||||
S->getNumTemplateArgs()));
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
if (S->hasExplicitTemplateArgs()) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
|
||||
S->getNumTemplateArgs()));
|
||||
}
|
||||
})
|
||||
|
|
@ -2001,6 +2208,9 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { })
|
|||
DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
|
||||
DEF_TRAVERSE_STMT(StringLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCNumericLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCArrayLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
|
||||
|
||||
// Traverse OpenCL: AsType, Convert.
|
||||
DEF_TRAVERSE_STMT(AsTypeExpr, { })
|
||||
|
|
|
|||
|
|
@ -64,22 +64,22 @@ public:
|
|||
|
||||
/// \brief Return the previous declaration of this declaration or NULL if this
|
||||
/// is the first declaration.
|
||||
decl_type *getPreviousDeclaration() {
|
||||
decl_type *getPreviousDecl() {
|
||||
if (RedeclLink.NextIsPrevious())
|
||||
return RedeclLink.getNext();
|
||||
return 0;
|
||||
}
|
||||
const decl_type *getPreviousDeclaration() const {
|
||||
const decl_type *getPreviousDecl() const {
|
||||
return const_cast<decl_type *>(
|
||||
static_cast<const decl_type*>(this))->getPreviousDeclaration();
|
||||
static_cast<const decl_type*>(this))->getPreviousDecl();
|
||||
}
|
||||
|
||||
/// \brief Return the first declaration of this declaration or itself if this
|
||||
/// is the only declaration.
|
||||
decl_type *getFirstDeclaration() {
|
||||
decl_type *D = static_cast<decl_type*>(this);
|
||||
while (D->getPreviousDeclaration())
|
||||
D = D->getPreviousDeclaration();
|
||||
while (D->getPreviousDecl())
|
||||
D = D->getPreviousDecl();
|
||||
return D;
|
||||
}
|
||||
|
||||
|
|
@ -87,8 +87,8 @@ public:
|
|||
/// is the only declaration.
|
||||
const decl_type *getFirstDeclaration() const {
|
||||
const decl_type *D = static_cast<const decl_type*>(this);
|
||||
while (D->getPreviousDeclaration())
|
||||
D = D->getPreviousDeclaration();
|
||||
while (D->getPreviousDecl())
|
||||
D = D->getPreviousDecl();
|
||||
return D;
|
||||
}
|
||||
|
||||
|
|
@ -98,12 +98,12 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||
decl_type *getMostRecentDeclaration() {
|
||||
decl_type *getMostRecentDecl() {
|
||||
return getFirstDeclaration()->RedeclLink.getNext();
|
||||
}
|
||||
|
||||
/// \brief Returns the most recent (re)declaration of this declaration.
|
||||
const decl_type *getMostRecentDeclaration() const {
|
||||
const decl_type *getMostRecentDecl() const {
|
||||
return getFirstDeclaration()->RedeclLink.getNext();
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +116,7 @@ public:
|
|||
/// Current - The current declaration.
|
||||
decl_type *Current;
|
||||
decl_type *Starter;
|
||||
bool PassedFirst;
|
||||
|
||||
public:
|
||||
typedef decl_type* value_type;
|
||||
|
|
@ -125,13 +126,24 @@ public:
|
|||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
redecl_iterator() : Current(0) { }
|
||||
explicit redecl_iterator(decl_type *C) : Current(C), Starter(C) { }
|
||||
explicit redecl_iterator(decl_type *C)
|
||||
: Current(C), Starter(C), PassedFirst(false) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
|
||||
redecl_iterator& operator++() {
|
||||
assert(Current && "Advancing while iterator has reached end");
|
||||
// Sanity check to avoid infinite loop on invalid redecl chain.
|
||||
if (Current->isFirstDeclaration()) {
|
||||
if (PassedFirst) {
|
||||
assert(0 && "Passed first decl twice, invalid redecl chain!");
|
||||
Current = 0;
|
||||
return *this;
|
||||
}
|
||||
PassedFirst = true;
|
||||
}
|
||||
|
||||
// Get either previous decl or latest decl.
|
||||
decl_type *Next = Current->RedeclLink.getNext();
|
||||
Current = (Next != Starter ? Next : 0);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@
|
|||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
|
@ -39,11 +40,11 @@ namespace clang {
|
|||
class StringLiteral;
|
||||
class SwitchStmt;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ExprIterator - Iterators for iterating over Stmt* arrays that contain
|
||||
// only Expr*. This is needed because AST nodes use Stmt* arrays to store
|
||||
// references to children (to be compatible with StmtIterator).
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class Stmt;
|
||||
class Expr;
|
||||
|
|
@ -141,11 +142,14 @@ protected:
|
|||
friend class CallExpr; // ctor
|
||||
friend class OffsetOfExpr; // ctor
|
||||
friend class ObjCMessageExpr; // ctor
|
||||
friend class ObjCArrayLiteral; // ctor
|
||||
friend class ObjCDictionaryLiteral; // ctor
|
||||
friend class ShuffleVectorExpr; // ctor
|
||||
friend class ParenListExpr; // ctor
|
||||
friend class CXXUnresolvedConstructExpr; // ctor
|
||||
friend class CXXDependentScopeMemberExpr; // ctor
|
||||
friend class OverloadExpr; // ctor
|
||||
friend class PseudoObjectExpr; // ctor
|
||||
friend class AtomicExpr; // ctor
|
||||
unsigned : NumStmtBits;
|
||||
|
||||
|
|
@ -158,15 +162,39 @@ protected:
|
|||
};
|
||||
enum { NumExprBits = 16 };
|
||||
|
||||
class CharacterLiteralBitfields {
|
||||
friend class CharacterLiteral;
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned Kind : 2;
|
||||
};
|
||||
|
||||
class FloatingLiteralBitfields {
|
||||
friend class FloatingLiteral;
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned IsIEEE : 1; // Distinguishes between PPC128 and IEEE128.
|
||||
unsigned IsExact : 1;
|
||||
};
|
||||
|
||||
class UnaryExprOrTypeTraitExprBitfields {
|
||||
friend class UnaryExprOrTypeTraitExpr;
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned Kind : 2;
|
||||
unsigned IsType : 1; // true if operand is a type, false if an expression.
|
||||
};
|
||||
|
||||
class DeclRefExprBitfields {
|
||||
friend class DeclRefExpr;
|
||||
friend class ASTStmtReader; // deserialization
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned HasQualifier : 1;
|
||||
unsigned HasExplicitTemplateArgs : 1;
|
||||
unsigned HasTemplateKWAndArgsInfo : 1;
|
||||
unsigned HasFoundDecl : 1;
|
||||
unsigned HadMultipleCandidates : 1;
|
||||
unsigned RefersToEnclosingLocal : 1;
|
||||
};
|
||||
|
||||
class CastExprBitfields {
|
||||
|
|
@ -184,6 +212,27 @@ protected:
|
|||
unsigned NumPreArgs : 1;
|
||||
};
|
||||
|
||||
class ExprWithCleanupsBitfields {
|
||||
friend class ExprWithCleanups;
|
||||
friend class ASTStmtReader; // deserialization
|
||||
|
||||
unsigned : NumExprBits;
|
||||
|
||||
unsigned NumObjects : 32 - NumExprBits;
|
||||
};
|
||||
|
||||
class PseudoObjectExprBitfields {
|
||||
friend class PseudoObjectExpr;
|
||||
friend class ASTStmtReader; // deserialization
|
||||
|
||||
unsigned : NumExprBits;
|
||||
|
||||
// These don't need to be particularly wide, because they're
|
||||
// strictly limited by the forms of expressions we permit.
|
||||
unsigned NumSubExprs : 8;
|
||||
unsigned ResultIndex : 32 - 8 - NumExprBits;
|
||||
};
|
||||
|
||||
class ObjCIndirectCopyRestoreExprBitfields {
|
||||
friend class ObjCIndirectCopyRestoreExpr;
|
||||
unsigned : NumExprBits;
|
||||
|
|
@ -191,6 +240,38 @@ protected:
|
|||
unsigned ShouldCopy : 1;
|
||||
};
|
||||
|
||||
class InitListExprBitfields {
|
||||
friend class InitListExpr;
|
||||
|
||||
unsigned : NumExprBits;
|
||||
|
||||
/// Whether this initializer list originally had a GNU array-range
|
||||
/// designator in it. This is a temporary marker used by CodeGen.
|
||||
unsigned HadArrayRangeDesignator : 1;
|
||||
|
||||
/// Whether this initializer list initializes a std::initializer_list
|
||||
/// object.
|
||||
unsigned InitializesStdInitializerList : 1;
|
||||
};
|
||||
|
||||
class TypeTraitExprBitfields {
|
||||
friend class TypeTraitExpr;
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
|
||||
unsigned : NumExprBits;
|
||||
|
||||
/// \brief The kind of type trait, which is a value of a TypeTrait enumerator.
|
||||
unsigned Kind : 8;
|
||||
|
||||
/// \brief If this expression is not value-dependent, this indicates whether
|
||||
/// the trait evaluated true or false.
|
||||
unsigned Value : 1;
|
||||
|
||||
/// \brief The number of arguments to this type trait.
|
||||
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
|
||||
};
|
||||
|
||||
union {
|
||||
// FIXME: this is wasteful on 64-bit platforms.
|
||||
void *Aligner;
|
||||
|
|
@ -198,13 +279,21 @@ protected:
|
|||
StmtBitfields StmtBits;
|
||||
CompoundStmtBitfields CompoundStmtBits;
|
||||
ExprBitfields ExprBits;
|
||||
CharacterLiteralBitfields CharacterLiteralBits;
|
||||
FloatingLiteralBitfields FloatingLiteralBits;
|
||||
UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits;
|
||||
DeclRefExprBitfields DeclRefExprBits;
|
||||
CastExprBitfields CastExprBits;
|
||||
CallExprBitfields CallExprBits;
|
||||
ExprWithCleanupsBitfields ExprWithCleanupsBits;
|
||||
PseudoObjectExprBitfields PseudoObjectExprBits;
|
||||
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
|
||||
InitListExprBitfields InitListExprBits;
|
||||
TypeTraitExprBitfields TypeTraitExprBits;
|
||||
};
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
|
||||
public:
|
||||
// Only allow allocation of Stmts using the allocator in ASTContext
|
||||
|
|
@ -234,20 +323,24 @@ public:
|
|||
/// de-serialization).
|
||||
struct EmptyShell { };
|
||||
|
||||
private:
|
||||
/// \brief Whether statistic collection is enabled.
|
||||
static bool StatisticsEnabled;
|
||||
|
||||
protected:
|
||||
/// \brief Construct an empty statement.
|
||||
explicit Stmt(StmtClass SC, EmptyShell) {
|
||||
StmtBits.sClass = SC;
|
||||
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
|
||||
if (StatisticsEnabled) Stmt::addStmtClass(SC);
|
||||
}
|
||||
|
||||
public:
|
||||
Stmt(StmtClass SC) {
|
||||
StmtBits.sClass = SC;
|
||||
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
|
||||
if (StatisticsEnabled) Stmt::addStmtClass(SC);
|
||||
}
|
||||
|
||||
StmtClass getStmtClass() const {
|
||||
StmtClass getStmtClass() const {
|
||||
return static_cast<StmtClass>(StmtBits.sClass);
|
||||
}
|
||||
const char *getStmtClassName() const;
|
||||
|
|
@ -255,21 +348,20 @@ public:
|
|||
/// SourceLocation tokens are not useful in isolation - they are low level
|
||||
/// value objects created/interpreted by SourceManager. We assume AST
|
||||
/// clients will have a pointer to the respective SourceManager.
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
SourceLocation getLocStart() const { return getSourceRange().getBegin(); }
|
||||
SourceLocation getLocEnd() const { return getSourceRange().getEnd(); }
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceLocation getLocStart() const LLVM_READONLY;
|
||||
SourceLocation getLocEnd() const LLVM_READONLY;
|
||||
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void addStmtClass(const StmtClass s);
|
||||
static bool CollectingStats(bool Enable = false);
|
||||
static void EnableStatistics();
|
||||
static void PrintStats();
|
||||
|
||||
/// dump - This does a local dump of the specified AST fragment. It dumps the
|
||||
/// specified node and a few nodes underneath it, but not the whole subtree.
|
||||
/// This is useful in a debugger.
|
||||
void dump() const;
|
||||
void dump(SourceManager &SM) const;
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
|
||||
void dump(raw_ostream &OS, SourceManager &SM) const;
|
||||
|
||||
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
|
||||
|
|
@ -384,7 +476,7 @@ public:
|
|||
SourceLocation getEndLoc() const { return EndLoc; }
|
||||
void setEndLoc(SourceLocation L) { EndLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(StartLoc, EndLoc);
|
||||
}
|
||||
|
||||
|
|
@ -433,7 +525,7 @@ public:
|
|||
|
||||
bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; }
|
||||
|
||||
SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(SemiLoc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == NullStmtClass;
|
||||
|
|
@ -483,7 +575,7 @@ public:
|
|||
body_iterator body_begin() { return Body; }
|
||||
body_iterator body_end() { return Body + size(); }
|
||||
Stmt *body_back() { return !body_empty() ? Body[size()-1] : 0; }
|
||||
|
||||
|
||||
void setLastStmt(Stmt *S) {
|
||||
assert(!body_empty() && "setLastStmt");
|
||||
Body[size()-1] = S;
|
||||
|
|
@ -513,7 +605,7 @@ public:
|
|||
return const_reverse_body_iterator(body_begin());
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(LBracLoc, RBracLoc);
|
||||
}
|
||||
|
||||
|
|
@ -531,7 +623,7 @@ public:
|
|||
child_range children() {
|
||||
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
|
||||
}
|
||||
|
||||
|
||||
const_child_range children() const {
|
||||
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
|
||||
}
|
||||
|
|
@ -558,7 +650,7 @@ public:
|
|||
return const_cast<SwitchCase*>(this)->getSubStmt();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const { return SourceRange(); }
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CaseStmtClass ||
|
||||
|
|
@ -613,7 +705,7 @@ public:
|
|||
void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); }
|
||||
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
// Handle deeply nested case statements with iteration instead of recursion.
|
||||
const CaseStmt *CS = this;
|
||||
while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt()))
|
||||
|
|
@ -653,7 +745,7 @@ public:
|
|||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
void setColonLoc(SourceLocation L) { ColonLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(DefaultLoc, SubStmt->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
@ -665,7 +757,7 @@ public:
|
|||
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// LabelStmt - Represents a label, which has a substatement. For example:
|
||||
/// foo: return;
|
||||
///
|
||||
|
|
@ -690,7 +782,7 @@ public:
|
|||
void setIdentLoc(SourceLocation L) { IdentLoc = L; }
|
||||
void setSubStmt(Stmt *SS) { SubStmt = SS; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(IdentLoc, SubStmt->getLocEnd());
|
||||
}
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
|
||||
|
|
@ -710,11 +802,11 @@ class IfStmt : public Stmt {
|
|||
|
||||
SourceLocation IfLoc;
|
||||
SourceLocation ElseLoc;
|
||||
|
||||
|
||||
public:
|
||||
IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
|
||||
IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
|
||||
Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
|
||||
|
||||
|
||||
/// \brief Build an empty if/then/else statement
|
||||
explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
|
||||
|
||||
|
|
@ -728,13 +820,13 @@ public:
|
|||
/// \endcode
|
||||
VarDecl *getConditionVariable() const;
|
||||
void setConditionVariable(ASTContext &C, VarDecl *V);
|
||||
|
||||
|
||||
/// If this IfStmt has a condition variable, return the faux DeclStmt
|
||||
/// associated with the creation of that condition variable.
|
||||
const DeclStmt *getConditionVariableDeclStmt() const {
|
||||
return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
|
||||
}
|
||||
|
||||
|
||||
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
|
||||
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
|
||||
const Stmt *getThen() const { return SubExprs[THEN]; }
|
||||
|
|
@ -751,7 +843,7 @@ public:
|
|||
SourceLocation getElseLoc() const { return ElseLoc; }
|
||||
void setElseLoc(SourceLocation L) { ElseLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
if (SubExprs[ELSE])
|
||||
return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd());
|
||||
else
|
||||
|
|
@ -801,7 +893,7 @@ public:
|
|||
/// \endcode
|
||||
VarDecl *getConditionVariable() const;
|
||||
void setConditionVariable(ASTContext &C, VarDecl *V);
|
||||
|
||||
|
||||
/// If this SwitchStmt has a condition variable, return the faux DeclStmt
|
||||
/// associated with the creation of that condition variable.
|
||||
const DeclStmt *getConditionVariableDeclStmt() const {
|
||||
|
|
@ -832,7 +924,8 @@ public:
|
|||
SwitchLoc = SL;
|
||||
}
|
||||
void addSwitchCase(SwitchCase *SC) {
|
||||
assert(!SC->getNextSwitchCase() && "case/default already added to a switch");
|
||||
assert(!SC->getNextSwitchCase()
|
||||
&& "case/default already added to a switch");
|
||||
SC->setNextSwitchCase(FirstCase);
|
||||
FirstCase = SC;
|
||||
}
|
||||
|
|
@ -849,7 +942,7 @@ public:
|
|||
return (bool) AllEnumCasesCovered;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
// Iterators
|
||||
|
|
@ -871,7 +964,7 @@ class WhileStmt : public Stmt {
|
|||
Stmt* SubExprs[END_EXPR];
|
||||
SourceLocation WhileLoc;
|
||||
public:
|
||||
WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
|
||||
WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
|
||||
SourceLocation WL);
|
||||
|
||||
/// \brief Build an empty while statement.
|
||||
|
|
@ -904,7 +997,7 @@ public:
|
|||
SourceLocation getWhileLoc() const { return WhileLoc; }
|
||||
void setWhileLoc(SourceLocation L) { WhileLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
@ -953,7 +1046,7 @@ public:
|
|||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(DoLoc, RParenLoc);
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
@ -979,14 +1072,14 @@ class ForStmt : public Stmt {
|
|||
SourceLocation LParenLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc,
|
||||
ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc,
|
||||
Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP);
|
||||
|
||||
/// \brief Build an empty for statement.
|
||||
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
|
||||
|
||||
Stmt *getInit() { return SubExprs[INIT]; }
|
||||
|
||||
|
||||
/// \brief Retrieve the variable declared in this "for" statement, if any.
|
||||
///
|
||||
/// In the following example, "y" is the condition variable.
|
||||
|
|
@ -997,7 +1090,7 @@ public:
|
|||
/// \endcode
|
||||
VarDecl *getConditionVariable() const;
|
||||
void setConditionVariable(ASTContext &C, VarDecl *V);
|
||||
|
||||
|
||||
/// If this ForStmt has a condition variable, return the faux DeclStmt
|
||||
/// associated with the creation of that condition variable.
|
||||
const DeclStmt *getConditionVariableDeclStmt() const {
|
||||
|
|
@ -1025,7 +1118,7 @@ public:
|
|||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
@ -1060,7 +1153,7 @@ public:
|
|||
SourceLocation getLabelLoc() const { return LabelLoc; }
|
||||
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(GotoLoc, LabelLoc);
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
@ -1104,7 +1197,7 @@ public:
|
|||
return const_cast<IndirectGotoStmt*>(this)->getConstantTarget();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(GotoLoc, Target->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
@ -1131,7 +1224,7 @@ public:
|
|||
SourceLocation getContinueLoc() const { return ContinueLoc; }
|
||||
void setContinueLoc(SourceLocation L) { ContinueLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(ContinueLoc);
|
||||
}
|
||||
|
||||
|
|
@ -1157,7 +1250,7 @@ public:
|
|||
SourceLocation getBreakLoc() const { return BreakLoc; }
|
||||
void setBreakLoc(SourceLocation L) { BreakLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const { return SourceRange(BreakLoc); }
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(BreakLoc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BreakStmtClass;
|
||||
|
|
@ -1182,7 +1275,7 @@ class ReturnStmt : public Stmt {
|
|||
Stmt *RetExpr;
|
||||
SourceLocation RetLoc;
|
||||
const VarDecl *NRVOCandidate;
|
||||
|
||||
|
||||
public:
|
||||
ReturnStmt(SourceLocation RL)
|
||||
: Stmt(ReturnStmtClass), RetExpr(0), RetLoc(RL), NRVOCandidate(0) { }
|
||||
|
|
@ -1208,8 +1301,8 @@ public:
|
|||
/// also marked as an NRVO object.
|
||||
const VarDecl *getNRVOCandidate() const { return NRVOCandidate; }
|
||||
void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; }
|
||||
|
||||
SourceRange getSourceRange() const;
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ReturnStmtClass;
|
||||
|
|
@ -1242,16 +1335,16 @@ class AsmStmt : public Stmt {
|
|||
StringLiteral **Constraints;
|
||||
Stmt **Exprs;
|
||||
StringLiteral **Clobbers;
|
||||
|
||||
|
||||
public:
|
||||
AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
|
||||
AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
|
||||
bool msasm, unsigned numoutputs, unsigned numinputs,
|
||||
IdentifierInfo **names, StringLiteral **constraints,
|
||||
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
|
||||
StringLiteral **clobbers, SourceLocation rparenloc);
|
||||
|
||||
/// \brief Build an empty inline-assembly statement.
|
||||
explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
|
||||
explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
|
||||
Names(0), Constraints(0), Exprs(0), Clobbers(0) { }
|
||||
|
||||
SourceLocation getAsmLoc() const { return AsmLoc; }
|
||||
|
|
@ -1333,7 +1426,7 @@ public:
|
|||
StringRef getOutputName(unsigned i) const {
|
||||
if (IdentifierInfo *II = getOutputIdentifier(i))
|
||||
return II->getName();
|
||||
|
||||
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
|
|
@ -1394,7 +1487,7 @@ public:
|
|||
|
||||
Expr *getInputExpr(unsigned i);
|
||||
void setInputExpr(unsigned i, Expr *E);
|
||||
|
||||
|
||||
const Expr *getInputExpr(unsigned i) const {
|
||||
return const_cast<AsmStmt*>(this)->getInputExpr(i);
|
||||
}
|
||||
|
|
@ -1404,7 +1497,7 @@ public:
|
|||
StringLiteral **Constraints,
|
||||
Stmt **Exprs,
|
||||
unsigned NumOutputs,
|
||||
unsigned NumInputs,
|
||||
unsigned NumInputs,
|
||||
StringLiteral **Clobbers,
|
||||
unsigned NumClobbers);
|
||||
|
||||
|
|
@ -1419,7 +1512,7 @@ public:
|
|||
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
|
||||
const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AsmLoc, RParenLoc);
|
||||
}
|
||||
|
||||
|
|
@ -1490,15 +1583,20 @@ public:
|
|||
SourceLocation ExceptLoc,
|
||||
Expr *FilterExpr,
|
||||
Stmt *Block);
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getExceptLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
SourceLocation getExceptLoc() const { return Loc; }
|
||||
SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); }
|
||||
|
||||
Expr *getFilterExpr() const { return reinterpret_cast<Expr*>(Children[FILTER_EXPR]); }
|
||||
CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Children[BLOCK]); }
|
||||
Expr *getFilterExpr() const {
|
||||
return reinterpret_cast<Expr*>(Children[FILTER_EXPR]);
|
||||
}
|
||||
|
||||
CompoundStmt *getBlock() const {
|
||||
return llvm::cast<CompoundStmt>(Children[BLOCK]);
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(Children,Children+2);
|
||||
|
|
@ -1528,7 +1626,7 @@ public:
|
|||
SourceLocation FinallyLoc,
|
||||
Stmt *Block);
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getFinallyLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
|
|
@ -1572,7 +1670,7 @@ public:
|
|||
Stmt *TryBlock,
|
||||
Stmt *Handler);
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getTryLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
|
|
@ -1580,7 +1678,11 @@ public:
|
|||
SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); }
|
||||
|
||||
bool getIsCXXTry() const { return IsCXXTry; }
|
||||
CompoundStmt* getTryBlock() const { return llvm::cast<CompoundStmt>(Children[TRY]); }
|
||||
|
||||
CompoundStmt* getTryBlock() const {
|
||||
return llvm::cast<CompoundStmt>(Children[TRY]);
|
||||
}
|
||||
|
||||
Stmt *getHandler() const { return Children[HANDLER]; }
|
||||
|
||||
/// Returns 0 if not defined
|
||||
|
|
@ -1596,7 +1698,6 @@ public:
|
|||
}
|
||||
|
||||
static bool classof(SEHTryStmt *) { return true; }
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#define LLVM_CLANG_AST_STMTCXX_H
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ public:
|
|||
CXXCatchStmt(EmptyShell Empty)
|
||||
: Stmt(CXXCatchStmtClass), ExceptionDecl(0), HandlerBlock(0) {}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +84,7 @@ public:
|
|||
static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty,
|
||||
unsigned numHandlers);
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getTryLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +149,9 @@ public:
|
|||
|
||||
|
||||
DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); }
|
||||
DeclStmt *getBeginEndStmt() { return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); }
|
||||
DeclStmt *getBeginEndStmt() {
|
||||
return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
|
||||
}
|
||||
Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); }
|
||||
Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); }
|
||||
DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
|
||||
|
|
@ -187,7 +190,7 @@ public:
|
|||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
@ -201,6 +204,91 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Representation of a Microsoft __if_exists or __if_not_exists
|
||||
/// statement with a dependent name.
|
||||
///
|
||||
/// The __if_exists statement can be used to include a sequence of statements
|
||||
/// in the program only when a particular dependent name does not exist. For
|
||||
/// example:
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T>
|
||||
/// void call_foo(T &t) {
|
||||
/// __if_exists (T::foo) {
|
||||
/// t.foo(); // okay: only called when T::foo exists.
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Similarly, the __if_not_exists statement can be used to include the
|
||||
/// statements when a particular name does not exist.
|
||||
///
|
||||
/// Note that this statement only captures __if_exists and __if_not_exists
|
||||
/// statements whose name is dependent. All non-dependent cases are handled
|
||||
/// directly in the parser, so that they don't introduce a new scope. Clang
|
||||
/// introduces scopes in the dependent case to keep names inside the compound
|
||||
/// statement from leaking out into the surround statements, which would
|
||||
/// compromise the template instantiation model. This behavior differs from
|
||||
/// Visual C++ (which never introduces a scope), but is a fairly reasonable
|
||||
/// approximation of the VC++ behavior.
|
||||
class MSDependentExistsStmt : public Stmt {
|
||||
SourceLocation KeywordLoc;
|
||||
bool IsIfExists;
|
||||
NestedNameSpecifierLoc QualifierLoc;
|
||||
DeclarationNameInfo NameInfo;
|
||||
Stmt *SubStmt;
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
MSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
DeclarationNameInfo NameInfo,
|
||||
CompoundStmt *SubStmt)
|
||||
: Stmt(MSDependentExistsStmtClass),
|
||||
KeywordLoc(KeywordLoc), IsIfExists(IsIfExists),
|
||||
QualifierLoc(QualifierLoc), NameInfo(NameInfo),
|
||||
SubStmt(reinterpret_cast<Stmt *>(SubStmt)) { }
|
||||
|
||||
/// \brief Retrieve the location of the __if_exists or __if_not_exists
|
||||
/// keyword.
|
||||
SourceLocation getKeywordLoc() const { return KeywordLoc; }
|
||||
|
||||
/// \brief Determine whether this is an __if_exists statement.
|
||||
bool isIfExists() const { return IsIfExists; }
|
||||
|
||||
/// \brief Determine whether this is an __if_exists statement.
|
||||
bool isIfNotExists() const { return !IsIfExists; }
|
||||
|
||||
/// \brief Retrieve the nested-name-specifier that qualifies this name, if
|
||||
/// any.
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
/// \brief Retrieve the name of the entity we're testing for, along with
|
||||
/// location information
|
||||
DeclarationNameInfo getNameInfo() const { return NameInfo; }
|
||||
|
||||
/// \brief Retrieve the compound statement that will be included in the
|
||||
/// program only if the existence of the symbol matches the initial keyword.
|
||||
CompoundStmt *getSubStmt() const {
|
||||
return reinterpret_cast<CompoundStmt *>(SubStmt);
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(KeywordLoc, SubStmt->getLocEnd());
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(&SubStmt, &SubStmt+1);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == MSDependentExistsStmtClass;
|
||||
}
|
||||
|
||||
static bool classof(MSDependentExistsStmt *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
|||
|
|
@ -90,14 +90,12 @@ public:
|
|||
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
|
||||
|
||||
DERIVED& operator++() {
|
||||
if (inDecl() || inDeclGroup()) {
|
||||
if (getVAPtr()) NextVA();
|
||||
else NextDecl();
|
||||
}
|
||||
else if (inSizeOfTypeVA())
|
||||
if (inStmt())
|
||||
++stmt;
|
||||
else if (getVAPtr())
|
||||
NextVA();
|
||||
else
|
||||
++stmt;
|
||||
NextDecl();
|
||||
|
||||
return static_cast<DERIVED&>(*this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#define LLVM_CLANG_AST_STMTOBJC_H
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ public:
|
|||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
@ -103,7 +104,7 @@ public:
|
|||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtCatchLoc, Body->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +134,7 @@ public:
|
|||
Stmt *getFinallyBody() { return AtFinallyStmt; }
|
||||
void setFinallyBody(Stmt *S) { AtFinallyStmt = S; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
@ -240,7 +241,7 @@ public:
|
|||
getStmts()[1 + NumCatchStmts] = S;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const;
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtTryStmtClass;
|
||||
|
|
@ -294,7 +295,7 @@ public:
|
|||
}
|
||||
void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +328,7 @@ public:
|
|||
SourceLocation getThrowLoc() { return AtThrowLoc; }
|
||||
void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
if (Throw)
|
||||
return SourceRange(AtThrowLoc, Throw->getLocEnd());
|
||||
else
|
||||
|
|
@ -360,7 +361,7 @@ public:
|
|||
Stmt *getSubStmt() { return SubStmt; }
|
||||
void setSubStmt(Stmt *S) { SubStmt = S; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, SubStmt->getLocEnd());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ public:
|
|||
// below.
|
||||
if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
default: llvm_unreachable("Unknown binary operator!");
|
||||
case BO_PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator);
|
||||
case BO_PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator);
|
||||
case BO_Mul: DISPATCH(BinMul, BinaryOperator);
|
||||
|
|
@ -80,7 +79,6 @@ public:
|
|||
}
|
||||
} else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) {
|
||||
switch (UnOp->getOpcode()) {
|
||||
default: llvm_unreachable("Unknown unary operator!");
|
||||
case UO_PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
|
||||
case UO_PostDec: DISPATCH(UnaryPostDec, UnaryOperator);
|
||||
case UO_PreInc: DISPATCH(UnaryPreInc, UnaryOperator);
|
||||
|
|
|
|||
|
|
@ -15,11 +15,12 @@
|
|||
#ifndef LLVM_CLANG_AST_TEMPLATEBASE_H
|
||||
#define LLVM_CLANG_AST_TEMPLATEBASE_H
|
||||
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace llvm {
|
||||
class FoldingSetNodeID;
|
||||
|
|
@ -100,7 +101,6 @@ public:
|
|||
/// declaration, which is either an external declaration or a
|
||||
/// template declaration.
|
||||
TemplateArgument(Decl *D) : Kind(Declaration) {
|
||||
// FIXME: Need to be sure we have the "canonical" declaration!
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(D);
|
||||
}
|
||||
|
||||
|
|
@ -457,7 +457,7 @@ public:
|
|||
}
|
||||
|
||||
/// \brief - Fetches the full source range of the argument.
|
||||
SourceRange getSourceRange() const;
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
const TemplateArgument &getArgument() const {
|
||||
return Argument;
|
||||
|
|
@ -589,7 +589,42 @@ struct ASTTemplateArgumentListInfo {
|
|||
bool &ContainsUnexpandedParameterPack);
|
||||
void copyInto(TemplateArgumentListInfo &List) const;
|
||||
static std::size_t sizeFor(unsigned NumTemplateArgs);
|
||||
static std::size_t sizeFor(const TemplateArgumentListInfo &List);
|
||||
};
|
||||
|
||||
/// \brief Extends ASTTemplateArgumentListInfo with the source location
|
||||
/// information for the template keyword; this is used as part of the
|
||||
/// representation of qualified identifiers, such as S<T>::template apply<T>.
|
||||
struct ASTTemplateKWAndArgsInfo : public ASTTemplateArgumentListInfo {
|
||||
typedef ASTTemplateArgumentListInfo Base;
|
||||
|
||||
// NOTE: the source location of the (optional) template keyword is
|
||||
// stored after all template arguments.
|
||||
|
||||
/// \brief Get the source location of the template keyword.
|
||||
SourceLocation getTemplateKeywordLoc() const {
|
||||
return *reinterpret_cast<const SourceLocation*>
|
||||
(getTemplateArgs() + NumTemplateArgs);
|
||||
}
|
||||
|
||||
/// \brief Sets the source location of the template keyword.
|
||||
void setTemplateKeywordLoc(SourceLocation TemplateKWLoc) {
|
||||
*reinterpret_cast<SourceLocation*>
|
||||
(getTemplateArgs() + NumTemplateArgs) = TemplateKWLoc;
|
||||
}
|
||||
|
||||
static const ASTTemplateKWAndArgsInfo*
|
||||
Create(ASTContext &C, SourceLocation TemplateKWLoc,
|
||||
const TemplateArgumentListInfo &List);
|
||||
|
||||
void initializeFrom(SourceLocation TemplateKWLoc,
|
||||
const TemplateArgumentListInfo &List);
|
||||
void initializeFrom(SourceLocation TemplateKWLoc,
|
||||
const TemplateArgumentListInfo &List,
|
||||
bool &Dependent, bool &InstantiationDependent,
|
||||
bool &ContainsUnexpandedParameterPack);
|
||||
void initializeFrom(SourceLocation TemplateKWLoc);
|
||||
|
||||
static std::size_t sizeFor(unsigned NumTemplateArgs);
|
||||
};
|
||||
|
||||
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -18,6 +18,7 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
|
|
@ -93,9 +94,11 @@ public:
|
|||
SourceLocation getEndLoc() const;
|
||||
|
||||
/// \brief Get the full source range.
|
||||
SourceRange getSourceRange() const {
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getBeginLoc(), getEndLoc());
|
||||
}
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
|
||||
|
||||
/// \brief Get the local source range.
|
||||
SourceRange getLocalSourceRange() const {
|
||||
|
|
@ -159,7 +162,8 @@ public:
|
|||
static bool classof(const TypeLoc *TL) { return true; }
|
||||
|
||||
private:
|
||||
static void initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation Loc);
|
||||
static void initializeImpl(ASTContext &Context, TypeLoc TL,
|
||||
SourceLocation Loc);
|
||||
static TypeLoc getNextTypeLocImpl(TypeLoc TL);
|
||||
static TypeLoc IgnoreParensImpl(TypeLoc TL);
|
||||
static SourceRange getLocalSourceRangeImpl(TypeLoc TL);
|
||||
|
|
@ -226,7 +230,7 @@ public:
|
|||
|
||||
/// \brief Returns the size of the type source info data block.
|
||||
unsigned getFullDataSize() const {
|
||||
return getLocalDataSize() +
|
||||
return getLocalDataSize() +
|
||||
getFullDataSizeForType(getType().getLocalUnqualifiedType());
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +330,7 @@ protected:
|
|||
void *getExtraLocalData() const {
|
||||
return getLocalData() + 1;
|
||||
}
|
||||
|
||||
|
||||
void *getNonLocalData() const {
|
||||
return static_cast<char*>(Base::Data) + asDerived()->getLocalDataSize();
|
||||
}
|
||||
|
|
@ -392,7 +396,7 @@ struct TypeSpecLocInfo {
|
|||
|
||||
/// \brief A reasonable base class for TypeLocs that correspond to
|
||||
/// types that are written as a type-specifier.
|
||||
class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
TypeSpecTypeLoc,
|
||||
Type,
|
||||
TypeSpecLocInfo> {
|
||||
|
|
@ -566,10 +570,11 @@ class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
|||
public:
|
||||
TagDecl *getDecl() const { return getTypePtr()->getDecl(); }
|
||||
|
||||
/// \brief True if the tag was defined in this type specifier.
|
||||
/// \brief True if the tag was defined in this type specifier.
|
||||
bool isDefinition() const {
|
||||
return getDecl()->isCompleteDefinition() &&
|
||||
(getNameLoc().isInvalid() || getNameLoc() == getDecl()->getLocation());
|
||||
TagDecl *D = getDecl();
|
||||
return D->isCompleteDefinition() &&
|
||||
(D->getIdentifier() == 0 || D->getLocation() == getNameLoc());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -789,7 +794,7 @@ public:
|
|||
assert(i < getNumProtocols() && "Index is out of bounds!");
|
||||
return *(this->getTypePtr()->qual_begin() + i);
|
||||
}
|
||||
|
||||
|
||||
bool hasBaseTypeAsWritten() const {
|
||||
return getLocalData()->HasBaseTypeAsWritten;
|
||||
}
|
||||
|
|
@ -900,11 +905,11 @@ struct PointerLikeLocInfo {
|
|||
SourceLocation StarLoc;
|
||||
};
|
||||
|
||||
/// A base class for
|
||||
/// A base class for
|
||||
template <class Derived, class TypeClass, class LocalData = PointerLikeLocInfo>
|
||||
class PointerLikeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, Derived,
|
||||
TypeClass, LocalData> {
|
||||
public:
|
||||
public:
|
||||
SourceLocation getSigilLoc() const {
|
||||
return this->getLocalData()->StarLoc;
|
||||
}
|
||||
|
|
@ -1077,6 +1082,10 @@ public:
|
|||
getLocalData()->TrailingReturn = Trailing;
|
||||
}
|
||||
|
||||
ArrayRef<ParmVarDecl *> getParams() const {
|
||||
return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
|
||||
}
|
||||
|
||||
// ParmVarDecls* are stored after Info, one for each argument.
|
||||
ParmVarDecl **getParmArray() const {
|
||||
return (ParmVarDecl**) getExtraLocalData();
|
||||
|
|
@ -1213,6 +1222,7 @@ struct TemplateNameLocInfo {
|
|||
};
|
||||
|
||||
struct TemplateSpecializationLocInfo : TemplateNameLocInfo {
|
||||
SourceLocation TemplateKWLoc;
|
||||
SourceLocation LAngleLoc;
|
||||
SourceLocation RAngleLoc;
|
||||
};
|
||||
|
|
@ -1223,6 +1233,13 @@ class TemplateSpecializationTypeLoc :
|
|||
TemplateSpecializationType,
|
||||
TemplateSpecializationLocInfo> {
|
||||
public:
|
||||
SourceLocation getTemplateKeywordLoc() const {
|
||||
return getLocalData()->TemplateKWLoc;
|
||||
}
|
||||
void setTemplateKeywordLoc(SourceLocation Loc) {
|
||||
getLocalData()->TemplateKWLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getLAngleLoc() const {
|
||||
return getLocalData()->LAngleLoc;
|
||||
}
|
||||
|
|
@ -1271,13 +1288,17 @@ public:
|
|||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return SourceRange(getTemplateNameLoc(), getRAngleLoc());
|
||||
if (getTemplateKeywordLoc().isValid())
|
||||
return SourceRange(getTemplateKeywordLoc(), getRAngleLoc());
|
||||
else
|
||||
return SourceRange(getTemplateNameLoc(), getRAngleLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setTemplateKeywordLoc(Loc);
|
||||
setTemplateNameLoc(Loc);
|
||||
setLAngleLoc(Loc);
|
||||
setRAngleLoc(Loc);
|
||||
setTemplateNameLoc(Loc);
|
||||
initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(),
|
||||
getArgInfos(), Loc);
|
||||
}
|
||||
|
|
@ -1475,10 +1496,8 @@ class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
|||
};
|
||||
|
||||
struct ElaboratedLocInfo {
|
||||
SourceLocation KeywordLoc;
|
||||
|
||||
/// \brief Opaque data pointer used to reconstruct a nested-name-specifier
|
||||
/// from
|
||||
SourceLocation ElaboratedKWLoc;
|
||||
/// \brief Data associated with the nested-name-specifier location.
|
||||
void *QualifierData;
|
||||
};
|
||||
|
||||
|
|
@ -1487,31 +1506,32 @@ class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
|||
ElaboratedType,
|
||||
ElaboratedLocInfo> {
|
||||
public:
|
||||
SourceLocation getKeywordLoc() const {
|
||||
return this->getLocalData()->KeywordLoc;
|
||||
SourceLocation getElaboratedKeywordLoc() const {
|
||||
return this->getLocalData()->ElaboratedKWLoc;
|
||||
}
|
||||
void setKeywordLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->KeywordLoc = Loc;
|
||||
void setElaboratedKeywordLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->ElaboratedKWLoc = Loc;
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc getQualifierLoc() const {
|
||||
return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
|
||||
return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
|
||||
getLocalData()->QualifierData);
|
||||
}
|
||||
|
||||
|
||||
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
|
||||
assert(QualifierLoc.getNestedNameSpecifier()
|
||||
assert(QualifierLoc.getNestedNameSpecifier()
|
||||
== getTypePtr()->getQualifier() &&
|
||||
"Inconsistent nested-name-specifier pointer");
|
||||
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
if (getKeywordLoc().isValid())
|
||||
if (getElaboratedKeywordLoc().isValid())
|
||||
if (getQualifierLoc())
|
||||
return SourceRange(getKeywordLoc(), getQualifierLoc().getEndLoc());
|
||||
return SourceRange(getElaboratedKeywordLoc(),
|
||||
getQualifierLoc().getEndLoc());
|
||||
else
|
||||
return SourceRange(getKeywordLoc());
|
||||
return SourceRange(getElaboratedKeywordLoc());
|
||||
else
|
||||
return getQualifierLoc().getSourceRange();
|
||||
}
|
||||
|
|
@ -1537,9 +1557,6 @@ public:
|
|||
// type is some sort of TypeDeclTypeLoc.
|
||||
struct DependentNameLocInfo : ElaboratedLocInfo {
|
||||
SourceLocation NameLoc;
|
||||
|
||||
/// \brief Data associated with the nested-name-specifier location.
|
||||
void *QualifierData;
|
||||
};
|
||||
|
||||
class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
|
|
@ -1547,25 +1564,25 @@ class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
|||
DependentNameType,
|
||||
DependentNameLocInfo> {
|
||||
public:
|
||||
SourceLocation getKeywordLoc() const {
|
||||
return this->getLocalData()->KeywordLoc;
|
||||
SourceLocation getElaboratedKeywordLoc() const {
|
||||
return this->getLocalData()->ElaboratedKWLoc;
|
||||
}
|
||||
void setKeywordLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->KeywordLoc = Loc;
|
||||
void setElaboratedKeywordLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->ElaboratedKWLoc = Loc;
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc getQualifierLoc() const {
|
||||
return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
|
||||
return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
|
||||
getLocalData()->QualifierData);
|
||||
}
|
||||
|
||||
|
||||
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
|
||||
assert(QualifierLoc.getNestedNameSpecifier()
|
||||
assert(QualifierLoc.getNestedNameSpecifier()
|
||||
== getTypePtr()->getQualifier() &&
|
||||
"Inconsistent nested-name-specifier pointer");
|
||||
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
|
||||
}
|
||||
|
||||
|
||||
SourceLocation getNameLoc() const {
|
||||
return this->getLocalData()->NameLoc;
|
||||
}
|
||||
|
|
@ -1574,8 +1591,8 @@ public:
|
|||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
if (getKeywordLoc().isValid())
|
||||
return SourceRange(getKeywordLoc(), getNameLoc());
|
||||
if (getElaboratedKeywordLoc().isValid())
|
||||
return SourceRange(getElaboratedKeywordLoc(), getNameLoc());
|
||||
else
|
||||
return SourceRange(getQualifierLoc().getBeginLoc(), getNameLoc());
|
||||
}
|
||||
|
|
@ -1590,7 +1607,7 @@ public:
|
|||
};
|
||||
|
||||
struct DependentTemplateSpecializationLocInfo : DependentNameLocInfo {
|
||||
SourceLocation KeywordLoc;
|
||||
SourceLocation TemplateKWLoc;
|
||||
SourceLocation LAngleLoc;
|
||||
SourceLocation RAngleLoc;
|
||||
// followed by a TemplateArgumentLocInfo[]
|
||||
|
|
@ -1602,41 +1619,48 @@ class DependentTemplateSpecializationTypeLoc :
|
|||
DependentTemplateSpecializationType,
|
||||
DependentTemplateSpecializationLocInfo> {
|
||||
public:
|
||||
SourceLocation getKeywordLoc() const {
|
||||
return this->getLocalData()->KeywordLoc;
|
||||
SourceLocation getElaboratedKeywordLoc() const {
|
||||
return this->getLocalData()->ElaboratedKWLoc;
|
||||
}
|
||||
void setKeywordLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->KeywordLoc = Loc;
|
||||
void setElaboratedKeywordLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->ElaboratedKWLoc = Loc;
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc getQualifierLoc() const {
|
||||
if (!getLocalData()->QualifierData)
|
||||
return NestedNameSpecifierLoc();
|
||||
|
||||
return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
|
||||
|
||||
return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
|
||||
getLocalData()->QualifierData);
|
||||
}
|
||||
|
||||
|
||||
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
|
||||
if (!QualifierLoc) {
|
||||
// Even if we have a nested-name-specifier in the dependent
|
||||
// Even if we have a nested-name-specifier in the dependent
|
||||
// template specialization type, we won't record the nested-name-specifier
|
||||
// location information when this type-source location information is
|
||||
// part of a nested-name-specifier.
|
||||
getLocalData()->QualifierData = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(QualifierLoc.getNestedNameSpecifier()
|
||||
|
||||
assert(QualifierLoc.getNestedNameSpecifier()
|
||||
== getTypePtr()->getQualifier() &&
|
||||
"Inconsistent nested-name-specifier pointer");
|
||||
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
|
||||
}
|
||||
|
||||
SourceLocation getNameLoc() const {
|
||||
SourceLocation getTemplateKeywordLoc() const {
|
||||
return getLocalData()->TemplateKWLoc;
|
||||
}
|
||||
void setTemplateKeywordLoc(SourceLocation Loc) {
|
||||
getLocalData()->TemplateKWLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getTemplateNameLoc() const {
|
||||
return this->getLocalData()->NameLoc;
|
||||
}
|
||||
void setNameLoc(SourceLocation Loc) {
|
||||
void setTemplateNameLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->NameLoc = Loc;
|
||||
}
|
||||
|
||||
|
|
@ -1670,12 +1694,14 @@ public:
|
|||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
if (getKeywordLoc().isValid())
|
||||
return SourceRange(getKeywordLoc(), getRAngleLoc());
|
||||
if (getElaboratedKeywordLoc().isValid())
|
||||
return SourceRange(getElaboratedKeywordLoc(), getRAngleLoc());
|
||||
else if (getQualifierLoc())
|
||||
return SourceRange(getQualifierLoc().getBeginLoc(), getRAngleLoc());
|
||||
else if (getTemplateKeywordLoc().isValid())
|
||||
return SourceRange(getTemplateKeywordLoc(), getRAngleLoc());
|
||||
else
|
||||
return SourceRange(getNameLoc(), getRAngleLoc());
|
||||
return SourceRange(getTemplateNameLoc(), getRAngleLoc());
|
||||
}
|
||||
|
||||
void copy(DependentTemplateSpecializationTypeLoc Loc) {
|
||||
|
|
@ -1702,7 +1728,7 @@ struct PackExpansionTypeLocInfo {
|
|||
};
|
||||
|
||||
class PackExpansionTypeLoc
|
||||
: public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc,
|
||||
: public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc,
|
||||
PackExpansionType, PackExpansionTypeLocInfo> {
|
||||
public:
|
||||
SourceLocation getEllipsisLoc() const {
|
||||
|
|
@ -1736,7 +1762,7 @@ struct AtomicTypeLocInfo {
|
|||
|
||||
class AtomicTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AtomicTypeLoc,
|
||||
AtomicType, AtomicTypeLocInfo> {
|
||||
public:
|
||||
public:
|
||||
TypeLoc getValueLoc() const {
|
||||
return this->getInnerTypeLoc();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ public:
|
|||
RetTy Visit(const Type *T) {
|
||||
// Top switch stmt: dispatch to VisitFooType for each FooType.
|
||||
switch (T->getTypeClass()) {
|
||||
default: llvm_unreachable("Unknown type class!");
|
||||
#define ABSTRACT_TYPE(CLASS, PARENT)
|
||||
#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type);
|
||||
#include "clang/AST/TypeNodes.def"
|
||||
}
|
||||
llvm_unreachable("Unknown type class!");
|
||||
}
|
||||
|
||||
// If the implementation chooses not to implement a certain visit method, fall
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
//===-- UsuallyTinyPtrVector.h - Pointer vector class -----------*- 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 UsuallyTinyPtrVector class, which is a vector that
|
||||
// optimizes the case where there is only one element.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H
|
||||
#define LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief A vector class template that is optimized for storing a single
|
||||
/// pointer element.
|
||||
template<typename T>
|
||||
class UsuallyTinyPtrVector {
|
||||
/// \brief Storage for the vector.
|
||||
///
|
||||
/// When the low bit is zero, this is a T *. When the
|
||||
/// low bit is one, this is a std::vector<T *> *.
|
||||
mutable uintptr_t Storage;
|
||||
|
||||
typedef std::vector<T*> vector_type;
|
||||
|
||||
public:
|
||||
UsuallyTinyPtrVector() : Storage(0) { }
|
||||
explicit UsuallyTinyPtrVector(T *Element)
|
||||
: Storage(reinterpret_cast<uintptr_t>(Element)) { }
|
||||
|
||||
bool empty() const { return !Storage; }
|
||||
|
||||
typedef const T **iterator;
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
size_t size() const;
|
||||
|
||||
void push_back(T *Method);
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
typename UsuallyTinyPtrVector<T>::iterator
|
||||
UsuallyTinyPtrVector<T>::begin() const {
|
||||
if ((Storage & 0x01) == 0)
|
||||
return reinterpret_cast<iterator>(&Storage);
|
||||
|
||||
vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
|
||||
return &Vec->front();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename UsuallyTinyPtrVector<T>::iterator
|
||||
UsuallyTinyPtrVector<T>::end() const {
|
||||
if ((Storage & 0x01) == 0) {
|
||||
if (Storage == 0)
|
||||
return reinterpret_cast<iterator>(&Storage);
|
||||
|
||||
return reinterpret_cast<iterator>(&Storage) + 1;
|
||||
}
|
||||
|
||||
vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
|
||||
return &Vec->front() + Vec->size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t UsuallyTinyPtrVector<T>::size() const {
|
||||
if ((Storage & 0x01) == 0)
|
||||
return (Storage == 0) ? 0 : 1;
|
||||
|
||||
vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
|
||||
return Vec->size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void UsuallyTinyPtrVector<T>::push_back(T *Element) {
|
||||
if (Storage == 0) {
|
||||
// 0 -> 1 element.
|
||||
Storage = reinterpret_cast<uintptr_t>(Element);
|
||||
return;
|
||||
}
|
||||
|
||||
vector_type *Vec;
|
||||
if ((Storage & 0x01) == 0) {
|
||||
// 1 -> 2 elements. Allocate a new vector and push the element into that
|
||||
// vector.
|
||||
Vec = new vector_type;
|
||||
Vec->push_back(reinterpret_cast<T *>(Storage));
|
||||
Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01;
|
||||
} else
|
||||
Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
|
||||
|
||||
// Add the new element to the vector.
|
||||
Vec->push_back(Element);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void UsuallyTinyPtrVector<T>::Destroy() {
|
||||
if (Storage & 0x01)
|
||||
delete reinterpret_cast<vector_type *>(Storage & ~0x01);
|
||||
|
||||
Storage = 0;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -34,16 +34,16 @@ public:
|
|||
CK_OffsetToTop,
|
||||
CK_RTTI,
|
||||
CK_FunctionPointer,
|
||||
|
||||
|
||||
/// CK_CompleteDtorPointer - A pointer to the complete destructor.
|
||||
CK_CompleteDtorPointer,
|
||||
|
||||
|
||||
/// CK_DeletingDtorPointer - A pointer to the deleting destructor.
|
||||
CK_DeletingDtorPointer,
|
||||
|
||||
|
||||
/// CK_UnusedFunctionPointer - In some cases, a vtable function pointer
|
||||
/// will end up never being called. Such vtable function pointers are
|
||||
/// represented as a CK_UnusedFunctionPointer.
|
||||
/// represented as a CK_UnusedFunctionPointer.
|
||||
CK_UnusedFunctionPointer
|
||||
};
|
||||
|
||||
|
|
@ -60,34 +60,34 @@ public:
|
|||
static VTableComponent MakeOffsetToTop(CharUnits Offset) {
|
||||
return VTableComponent(CK_OffsetToTop, Offset);
|
||||
}
|
||||
|
||||
|
||||
static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
|
||||
return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
|
||||
}
|
||||
|
||||
static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
|
||||
assert(!isa<CXXDestructorDecl>(MD) &&
|
||||
assert(!isa<CXXDestructorDecl>(MD) &&
|
||||
"Don't use MakeFunction with destructors!");
|
||||
|
||||
return VTableComponent(CK_FunctionPointer,
|
||||
return VTableComponent(CK_FunctionPointer,
|
||||
reinterpret_cast<uintptr_t>(MD));
|
||||
}
|
||||
|
||||
|
||||
static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
|
||||
return VTableComponent(CK_CompleteDtorPointer,
|
||||
reinterpret_cast<uintptr_t>(DD));
|
||||
}
|
||||
|
||||
static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
|
||||
return VTableComponent(CK_DeletingDtorPointer,
|
||||
return VTableComponent(CK_DeletingDtorPointer,
|
||||
reinterpret_cast<uintptr_t>(DD));
|
||||
}
|
||||
|
||||
static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
|
||||
assert(!isa<CXXDestructorDecl>(MD) &&
|
||||
assert(!isa<CXXDestructorDecl>(MD) &&
|
||||
"Don't use MakeUnusedFunction with destructors!");
|
||||
return VTableComponent(CK_UnusedFunctionPointer,
|
||||
reinterpret_cast<uintptr_t>(MD));
|
||||
reinterpret_cast<uintptr_t>(MD));
|
||||
}
|
||||
|
||||
static VTableComponent getFromOpaqueInteger(uint64_t I) {
|
||||
|
|
@ -101,88 +101,88 @@ public:
|
|||
|
||||
CharUnits getVCallOffset() const {
|
||||
assert(getKind() == CK_VCallOffset && "Invalid component kind!");
|
||||
|
||||
|
||||
return getOffset();
|
||||
}
|
||||
|
||||
CharUnits getVBaseOffset() const {
|
||||
assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
|
||||
|
||||
|
||||
return getOffset();
|
||||
}
|
||||
|
||||
CharUnits getOffsetToTop() const {
|
||||
assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
|
||||
|
||||
|
||||
return getOffset();
|
||||
}
|
||||
|
||||
|
||||
const CXXRecordDecl *getRTTIDecl() const {
|
||||
assert(getKind() == CK_RTTI && "Invalid component kind!");
|
||||
|
||||
|
||||
return reinterpret_cast<CXXRecordDecl *>(getPointer());
|
||||
}
|
||||
|
||||
|
||||
const CXXMethodDecl *getFunctionDecl() const {
|
||||
assert(getKind() == CK_FunctionPointer);
|
||||
|
||||
|
||||
return reinterpret_cast<CXXMethodDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXDestructorDecl *getDestructorDecl() const {
|
||||
assert((getKind() == CK_CompleteDtorPointer ||
|
||||
getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
|
||||
|
||||
|
||||
return reinterpret_cast<CXXDestructorDecl *>(getPointer());
|
||||
}
|
||||
|
||||
const CXXMethodDecl *getUnusedFunctionDecl() const {
|
||||
assert(getKind() == CK_UnusedFunctionPointer);
|
||||
|
||||
|
||||
return reinterpret_cast<CXXMethodDecl *>(getPointer());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
VTableComponent(Kind ComponentKind, CharUnits Offset) {
|
||||
assert((ComponentKind == CK_VCallOffset ||
|
||||
assert((ComponentKind == CK_VCallOffset ||
|
||||
ComponentKind == CK_VBaseOffset ||
|
||||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
|
||||
assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
|
||||
|
||||
|
||||
Value = ((Offset.getQuantity() << 3) | ComponentKind);
|
||||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
|
||||
assert((ComponentKind == CK_RTTI ||
|
||||
assert((ComponentKind == CK_RTTI ||
|
||||
ComponentKind == CK_FunctionPointer ||
|
||||
ComponentKind == CK_CompleteDtorPointer ||
|
||||
ComponentKind == CK_DeletingDtorPointer ||
|
||||
ComponentKind == CK_UnusedFunctionPointer) &&
|
||||
"Invalid component kind!");
|
||||
|
||||
|
||||
assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
|
||||
|
||||
|
||||
Value = Ptr | ComponentKind;
|
||||
}
|
||||
|
||||
|
||||
CharUnits getOffset() const {
|
||||
assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
|
||||
getKind() == CK_OffsetToTop) && "Invalid component kind!");
|
||||
|
||||
|
||||
return CharUnits::fromQuantity(Value >> 3);
|
||||
}
|
||||
|
||||
uintptr_t getPointer() const {
|
||||
assert((getKind() == CK_RTTI ||
|
||||
assert((getKind() == CK_RTTI ||
|
||||
getKind() == CK_FunctionPointer ||
|
||||
getKind() == CK_CompleteDtorPointer ||
|
||||
getKind() == CK_DeletingDtorPointer ||
|
||||
getKind() == CK_UnusedFunctionPointer) &&
|
||||
"Invalid component kind!");
|
||||
|
||||
|
||||
return static_cast<uintptr_t>(Value & ~7ULL);
|
||||
}
|
||||
|
||||
|
||||
explicit VTableComponent(uint64_t Value)
|
||||
: Value(Value) { }
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ private:
|
|||
/// VTableThunks - Contains thunks needed by vtables.
|
||||
uint64_t NumVTableThunks;
|
||||
VTableThunkTy *VTableThunks;
|
||||
|
||||
|
||||
/// Address points - Address points for all vtables.
|
||||
AddressPointsMapTy AddressPoints;
|
||||
|
||||
|
|
@ -265,10 +265,10 @@ class VTableContext {
|
|||
ASTContext &Context;
|
||||
|
||||
public:
|
||||
typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
|
||||
typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
|
||||
VTableThunksTy;
|
||||
typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
|
||||
|
||||
|
||||
private:
|
||||
/// MethodVTableIndices - Contains the index (relative to the vtable address
|
||||
/// point) where the function pointer for a virtual function is stored.
|
||||
|
|
@ -279,22 +279,22 @@ private:
|
|||
VTableLayoutMapTy;
|
||||
VTableLayoutMapTy VTableLayouts;
|
||||
|
||||
/// NumVirtualFunctionPointers - Contains the number of virtual function
|
||||
/// NumVirtualFunctionPointers - Contains the number of virtual function
|
||||
/// pointers in the vtable for a given record decl.
|
||||
llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
|
||||
|
||||
typedef std::pair<const CXXRecordDecl *,
|
||||
const CXXRecordDecl *> ClassPairTy;
|
||||
|
||||
/// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
|
||||
/// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
|
||||
/// the address point) in chars where the offsets for virtual bases of a class
|
||||
/// are stored.
|
||||
typedef llvm::DenseMap<ClassPairTy, CharUnits>
|
||||
typedef llvm::DenseMap<ClassPairTy, CharUnits>
|
||||
VirtualBaseClassOffsetOffsetsMapTy;
|
||||
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
|
||||
|
||||
typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
|
||||
|
||||
|
||||
/// Thunks - Contains all thunks that a given method decl will need.
|
||||
ThunksMapTy Thunks;
|
||||
|
||||
|
|
@ -312,7 +312,7 @@ public:
|
|||
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
|
||||
ComputeVTableRelatedInformation(RD);
|
||||
assert(VTableLayouts.count(RD) && "No layout for this record decl!");
|
||||
|
||||
|
||||
return *VTableLayouts[RD];
|
||||
}
|
||||
|
||||
|
|
@ -337,14 +337,14 @@ public:
|
|||
/// getNumVirtualFunctionPointers - Return the number of virtual function
|
||||
/// pointers in the vtable for a given record decl.
|
||||
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
|
||||
|
||||
|
||||
/// getMethodVTableIndex - Return the index (relative to the vtable address
|
||||
/// point) where the function pointer for the given virtual function is
|
||||
/// stored.
|
||||
uint64_t getMethodVTableIndex(GlobalDecl GD);
|
||||
|
||||
/// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the
|
||||
/// vtable address point) where the offset of the virtual base that contains
|
||||
/// vtable address point) where the offset of the virtual base that contains
|
||||
/// the given base is stored, otherwise, if no virtual base contains the given
|
||||
/// class, return 0. Base must be a virtual base class or an unambigious
|
||||
/// base.
|
||||
|
|
|
|||
212
include/clang/Analysis/Analyses/Dominators.h
Normal file
212
include/clang/Analysis/Analyses/Dominators.h
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
//==- Dominators.h - Implementation of dominators tree for Clang CFG C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the dominators tree functionality for Clang CFGs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DOMINATORS_H
|
||||
#define LLVM_CLANG_DOMINATORS_H
|
||||
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/Analysis/DominatorInternals.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CFGBlock;
|
||||
typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode;
|
||||
|
||||
/// \brief Concrete subclass of DominatorTreeBase for Clang
|
||||
/// This class implements the dominators tree functionality given a Clang CFG.
|
||||
///
|
||||
class DominatorTree : public ManagedAnalysis {
|
||||
virtual void anchor();
|
||||
public:
|
||||
llvm::DominatorTreeBase<CFGBlock>* DT;
|
||||
|
||||
DominatorTree() {
|
||||
DT = new llvm::DominatorTreeBase<CFGBlock>(false);
|
||||
}
|
||||
|
||||
~DominatorTree() {
|
||||
delete DT;
|
||||
}
|
||||
|
||||
llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; }
|
||||
|
||||
/// \brief This method returns the root CFGBlock of the dominators tree.
|
||||
///
|
||||
inline CFGBlock *getRoot() const {
|
||||
return DT->getRoot();
|
||||
}
|
||||
|
||||
/// \brief This method returns the root DomTreeNode, which is the wrapper
|
||||
/// for CFGBlock.
|
||||
inline DomTreeNode *getRootNode() const {
|
||||
return DT->getRootNode();
|
||||
}
|
||||
|
||||
/// \brief This method compares two dominator trees.
|
||||
/// The method returns false if the other dominator tree matches this
|
||||
/// dominator tree, otherwise returns true.
|
||||
///
|
||||
inline bool compare(DominatorTree &Other) const {
|
||||
DomTreeNode *R = getRootNode();
|
||||
DomTreeNode *OtherR = Other.getRootNode();
|
||||
|
||||
if (!R || !OtherR || R->getBlock() != OtherR->getBlock())
|
||||
return true;
|
||||
|
||||
if (DT->compare(Other.getBase()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief This method builds the dominator tree for a given CFG
|
||||
/// The CFG information is passed via AnalysisDeclContext
|
||||
///
|
||||
void buildDominatorTree(AnalysisDeclContext &AC) {
|
||||
cfg = AC.getCFG();
|
||||
DT->recalculate(*cfg);
|
||||
}
|
||||
|
||||
/// \brief This method dumps immediate dominators for each block,
|
||||
/// mainly used for debug purposes.
|
||||
///
|
||||
void dump() {
|
||||
llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n";
|
||||
for (CFG::const_iterator I = cfg->begin(),
|
||||
E = cfg->end(); I != E; ++I) {
|
||||
if(DT->getNode(*I)->getIDom())
|
||||
llvm::errs() << "(" << (*I)->getBlockID()
|
||||
<< ","
|
||||
<< DT->getNode(*I)->getIDom()->getBlock()->getBlockID()
|
||||
<< ")\n";
|
||||
else llvm::errs() << "(" << (*I)->getBlockID()
|
||||
<< "," << (*I)->getBlockID() << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief This method tests if one CFGBlock dominates the other.
|
||||
/// The method return true if A dominates B, false otherwise.
|
||||
/// Note a block always dominates itself.
|
||||
///
|
||||
inline bool dominates(const CFGBlock* A, const CFGBlock* B) const {
|
||||
return DT->dominates(A, B);
|
||||
}
|
||||
|
||||
/// \brief This method tests if one CFGBlock properly dominates the other.
|
||||
/// The method return true if A properly dominates B, false otherwise.
|
||||
///
|
||||
bool properlyDominates(const CFGBlock*A, const CFGBlock*B) const {
|
||||
return DT->properlyDominates(A, B);
|
||||
}
|
||||
|
||||
/// \brief This method finds the nearest common dominator CFG block
|
||||
/// for CFG block A and B. If there is no such block then return NULL.
|
||||
///
|
||||
inline CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) {
|
||||
return DT->findNearestCommonDominator(A, B);
|
||||
}
|
||||
|
||||
inline const CFGBlock *findNearestCommonDominator(const CFGBlock *A,
|
||||
const CFGBlock *B) {
|
||||
return DT->findNearestCommonDominator(A, B);
|
||||
}
|
||||
|
||||
/// \brief This method is used to update the dominator
|
||||
/// tree information when a node's immediate dominator changes.
|
||||
///
|
||||
inline void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) {
|
||||
DT->changeImmediateDominator(N, NewIDom);
|
||||
}
|
||||
|
||||
/// \brief This method tests if the given CFGBlock can be reachable from root.
|
||||
/// Returns true if reachable, false otherwise.
|
||||
///
|
||||
bool isReachableFromEntry(const CFGBlock *A) {
|
||||
return DT->isReachableFromEntry(A);
|
||||
}
|
||||
|
||||
/// \brief This method releases the memory held by the dominator tree.
|
||||
///
|
||||
virtual void releaseMemory() {
|
||||
DT->releaseMemory();
|
||||
}
|
||||
|
||||
/// \brief This method converts the dominator tree to human readable form.
|
||||
///
|
||||
virtual void print(raw_ostream &OS, const llvm::Module* M= 0) const {
|
||||
DT->print(OS);
|
||||
}
|
||||
|
||||
private:
|
||||
CFG *cfg;
|
||||
};
|
||||
|
||||
inline void WriteAsOperand(raw_ostream &OS, const CFGBlock *BB,
|
||||
bool t) {
|
||||
OS << "BB#" << BB->getBlockID();
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
//===-------------------------------------
|
||||
/// DominatorTree GraphTraits specialization so the DominatorTree can be
|
||||
/// iterable by generic graph iterators.
|
||||
///
|
||||
namespace llvm {
|
||||
template <> struct GraphTraits< ::clang::DomTreeNode* > {
|
||||
typedef ::clang::DomTreeNode NodeType;
|
||||
typedef NodeType::iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(NodeType *N) {
|
||||
return N;
|
||||
}
|
||||
static inline ChildIteratorType child_begin(NodeType *N) {
|
||||
return N->begin();
|
||||
}
|
||||
static inline ChildIteratorType child_end(NodeType *N) {
|
||||
return N->end();
|
||||
}
|
||||
|
||||
typedef df_iterator< ::clang::DomTreeNode* > nodes_iterator;
|
||||
|
||||
static nodes_iterator nodes_begin(::clang::DomTreeNode *N) {
|
||||
return df_begin(getEntryNode(N));
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(::clang::DomTreeNode *N) {
|
||||
return df_end(getEntryNode(N));
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct GraphTraits< ::clang::DominatorTree* >
|
||||
: public GraphTraits< ::clang::DomTreeNode* > {
|
||||
static NodeType *getEntryNode(::clang::DominatorTree *DT) {
|
||||
return DT->getRootNode();
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_begin(::clang::DominatorTree *N) {
|
||||
return df_begin(getEntryNode(N));
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(::clang::DominatorTree *N) {
|
||||
return df_end(getEntryNode(N));
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
@ -66,11 +66,14 @@ public:
|
|||
AsChar, // 'hh'
|
||||
AsShort, // 'h'
|
||||
AsLong, // 'l'
|
||||
AsLongLong, // 'll', 'q' (BSD, deprecated)
|
||||
AsLongLong, // 'll'
|
||||
AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)
|
||||
AsIntMax, // 'j'
|
||||
AsSizeT, // 'z'
|
||||
AsPtrDiff, // 't'
|
||||
AsLongDouble, // 'L'
|
||||
AsAllocate, // for '%as', GNU extension to C90 scanf
|
||||
AsMAllocate, // for '%ms', GNU extension to scanf
|
||||
AsWideChar = AsLong // for '%ls', only makes sense for printf
|
||||
};
|
||||
|
||||
|
|
@ -104,7 +107,7 @@ private:
|
|||
const char *Position;
|
||||
Kind kind;
|
||||
};
|
||||
|
||||
|
||||
class ConversionSpecifier {
|
||||
public:
|
||||
enum Kind {
|
||||
|
|
@ -113,14 +116,14 @@ public:
|
|||
cArg,
|
||||
dArg,
|
||||
iArg,
|
||||
IntArgBeg = cArg, IntArgEnd = iArg,
|
||||
|
||||
IntArgBeg = cArg, IntArgEnd = iArg,
|
||||
|
||||
oArg,
|
||||
uArg,
|
||||
xArg,
|
||||
XArg,
|
||||
UIntArgBeg = oArg, UIntArgEnd = XArg,
|
||||
|
||||
|
||||
fArg,
|
||||
FArg,
|
||||
eArg,
|
||||
|
|
@ -130,44 +133,44 @@ public:
|
|||
aArg,
|
||||
AArg,
|
||||
DoubleArgBeg = fArg, DoubleArgEnd = AArg,
|
||||
|
||||
|
||||
sArg,
|
||||
pArg,
|
||||
nArg,
|
||||
PercentArg,
|
||||
CArg,
|
||||
SArg,
|
||||
|
||||
|
||||
// ** Printf-specific **
|
||||
|
||||
|
||||
// Objective-C specific specifiers.
|
||||
ObjCObjArg, // '@'
|
||||
ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
|
||||
|
||||
|
||||
// GlibC specific specifiers.
|
||||
PrintErrno, // 'm'
|
||||
|
||||
|
||||
PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
|
||||
|
||||
// ** Scanf-specific **
|
||||
|
||||
// ** Scanf-specific **
|
||||
ScanListArg, // '['
|
||||
ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
|
||||
};
|
||||
|
||||
|
||||
ConversionSpecifier(bool isPrintf)
|
||||
: IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
|
||||
|
||||
|
||||
ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
|
||||
: IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {}
|
||||
|
||||
|
||||
const char *getStart() const {
|
||||
return Position;
|
||||
}
|
||||
|
||||
|
||||
StringRef getCharacters() const {
|
||||
return StringRef(getStart(), getLength());
|
||||
}
|
||||
|
||||
|
||||
bool consumesDataArgument() const {
|
||||
switch (kind) {
|
||||
case PrintErrno:
|
||||
|
|
@ -178,15 +181,16 @@ public:
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
void setKind(Kind k) { kind = k; }
|
||||
unsigned getLength() const {
|
||||
return EndScanList ? EndScanList - Position : 1;
|
||||
}
|
||||
|
||||
|
||||
bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
|
||||
const char *toString() const;
|
||||
|
||||
|
||||
bool isPrintfKind() const { return IsPrintf; }
|
||||
|
||||
protected:
|
||||
|
|
@ -199,15 +203,18 @@ protected:
|
|||
class ArgTypeResult {
|
||||
public:
|
||||
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
|
||||
CStrTy, WCStrTy, WIntTy };
|
||||
AnyCharTy, CStrTy, WCStrTy, WIntTy };
|
||||
private:
|
||||
const Kind K;
|
||||
QualType T;
|
||||
ArgTypeResult(bool) : K(InvalidTy) {}
|
||||
const char *Name;
|
||||
ArgTypeResult(bool) : K(InvalidTy), Name(0) {}
|
||||
public:
|
||||
ArgTypeResult(Kind k = UnknownTy) : K(k) {}
|
||||
ArgTypeResult(QualType t) : K(SpecificTy), T(t) {}
|
||||
ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {}
|
||||
ArgTypeResult(Kind k = UnknownTy) : K(k), Name(0) {}
|
||||
ArgTypeResult(Kind k, const char *n) : K(k), Name(n) {}
|
||||
ArgTypeResult(QualType t) : K(SpecificTy), T(t), Name(0) {}
|
||||
ArgTypeResult(QualType t, const char *n) : K(SpecificTy), T(t), Name(n) {}
|
||||
ArgTypeResult(CanQualType t) : K(SpecificTy), T(t), Name(0) {}
|
||||
|
||||
static ArgTypeResult Invalid() { return ArgTypeResult(true); }
|
||||
|
||||
|
|
@ -222,6 +229,8 @@ public:
|
|||
bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
|
||||
|
||||
QualType getRepresentativeType(ASTContext &C) const;
|
||||
|
||||
std::string getRepresentativeTypeName(ASTContext &C) const;
|
||||
};
|
||||
|
||||
class OptionalAmount {
|
||||
|
|
@ -297,9 +306,9 @@ protected:
|
|||
LengthModifier LM;
|
||||
OptionalAmount FieldWidth;
|
||||
ConversionSpecifier CS;
|
||||
/// Positional arguments, an IEEE extension:
|
||||
/// IEEE Std 1003.1, 2004 Edition
|
||||
/// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
|
||||
/// Positional arguments, an IEEE extension:
|
||||
/// IEEE Std 1003.1, 2004 Edition
|
||||
/// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
|
||||
bool UsesPositionalArg;
|
||||
unsigned argIndex;
|
||||
public:
|
||||
|
|
@ -337,8 +346,14 @@ public:
|
|||
}
|
||||
|
||||
bool usesPositionalArg() const { return UsesPositionalArg; }
|
||||
|
||||
|
||||
bool hasValidLengthModifier() const;
|
||||
|
||||
bool hasStandardLengthModifier() const;
|
||||
|
||||
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
|
||||
|
||||
bool hasStandardLengthConversionCombination() const;
|
||||
};
|
||||
|
||||
} // end analyze_format_string namespace
|
||||
|
|
@ -348,7 +363,7 @@ public:
|
|||
|
||||
namespace analyze_printf {
|
||||
|
||||
class PrintfConversionSpecifier :
|
||||
class PrintfConversionSpecifier :
|
||||
public analyze_format_string::ConversionSpecifier {
|
||||
public:
|
||||
PrintfConversionSpecifier()
|
||||
|
|
@ -359,9 +374,8 @@ public:
|
|||
|
||||
bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
|
||||
bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
|
||||
bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
|
||||
bool isDoubleArg() const { return kind >= DoubleArgBeg &&
|
||||
kind <= DoubleArgBeg; }
|
||||
bool isDoubleArg() const { return kind >= DoubleArgBeg &&
|
||||
kind <= DoubleArgEnd; }
|
||||
unsigned getLength() const {
|
||||
// Conversion specifiers currently only are represented by
|
||||
// single characters, but we be flexible.
|
||||
|
|
@ -438,7 +452,7 @@ public:
|
|||
const OptionalAmount &getPrecision() const {
|
||||
return Precision;
|
||||
}
|
||||
|
||||
|
||||
bool consumesDataArgument() const {
|
||||
return getConversionSpecifier().consumesDataArgument();
|
||||
}
|
||||
|
|
@ -448,9 +462,9 @@ public:
|
|||
/// will return null if the format specifier does not have
|
||||
/// a matching data argument or the matching argument matches
|
||||
/// more than one type.
|
||||
ArgTypeResult getArgType(ASTContext &Ctx) const;
|
||||
ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
|
||||
|
||||
const OptionalFlag &hasThousandsGrouping() const {
|
||||
const OptionalFlag &hasThousandsGrouping() const {
|
||||
return HasThousandsGrouping;
|
||||
}
|
||||
const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
|
||||
|
|
@ -460,14 +474,15 @@ public:
|
|||
const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
|
||||
bool usesPositionalArg() const { return UsesPositionalArg; }
|
||||
|
||||
/// Changes the specifier and length according to a QualType, retaining any
|
||||
/// flags or options. Returns true on success, or false when a conversion
|
||||
/// was not successful.
|
||||
bool fixType(QualType QT);
|
||||
/// Changes the specifier and length according to a QualType, retaining any
|
||||
/// flags or options. Returns true on success, or false when a conversion
|
||||
/// was not successful.
|
||||
bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
|
||||
bool IsObjCLiteral);
|
||||
|
||||
void toString(raw_ostream &os) const;
|
||||
|
||||
// Validation methods - to check if any element results in undefined behavior
|
||||
// Validation methods - to check if any element results in undefined behavior
|
||||
bool hasValidPlusPrefix() const;
|
||||
bool hasValidAlternativeForm() const;
|
||||
bool hasValidLeadingZeros() const;
|
||||
|
|
@ -495,16 +510,41 @@ public:
|
|||
: ConversionSpecifier(false, pos, k) {}
|
||||
|
||||
void setEndScanList(const char *pos) { EndScanList = pos; }
|
||||
|
||||
|
||||
static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
|
||||
return !CS->isPrintfKind();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using analyze_format_string::ArgTypeResult;
|
||||
using analyze_format_string::LengthModifier;
|
||||
using analyze_format_string::OptionalAmount;
|
||||
using analyze_format_string::OptionalFlag;
|
||||
|
||||
class ScanfArgTypeResult : public ArgTypeResult {
|
||||
public:
|
||||
enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeResultTy };
|
||||
private:
|
||||
Kind K;
|
||||
ArgTypeResult A;
|
||||
const char *Name;
|
||||
QualType getRepresentativeType(ASTContext &C) const;
|
||||
public:
|
||||
ScanfArgTypeResult(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {}
|
||||
ScanfArgTypeResult(ArgTypeResult a, const char *n = 0)
|
||||
: K(PtrToArgTypeResultTy), A(a), Name(n) {
|
||||
assert(A.isValid());
|
||||
}
|
||||
|
||||
static ScanfArgTypeResult Invalid() { return ScanfArgTypeResult(InvalidTy); }
|
||||
|
||||
bool isValid() const { return K != InvalidTy; }
|
||||
|
||||
bool matchesType(ASTContext& C, QualType argTy) const;
|
||||
|
||||
std::string getRepresentativeTypeName(ASTContext& C) const;
|
||||
};
|
||||
|
||||
class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
OptionalFlag SuppressAssignment; // '*'
|
||||
public:
|
||||
|
|
@ -528,11 +568,17 @@ public:
|
|||
const ScanfConversionSpecifier &getConversionSpecifier() const {
|
||||
return cast<ScanfConversionSpecifier>(CS);
|
||||
}
|
||||
|
||||
|
||||
bool consumesDataArgument() const {
|
||||
return CS.consumesDataArgument() && !SuppressAssignment;
|
||||
}
|
||||
|
||||
ScanfArgTypeResult getArgType(ASTContext &Ctx) const;
|
||||
|
||||
bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
|
||||
|
||||
void toString(raw_ostream &os) const;
|
||||
|
||||
static ScanfSpecifier Parse(const char *beg, const char *end);
|
||||
};
|
||||
|
||||
|
|
@ -552,6 +598,8 @@ public:
|
|||
|
||||
virtual void HandleNullChar(const char *nullCharacter) {}
|
||||
|
||||
virtual void HandlePosition(const char *startPos, unsigned posLen) {}
|
||||
|
||||
virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
|
||||
PositionContext p) {}
|
||||
|
||||
|
|
@ -594,10 +642,10 @@ public:
|
|||
};
|
||||
|
||||
bool ParsePrintfString(FormatStringHandler &H,
|
||||
const char *beg, const char *end);
|
||||
const char *beg, const char *end, const LangOptions &LO);
|
||||
|
||||
bool ParseScanfString(FormatStringHandler &H,
|
||||
const char *beg, const char *end);
|
||||
const char *beg, const char *end, const LangOptions &LO);
|
||||
|
||||
} // end analyze_format_string namespace
|
||||
} // end clang namespace
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ public:
|
|||
friend class LiveVariables;
|
||||
};
|
||||
|
||||
struct Observer {
|
||||
class Observer {
|
||||
virtual void anchor();
|
||||
public:
|
||||
virtual ~Observer() {}
|
||||
|
||||
/// A callback invoked right before invoking the
|
||||
|
|
@ -70,7 +72,7 @@ public:
|
|||
virtual ~LiveVariables();
|
||||
|
||||
/// Compute the liveness information for a given CFG.
|
||||
static LiveVariables *computeLiveness(AnalysisContext &analysisContext,
|
||||
static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext,
|
||||
bool killAtAssign);
|
||||
|
||||
/// Return true if a variable is live at the end of a
|
||||
|
|
@ -93,7 +95,7 @@ public:
|
|||
|
||||
void runOnAllBlocks(Observer &obs);
|
||||
|
||||
static LiveVariables *create(AnalysisContext &analysisContext) {
|
||||
static LiveVariables *create(AnalysisDeclContext &analysisContext) {
|
||||
return computeLiveness(analysisContext, true);
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +108,7 @@ private:
|
|||
|
||||
class RelaxedLiveVariables : public LiveVariables {
|
||||
public:
|
||||
static LiveVariables *create(AnalysisContext &analysisContext) {
|
||||
static LiveVariables *create(AnalysisDeclContext &analysisContext) {
|
||||
return computeLiveness(analysisContext, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
111
include/clang/Analysis/Analyses/PostOrderCFGView.h
Normal file
111
include/clang/Analysis/Analyses/PostOrderCFGView.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
//===- PostOrderCFGView.h - Post order view of CFG blocks ---------*- C++ --*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements post order view of the blocks in a CFG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_POSTORDER_CFGVIEW
|
||||
#define LLVM_CLANG_POSTORDER_CFGVIEW
|
||||
|
||||
#include <vector>
|
||||
//#include <algorithm>
|
||||
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PostOrderCFGView : public ManagedAnalysis {
|
||||
virtual void anchor();
|
||||
public:
|
||||
/// \brief Implements a set of CFGBlocks using a BitVector.
|
||||
///
|
||||
/// This class contains a minimal interface, primarily dictated by the SetType
|
||||
/// template parameter of the llvm::po_iterator template, as used with
|
||||
/// external storage. We also use this set to keep track of which CFGBlocks we
|
||||
/// visit during the analysis.
|
||||
class CFGBlockSet {
|
||||
llvm::BitVector VisitedBlockIDs;
|
||||
public:
|
||||
// po_iterator requires this iterator, but the only interface needed is the
|
||||
// value_type typedef.
|
||||
struct iterator { typedef const CFGBlock *value_type; };
|
||||
|
||||
CFGBlockSet() {}
|
||||
CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
|
||||
|
||||
/// \brief Set the bit associated with a particular CFGBlock.
|
||||
/// This is the important method for the SetType template parameter.
|
||||
bool insert(const CFGBlock *Block) {
|
||||
// Note that insert() is called by po_iterator, which doesn't check to
|
||||
// make sure that Block is non-null. Moreover, the CFGBlock iterator will
|
||||
// occasionally hand out null pointers for pruned edges, so we catch those
|
||||
// here.
|
||||
if (Block == 0)
|
||||
return false; // if an edge is trivially false.
|
||||
if (VisitedBlockIDs.test(Block->getBlockID()))
|
||||
return false;
|
||||
VisitedBlockIDs.set(Block->getBlockID());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Check if the bit for a CFGBlock has been already set.
|
||||
/// This method is for tracking visited blocks in the main threadsafety
|
||||
/// loop. Block must not be null.
|
||||
bool alreadySet(const CFGBlock *Block) {
|
||||
return VisitedBlockIDs.test(Block->getBlockID());
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
|
||||
std::vector<const CFGBlock*> Blocks;
|
||||
|
||||
typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy;
|
||||
BlockOrderTy BlockOrder;
|
||||
|
||||
public:
|
||||
typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
|
||||
|
||||
PostOrderCFGView(const CFG *cfg);
|
||||
|
||||
iterator begin() { return Blocks.rbegin(); }
|
||||
iterator end() { return Blocks.rend(); }
|
||||
|
||||
bool empty() { return begin() == end(); }
|
||||
|
||||
struct BlockOrderCompare;
|
||||
friend struct BlockOrderCompare;
|
||||
|
||||
struct BlockOrderCompare {
|
||||
const PostOrderCFGView &POV;
|
||||
public:
|
||||
BlockOrderCompare(const PostOrderCFGView &pov) : POV(pov) {}
|
||||
bool operator()(const CFGBlock *b1, const CFGBlock *b2) const;
|
||||
};
|
||||
|
||||
BlockOrderCompare getComparator() const {
|
||||
return BlockOrderCompare(*this);
|
||||
}
|
||||
|
||||
// Used by AnalyisContext to construct this object.
|
||||
static const void *getTag();
|
||||
|
||||
static PostOrderCFGView *create(AnalysisDeclContext &analysisContext);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ namespace llvm {
|
|||
}
|
||||
|
||||
namespace clang {
|
||||
class AnalysisContext;
|
||||
class AnalysisDeclContext;
|
||||
class CFGBlock;
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +37,7 @@ namespace clang {
|
|||
namespace reachable_code {
|
||||
|
||||
class Callback {
|
||||
virtual void anchor();
|
||||
public:
|
||||
virtual ~Callback() {}
|
||||
virtual void HandleUnreachable(SourceLocation L, SourceRange R1,
|
||||
|
|
@ -48,7 +49,7 @@ public:
|
|||
unsigned ScanReachableFromBlock(const CFGBlock *Start,
|
||||
llvm::BitVector &Reachable);
|
||||
|
||||
void FindUnreachableCode(AnalysisContext &AC, Callback &CB);
|
||||
void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB);
|
||||
|
||||
}} // end namespace clang::reachable_code
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ enum LockErrorKind {
|
|||
class ThreadSafetyHandler {
|
||||
public:
|
||||
typedef llvm::StringRef Name;
|
||||
virtual ~ThreadSafetyHandler() = 0;
|
||||
virtual ~ThreadSafetyHandler();
|
||||
|
||||
/// Warn about lock expressions which fail to resolve to lockable objects.
|
||||
/// \param Loc -- the SourceLocation of the unresolved expression.
|
||||
|
|
@ -93,9 +93,14 @@ public:
|
|||
/// 3. or when a mutex is locked but not unlocked inside a function.
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param Loc -- The location of the lock expression where the mutex is locked
|
||||
/// \param LocLocked -- The location of the lock expression where the mutex is
|
||||
/// locked
|
||||
/// \param LocEndOfScope -- The location of the end of the scope where the
|
||||
/// mutex is no longer held
|
||||
/// \param LEK -- which of the three above cases we should warn for
|
||||
virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
|
||||
virtual void handleMutexHeldEndOfScope(Name LockName,
|
||||
SourceLocation LocLocked,
|
||||
SourceLocation LocEndOfScope,
|
||||
LockErrorKind LEK){}
|
||||
|
||||
/// Warn when a mutex is held exclusively and shared at the same point. For
|
||||
|
|
@ -143,7 +148,8 @@ public:
|
|||
/// We traverse the blocks in the CFG, compute the set of mutexes that are held
|
||||
/// at the end of each block, and issue warnings for thread safety violations.
|
||||
/// Each block in the CFG is traversed exactly once.
|
||||
void runThreadSafetyAnalysis(AnalysisContext &AC, ThreadSafetyHandler &Handler);
|
||||
void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
|
||||
ThreadSafetyHandler &Handler);
|
||||
|
||||
/// \brief Helper function that returns a LockKind required for the given level
|
||||
/// of access.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//= UninitializedValues.h - Finding uses of uninitialized values --*- C++ -*-==//
|
||||
//= UninitializedValues.h - Finding uses of uninitialized values -*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -17,12 +17,12 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
class AnalysisContext;
|
||||
class CFG;
|
||||
class AnalysisDeclContext;
|
||||
class CFG;
|
||||
class DeclContext;
|
||||
class Expr;
|
||||
class VarDecl;
|
||||
|
||||
|
||||
class UninitVariablesHandler {
|
||||
public:
|
||||
UninitVariablesHandler() {}
|
||||
|
|
@ -32,7 +32,7 @@ public:
|
|||
virtual void handleUseOfUninitVariable(const Expr *ex,
|
||||
const VarDecl *vd,
|
||||
bool isAlwaysUninit) {}
|
||||
|
||||
|
||||
/// Called when the uninitialized variable analysis detects the
|
||||
/// idiom 'int x = x'. All other uses of 'x' within the initializer
|
||||
/// are handled by handleUseOfUninitVariable.
|
||||
|
|
@ -45,7 +45,7 @@ struct UninitVariablesAnalysisStats {
|
|||
};
|
||||
|
||||
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
|
||||
AnalysisContext &ac,
|
||||
AnalysisDeclContext &ac,
|
||||
UninitVariablesHandler &handler,
|
||||
UninitVariablesAnalysisStats &stats);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines AnalysisContext, a class that manages the analysis context
|
||||
// data for path sensitive analysis.
|
||||
// This file defines AnalysisDeclContext, a class that manages the analysis
|
||||
// context data for path sensitive analysis.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
|
@ -38,17 +38,19 @@ class PseudoConstantAnalysis;
|
|||
class ImplicitParamDecl;
|
||||
class LocationContextManager;
|
||||
class StackFrameContext;
|
||||
|
||||
class AnalysisDeclContextManager;
|
||||
class LocationContext;
|
||||
|
||||
namespace idx { class TranslationUnit; }
|
||||
|
||||
/// The base class of a hierarchy of objects representing analyses tied
|
||||
/// to AnalysisContext.
|
||||
/// to AnalysisDeclContext.
|
||||
class ManagedAnalysis {
|
||||
protected:
|
||||
ManagedAnalysis() {}
|
||||
public:
|
||||
virtual ~ManagedAnalysis();
|
||||
|
||||
|
||||
// Subclasses need to implement:
|
||||
//
|
||||
// static const void *getTag();
|
||||
|
|
@ -56,47 +58,55 @@ public:
|
|||
// Which returns a fixed pointer address to distinguish classes of
|
||||
// analysis objects. They also need to implement:
|
||||
//
|
||||
// static [Derived*] create(AnalysisContext &Ctx);
|
||||
// static [Derived*] create(AnalysisDeclContext &Ctx);
|
||||
//
|
||||
// which creates the analysis object given an AnalysisContext.
|
||||
// which creates the analysis object given an AnalysisDeclContext.
|
||||
};
|
||||
|
||||
/// AnalysisContext contains the context data for the function or method under
|
||||
/// analysis.
|
||||
class AnalysisContext {
|
||||
|
||||
|
||||
/// AnalysisDeclContext contains the context data for the function or method
|
||||
/// under analysis.
|
||||
class AnalysisDeclContext {
|
||||
/// Backpoint to the AnalysisManager object that created this
|
||||
/// AnalysisDeclContext. This may be null.
|
||||
AnalysisDeclContextManager *Manager;
|
||||
|
||||
const Decl *D;
|
||||
|
||||
// TranslationUnit is NULL if we don't have multiple translation units.
|
||||
idx::TranslationUnit *TU;
|
||||
|
||||
llvm::OwningPtr<CFG> cfg, completeCFG;
|
||||
llvm::OwningPtr<CFGStmtMap> cfgStmtMap;
|
||||
OwningPtr<CFG> cfg, completeCFG;
|
||||
OwningPtr<CFGStmtMap> cfgStmtMap;
|
||||
|
||||
CFG::BuildOptions cfgBuildOptions;
|
||||
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
|
||||
|
||||
|
||||
bool builtCFG, builtCompleteCFG;
|
||||
|
||||
llvm::OwningPtr<LiveVariables> liveness;
|
||||
llvm::OwningPtr<LiveVariables> relaxedLiveness;
|
||||
llvm::OwningPtr<ParentMap> PM;
|
||||
llvm::OwningPtr<PseudoConstantAnalysis> PCA;
|
||||
llvm::OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
|
||||
OwningPtr<LiveVariables> liveness;
|
||||
OwningPtr<LiveVariables> relaxedLiveness;
|
||||
OwningPtr<ParentMap> PM;
|
||||
OwningPtr<PseudoConstantAnalysis> PCA;
|
||||
OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
|
||||
|
||||
llvm::BumpPtrAllocator A;
|
||||
|
||||
// FIXME: remove.
|
||||
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
|
||||
|
||||
void *ManagedAnalyses;
|
||||
|
||||
public:
|
||||
AnalysisContext(const Decl *d, idx::TranslationUnit *tu);
|
||||
AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
|
||||
const Decl *D,
|
||||
idx::TranslationUnit *TU);
|
||||
|
||||
AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
|
||||
const CFG::BuildOptions &buildOptions);
|
||||
AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
|
||||
const Decl *D,
|
||||
idx::TranslationUnit *TU,
|
||||
const CFG::BuildOptions &BuildOptions);
|
||||
|
||||
~AnalysisContext();
|
||||
~AnalysisDeclContext();
|
||||
|
||||
ASTContext &getASTContext() { return D->getASTContext(); }
|
||||
const Decl *getDecl() const { return D; }
|
||||
|
|
@ -111,12 +121,12 @@ public:
|
|||
const CFG::BuildOptions &getCFGBuildOptions() const {
|
||||
return cfgBuildOptions;
|
||||
}
|
||||
|
||||
|
||||
/// getAddEHEdges - Return true iff we are adding exceptional edges from
|
||||
/// callExprs. If this is false, then try/catch statements and blocks
|
||||
/// reachable from them can appear to be dead in the CFG, analysis passes must
|
||||
/// cope with that.
|
||||
bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
|
||||
bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
|
||||
bool getUseUnoptimizedCFG() const {
|
||||
return !cfgBuildOptions.PruneTriviallyFalseEdges;
|
||||
}
|
||||
|
|
@ -125,18 +135,18 @@ public:
|
|||
|
||||
void registerForcedBlockExpression(const Stmt *stmt);
|
||||
const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
|
||||
|
||||
|
||||
Stmt *getBody() const;
|
||||
CFG *getCFG();
|
||||
|
||||
|
||||
CFGStmtMap *getCFGStmtMap();
|
||||
|
||||
CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis();
|
||||
|
||||
|
||||
/// Return a version of the CFG without any edges pruned.
|
||||
CFG *getUnoptimizedCFG();
|
||||
|
||||
void dumpCFG();
|
||||
void dumpCFG(bool ShowColors);
|
||||
|
||||
/// \brief Returns true if we have built a CFG for this analysis context.
|
||||
/// Note that this doesn't correspond to whether or not a valid CFG exists, it
|
||||
|
|
@ -152,9 +162,14 @@ public:
|
|||
getReferencedBlockVars(const BlockDecl *BD);
|
||||
|
||||
/// Return the ImplicitParamDecl* associated with 'self' if this
|
||||
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
|
||||
/// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise.
|
||||
const ImplicitParamDecl *getSelfDecl() const;
|
||||
|
||||
|
||||
const StackFrameContext *getStackFrame(LocationContext const *Parent,
|
||||
const Stmt *S,
|
||||
const CFGBlock *Blk,
|
||||
unsigned Idx);
|
||||
|
||||
/// Return the specified analysis object, lazily running the analysis if
|
||||
/// necessary. Return NULL if the analysis could not run.
|
||||
template <typename T>
|
||||
|
|
@ -168,31 +183,8 @@ public:
|
|||
}
|
||||
private:
|
||||
ManagedAnalysis *&getAnalysisImpl(const void* tag);
|
||||
};
|
||||
|
||||
class AnalysisContextManager {
|
||||
typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
|
||||
ContextMap Contexts;
|
||||
CFG::BuildOptions cfgBuildOptions;
|
||||
public:
|
||||
AnalysisContextManager(bool useUnoptimizedCFG = false,
|
||||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false);
|
||||
|
||||
~AnalysisContextManager();
|
||||
|
||||
AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
|
||||
|
||||
bool getUseUnoptimizedCFG() const {
|
||||
return !cfgBuildOptions.PruneTriviallyFalseEdges;
|
||||
}
|
||||
|
||||
CFG::BuildOptions &getCFGBuildOptions() {
|
||||
return cfgBuildOptions;
|
||||
}
|
||||
|
||||
/// Discard all previously created AnalysisContexts.
|
||||
void clear();
|
||||
LocationContextManager &getLocationContextManager();
|
||||
};
|
||||
|
||||
class LocationContext : public llvm::FoldingSetNode {
|
||||
|
|
@ -202,13 +194,14 @@ public:
|
|||
private:
|
||||
ContextKind Kind;
|
||||
|
||||
// AnalysisContext can't be const since some methods may modify its member.
|
||||
AnalysisContext *Ctx;
|
||||
// AnalysisDeclContext can't be const since some methods may modify its
|
||||
// member.
|
||||
AnalysisDeclContext *Ctx;
|
||||
|
||||
const LocationContext *Parent;
|
||||
|
||||
protected:
|
||||
LocationContext(ContextKind k, AnalysisContext *ctx,
|
||||
LocationContext(ContextKind k, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent)
|
||||
: Kind(k), Ctx(ctx), Parent(parent) {}
|
||||
|
||||
|
|
@ -217,27 +210,27 @@ public:
|
|||
|
||||
ContextKind getKind() const { return Kind; }
|
||||
|
||||
AnalysisContext *getAnalysisContext() const { return Ctx; }
|
||||
AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
|
||||
|
||||
idx::TranslationUnit *getTranslationUnit() const {
|
||||
return Ctx->getTranslationUnit();
|
||||
idx::TranslationUnit *getTranslationUnit() const {
|
||||
return Ctx->getTranslationUnit();
|
||||
}
|
||||
|
||||
const LocationContext *getParent() const { return Parent; }
|
||||
|
||||
bool isParentOf(const LocationContext *LC) const;
|
||||
|
||||
const Decl *getDecl() const { return getAnalysisContext()->getDecl(); }
|
||||
const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); }
|
||||
|
||||
CFG *getCFG() const { return getAnalysisContext()->getCFG(); }
|
||||
CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); }
|
||||
|
||||
template <typename T>
|
||||
T *getAnalysis() const {
|
||||
return getAnalysisContext()->getAnalysis<T>();
|
||||
return getAnalysisDeclContext()->getAnalysis<T>();
|
||||
}
|
||||
|
||||
ParentMap &getParentMap() const {
|
||||
return getAnalysisContext()->getParentMap();
|
||||
return getAnalysisDeclContext()->getParentMap();
|
||||
}
|
||||
|
||||
const ImplicitParamDecl *getSelfDecl() const {
|
||||
|
|
@ -255,7 +248,7 @@ public:
|
|||
public:
|
||||
static void ProfileCommon(llvm::FoldingSetNodeID &ID,
|
||||
ContextKind ck,
|
||||
AnalysisContext *ctx,
|
||||
AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const void *data);
|
||||
};
|
||||
|
|
@ -271,8 +264,8 @@ class StackFrameContext : public LocationContext {
|
|||
unsigned Index;
|
||||
|
||||
friend class LocationContextManager;
|
||||
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s, const CFGBlock *blk,
|
||||
StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s, const CFGBlock *blk,
|
||||
unsigned idx)
|
||||
: LocationContext(StackFrame, ctx, parent), CallSite(s),
|
||||
Block(blk), Index(idx) {}
|
||||
|
|
@ -288,7 +281,7 @@ public:
|
|||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const Stmt *s,
|
||||
const CFGBlock *blk, unsigned idx) {
|
||||
ProfileCommon(ID, StackFrame, ctx, parent, s);
|
||||
|
|
@ -305,7 +298,7 @@ class ScopeContext : public LocationContext {
|
|||
const Stmt *Enter;
|
||||
|
||||
friend class LocationContextManager;
|
||||
ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s)
|
||||
: LocationContext(Scope, ctx, parent), Enter(s) {}
|
||||
|
||||
|
|
@ -314,7 +307,7 @@ public:
|
|||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const Stmt *s) {
|
||||
ProfileCommon(ID, Scope, ctx, parent, s);
|
||||
}
|
||||
|
|
@ -331,7 +324,8 @@ class BlockInvocationContext : public LocationContext {
|
|||
|
||||
friend class LocationContextManager;
|
||||
|
||||
BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
BlockInvocationContext(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const BlockDecl *bd)
|
||||
: LocationContext(Block, ctx, parent), BD(bd) {}
|
||||
|
||||
|
|
@ -342,7 +336,7 @@ public:
|
|||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const BlockDecl *bd) {
|
||||
ProfileCommon(ID, Block, ctx, parent, bd);
|
||||
}
|
||||
|
|
@ -357,12 +351,12 @@ class LocationContextManager {
|
|||
public:
|
||||
~LocationContextManager();
|
||||
|
||||
const StackFrameContext *getStackFrame(AnalysisContext *ctx,
|
||||
const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s,
|
||||
const CFGBlock *blk, unsigned idx);
|
||||
|
||||
const ScopeContext *getScope(AnalysisContext *ctx,
|
||||
const ScopeContext *getScope(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s);
|
||||
|
||||
|
|
@ -370,10 +364,69 @@ public:
|
|||
void clear();
|
||||
private:
|
||||
template <typename LOC, typename DATA>
|
||||
const LOC *getLocationContext(AnalysisContext *ctx,
|
||||
const LOC *getLocationContext(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const DATA *d);
|
||||
};
|
||||
|
||||
class AnalysisDeclContextManager {
|
||||
typedef llvm::DenseMap<const Decl*, AnalysisDeclContext*> ContextMap;
|
||||
|
||||
ContextMap Contexts;
|
||||
LocationContextManager LocContexts;
|
||||
CFG::BuildOptions cfgBuildOptions;
|
||||
|
||||
public:
|
||||
AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
|
||||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false);
|
||||
|
||||
~AnalysisDeclContextManager();
|
||||
|
||||
AnalysisDeclContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
|
||||
|
||||
bool getUseUnoptimizedCFG() const {
|
||||
return !cfgBuildOptions.PruneTriviallyFalseEdges;
|
||||
}
|
||||
|
||||
CFG::BuildOptions &getCFGBuildOptions() {
|
||||
return cfgBuildOptions;
|
||||
}
|
||||
|
||||
const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
|
||||
LocationContext const *Parent,
|
||||
const Stmt *S,
|
||||
const CFGBlock *Blk,
|
||||
unsigned Idx) {
|
||||
return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx);
|
||||
}
|
||||
|
||||
// Get the top level stack frame.
|
||||
const StackFrameContext *getStackFrame(Decl const *D,
|
||||
idx::TranslationUnit *TU) {
|
||||
return LocContexts.getStackFrame(getContext(D, TU), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Get a stack frame with parent.
|
||||
StackFrameContext const *getStackFrame(const Decl *D,
|
||||
LocationContext const *Parent,
|
||||
const Stmt *S,
|
||||
const CFGBlock *Blk,
|
||||
unsigned Idx) {
|
||||
return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
|
||||
}
|
||||
|
||||
|
||||
/// Discard all previously created AnalysisDeclContexts.
|
||||
void clear();
|
||||
|
||||
private:
|
||||
friend class AnalysisDeclContext;
|
||||
|
||||
LocationContextManager &getLocationContextManager() {
|
||||
return LocContexts;
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace clang {
|
|||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
#define ANALYSISSTART
|
||||
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
|
||||
#undef DIAG
|
||||
|
|
|
|||
|
|
@ -67,22 +67,22 @@ protected:
|
|||
|
||||
CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = 0)
|
||||
: Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
|
||||
Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {}
|
||||
Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {}
|
||||
|
||||
public:
|
||||
CFGElement() {}
|
||||
|
||||
Kind getKind() const {
|
||||
Kind getKind() const {
|
||||
unsigned x = Data2.getInt();
|
||||
x <<= 2;
|
||||
x |= Data1.getInt();
|
||||
return (Kind) x;
|
||||
}
|
||||
|
||||
|
||||
bool isValid() const { return getKind() != Invalid; }
|
||||
|
||||
operator bool() const { return isValid(); }
|
||||
|
||||
|
||||
template<class ElemTy> const ElemTy *getAs() const {
|
||||
if (llvm::isa<ElemTy>(this))
|
||||
return static_cast<const ElemTy*>(this);
|
||||
|
|
@ -96,7 +96,7 @@ class CFGStmt : public CFGElement {
|
|||
public:
|
||||
CFGStmt(Stmt *S) : CFGElement(Statement, S) {}
|
||||
|
||||
const Stmt *getStmt() const {
|
||||
const Stmt *getStmt() const {
|
||||
return static_cast<const Stmt *>(Data1.getPointer());
|
||||
}
|
||||
|
||||
|
|
@ -125,9 +125,9 @@ public:
|
|||
/// by compiler on various occasions.
|
||||
class CFGImplicitDtor : public CFGElement {
|
||||
protected:
|
||||
CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0)
|
||||
CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0)
|
||||
: CFGElement(kind, data1, data2) {
|
||||
assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
|
||||
assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -272,12 +272,12 @@ class CFGBlock {
|
|||
ImplTy Impl;
|
||||
public:
|
||||
ElementList(BumpVectorContext &C) : Impl(C, 4) {}
|
||||
|
||||
|
||||
typedef std::reverse_iterator<ImplTy::iterator> iterator;
|
||||
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
|
||||
typedef ImplTy::iterator reverse_iterator;
|
||||
typedef ImplTy::const_iterator const_reverse_iterator;
|
||||
|
||||
typedef ImplTy::const_iterator const_reverse_iterator;
|
||||
|
||||
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
|
||||
reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
|
||||
BumpVectorContext &C) {
|
||||
|
|
@ -286,7 +286,7 @@ class CFGBlock {
|
|||
|
||||
CFGElement front() const { return Impl.back(); }
|
||||
CFGElement back() const { return Impl.front(); }
|
||||
|
||||
|
||||
iterator begin() { return Impl.rbegin(); }
|
||||
iterator end() { return Impl.rend(); }
|
||||
const_iterator begin() const { return Impl.rbegin(); }
|
||||
|
|
@ -300,7 +300,7 @@ class CFGBlock {
|
|||
assert(i < Impl.size());
|
||||
return Impl[Impl.size() - 1 - i];
|
||||
}
|
||||
|
||||
|
||||
size_t size() const { return Impl.size(); }
|
||||
bool empty() const { return Impl.empty(); }
|
||||
};
|
||||
|
|
@ -344,10 +344,14 @@ class CFGBlock {
|
|||
/// storage if the memory usage of CFGBlock becomes an issue.
|
||||
unsigned HasNoReturnElement : 1;
|
||||
|
||||
/// Parent - The parent CFG that owns this CFGBlock.
|
||||
CFG *Parent;
|
||||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
|
||||
: Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false) {}
|
||||
explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent)
|
||||
: Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false),
|
||||
Parent(parent) {}
|
||||
~CFGBlock() {}
|
||||
|
||||
// Statement iterators
|
||||
|
|
@ -489,16 +493,19 @@ public:
|
|||
|
||||
unsigned getBlockID() const { return BlockID; }
|
||||
|
||||
void dump(const CFG *cfg, const LangOptions &LO) const;
|
||||
void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
|
||||
CFG *getParent() const { return Parent; }
|
||||
|
||||
void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const;
|
||||
void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO,
|
||||
bool ShowColors) const;
|
||||
void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
|
||||
|
||||
|
||||
void addSuccessor(CFGBlock *Block, BumpVectorContext &C) {
|
||||
if (Block)
|
||||
Block->Preds.push_back(this, C);
|
||||
Succs.push_back(Block, C);
|
||||
}
|
||||
|
||||
|
||||
void appendStmt(Stmt *statement, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGStmt(statement), C);
|
||||
}
|
||||
|
|
@ -515,7 +522,7 @@ public:
|
|||
void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGMemberDtor(FD), C);
|
||||
}
|
||||
|
||||
|
||||
void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGTemporaryDtor(E), C);
|
||||
}
|
||||
|
|
@ -554,22 +561,22 @@ public:
|
|||
llvm::BitVector alwaysAddMask;
|
||||
public:
|
||||
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
|
||||
ForcedBlkExprs **forcedBlkExprs;
|
||||
ForcedBlkExprs **forcedBlkExprs;
|
||||
|
||||
bool PruneTriviallyFalseEdges;
|
||||
bool AddEHEdges;
|
||||
bool AddInitializers;
|
||||
bool AddImplicitDtors;
|
||||
|
||||
|
||||
bool alwaysAdd(const Stmt *stmt) const {
|
||||
return alwaysAddMask[stmt->getStmtClass()];
|
||||
}
|
||||
|
||||
|
||||
BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) {
|
||||
alwaysAddMask[stmtClass] = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BuildOptions &setAllAlwaysAdd() {
|
||||
alwaysAddMask.set();
|
||||
return *this;
|
||||
|
|
@ -583,6 +590,55 @@ public:
|
|||
,AddImplicitDtors(false) {}
|
||||
};
|
||||
|
||||
/// \brief Provides a custom implementation of the iterator class to have the
|
||||
/// same interface as Function::iterator - iterator returns CFGBlock
|
||||
/// (not a pointer to CFGBlock).
|
||||
class graph_iterator {
|
||||
public:
|
||||
typedef const CFGBlock value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef BumpVector<CFGBlock*>::iterator ImplTy;
|
||||
|
||||
graph_iterator(const ImplTy &i) : I(i) {}
|
||||
|
||||
bool operator==(const graph_iterator &X) const { return I == X.I; }
|
||||
bool operator!=(const graph_iterator &X) const { return I != X.I; }
|
||||
|
||||
reference operator*() const { return **I; }
|
||||
pointer operator->() const { return *I; }
|
||||
operator CFGBlock* () { return *I; }
|
||||
|
||||
graph_iterator &operator++() { ++I; return *this; }
|
||||
graph_iterator &operator--() { --I; return *this; }
|
||||
|
||||
private:
|
||||
ImplTy I;
|
||||
};
|
||||
|
||||
class const_graph_iterator {
|
||||
public:
|
||||
typedef const CFGBlock value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef BumpVector<CFGBlock*>::const_iterator ImplTy;
|
||||
|
||||
const_graph_iterator(const ImplTy &i) : I(i) {}
|
||||
|
||||
bool operator==(const const_graph_iterator &X) const { return I == X.I; }
|
||||
bool operator!=(const const_graph_iterator &X) const { return I != X.I; }
|
||||
|
||||
reference operator*() const { return **I; }
|
||||
pointer operator->() const { return *I; }
|
||||
operator CFGBlock* () const { return *I; }
|
||||
|
||||
const_graph_iterator &operator++() { ++I; return *this; }
|
||||
const_graph_iterator &operator--() { --I; return *this; }
|
||||
|
||||
private:
|
||||
ImplTy I;
|
||||
};
|
||||
|
||||
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
|
||||
/// constructed CFG belongs to the caller.
|
||||
static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
|
||||
|
|
@ -605,7 +661,7 @@ public:
|
|||
// Block Iterators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
typedef BumpVector<CFGBlock*> CFGBlockListTy;
|
||||
typedef BumpVector<CFGBlock*> CFGBlockListTy;
|
||||
typedef CFGBlockListTy::iterator iterator;
|
||||
typedef CFGBlockListTy::const_iterator const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
|
@ -619,6 +675,15 @@ public:
|
|||
const_iterator begin() const { return Blocks.begin(); }
|
||||
const_iterator end() const { return Blocks.end(); }
|
||||
|
||||
graph_iterator nodes_begin() { return graph_iterator(Blocks.begin()); }
|
||||
graph_iterator nodes_end() { return graph_iterator(Blocks.end()); }
|
||||
const_graph_iterator nodes_begin() const {
|
||||
return const_graph_iterator(Blocks.begin());
|
||||
}
|
||||
const_graph_iterator nodes_end() const {
|
||||
return const_graph_iterator(Blocks.end());
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() { return Blocks.rbegin(); }
|
||||
reverse_iterator rend() { return Blocks.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
|
||||
|
|
@ -631,7 +696,7 @@ public:
|
|||
|
||||
CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; }
|
||||
const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; }
|
||||
|
||||
|
||||
typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator;
|
||||
try_block_iterator try_blocks_begin() const {
|
||||
return TryDispatchBlocks.begin();
|
||||
|
|
@ -639,7 +704,7 @@ public:
|
|||
try_block_iterator try_blocks_end() const {
|
||||
return TryDispatchBlocks.end();
|
||||
}
|
||||
|
||||
|
||||
void addTryDispatchBlock(const CFGBlock *block) {
|
||||
TryDispatchBlocks.push_back(block);
|
||||
}
|
||||
|
|
@ -681,13 +746,18 @@ public:
|
|||
/// start at 0).
|
||||
unsigned getNumBlockIDs() const { return NumBlockIDs; }
|
||||
|
||||
/// size - Return the total number of CFGBlocks within the CFG
|
||||
/// This is simply a renaming of the getNumBlockIDs(). This is necessary
|
||||
/// because the dominator implementation needs such an interface.
|
||||
unsigned size() const { return NumBlockIDs; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Debugging: Pretty-Printing and Visualization.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void viewCFG(const LangOptions &LO) const;
|
||||
void print(raw_ostream &OS, const LangOptions &LO) const;
|
||||
void dump(const LangOptions &LO) const;
|
||||
void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const;
|
||||
void dump(const LangOptions &LO, bool ShowColors) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal: constructors and data.
|
||||
|
|
@ -701,7 +771,7 @@ public:
|
|||
llvm::BumpPtrAllocator& getAllocator() {
|
||||
return BlkBVC.getAllocator();
|
||||
}
|
||||
|
||||
|
||||
BumpVectorContext &getBumpVectorContext() {
|
||||
return BlkBVC;
|
||||
}
|
||||
|
|
@ -717,11 +787,11 @@ private:
|
|||
// It represents a map from Expr* to integers to record the set of
|
||||
// block-level expressions and their "statement number" in the CFG.
|
||||
void * BlkExprMap;
|
||||
|
||||
|
||||
BumpVectorContext BlkBVC;
|
||||
|
||||
|
||||
CFGBlockListTy Blocks;
|
||||
|
||||
|
||||
/// C++ 'try' statements are modeled with an indirect dispatch block.
|
||||
/// This is the collection of such blocks present in the CFG.
|
||||
std::vector<const CFGBlock *> TryDispatchBlocks;
|
||||
|
|
@ -781,6 +851,20 @@ template <> struct GraphTraits< const ::clang::CFGBlock *> {
|
|||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse< ::clang::CFGBlock*> > {
|
||||
typedef ::clang::CFGBlock NodeType;
|
||||
typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(Inverse< ::clang::CFGBlock*> G)
|
||||
{ return G.Graph; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->pred_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->pred_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
|
||||
typedef const ::clang::CFGBlock NodeType;
|
||||
typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
|
||||
|
|
@ -800,37 +884,55 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
|
|||
template <> struct GraphTraits< ::clang::CFG* >
|
||||
: public GraphTraits< ::clang::CFGBlock *> {
|
||||
|
||||
typedef ::clang::CFG::iterator nodes_iterator;
|
||||
typedef ::clang::CFG::graph_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin(::clang::CFG* F) { return F->begin(); }
|
||||
static nodes_iterator nodes_end(::clang::CFG* F) { return F->end(); }
|
||||
static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();}
|
||||
static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); }
|
||||
static unsigned size(::clang::CFG* F) { return F->size(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const ::clang::CFG* >
|
||||
: public GraphTraits<const ::clang::CFGBlock *> {
|
||||
|
||||
typedef ::clang::CFG::const_iterator nodes_iterator;
|
||||
typedef ::clang::CFG::const_graph_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode( const ::clang::CFG* F) {
|
||||
return &F->getEntry();
|
||||
}
|
||||
static nodes_iterator nodes_begin( const ::clang::CFG* F) {
|
||||
return F->begin();
|
||||
return F->nodes_begin();
|
||||
}
|
||||
static nodes_iterator nodes_end( const ::clang::CFG* F) {
|
||||
return F->end();
|
||||
return F->nodes_end();
|
||||
}
|
||||
static unsigned size(const ::clang::CFG* F) {
|
||||
return F->size();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse< ::clang::CFG*> >
|
||||
: public GraphTraits<Inverse< ::clang::CFGBlock*> > {
|
||||
|
||||
typedef ::clang::CFG::graph_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode( ::clang::CFG* F) { return &F->getExit(); }
|
||||
static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();}
|
||||
static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const ::clang::CFG*> >
|
||||
: public GraphTraits<Inverse<const ::clang::CFGBlock*> > {
|
||||
|
||||
typedef ::clang::CFG::const_iterator nodes_iterator;
|
||||
typedef ::clang::CFG::const_graph_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); }
|
||||
static nodes_iterator nodes_begin(const ::clang::CFG* F) { return F->begin();}
|
||||
static nodes_iterator nodes_end(const ::clang::CFG* F) { return F->end(); }
|
||||
static nodes_iterator nodes_begin(const ::clang::CFG* F) {
|
||||
return F->nodes_begin();
|
||||
}
|
||||
static nodes_iterator nodes_end(const ::clang::CFG* F) {
|
||||
return F->nodes_end();
|
||||
}
|
||||
};
|
||||
} // end llvm namespace
|
||||
#endif
|
||||
|
|
|
|||
257
include/clang/Analysis/CallGraph.h
Normal file
257
include/clang/Analysis/CallGraph.h
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
//== CallGraph.h - AST-based Call graph ------------------------*- 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 AST-based CallGraph.
|
||||
//
|
||||
// A call graph for functions whose definitions/bodies are available in the
|
||||
// current translation unit. The graph has a "virtual" root node that contains
|
||||
// edges to all externally available functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH
|
||||
#define LLVM_CLANG_ANALYSIS_CALLGRAPH
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
|
||||
namespace clang {
|
||||
class CallGraphNode;
|
||||
|
||||
/// \class The AST-based call graph.
|
||||
///
|
||||
/// The call graph extends itself with the given declarations by implementing
|
||||
/// the recursive AST visitor, which constructs the graph by visiting the given
|
||||
/// declarations.
|
||||
class CallGraph : public RecursiveASTVisitor<CallGraph> {
|
||||
friend class CallGraphNode;
|
||||
|
||||
typedef llvm::DenseMap<const Decl *, CallGraphNode *> FunctionMapTy;
|
||||
|
||||
/// FunctionMap owns all CallGraphNodes.
|
||||
FunctionMapTy FunctionMap;
|
||||
|
||||
/// This is a virtual root node that has edges to all the global functions -
|
||||
/// 'main' or functions accessible from other translation units.
|
||||
CallGraphNode *Root;
|
||||
|
||||
/// The list of nodes that have no parent. These are unreachable from Root.
|
||||
/// Declarations can get to this list due to impressions in the graph, for
|
||||
/// example, we do not track functions whose addresses were taken.
|
||||
llvm::SetVector<CallGraphNode *> ParentlessNodes;
|
||||
|
||||
public:
|
||||
CallGraph();
|
||||
~CallGraph();
|
||||
|
||||
/// \brief Populate the call graph with the functions in the given
|
||||
/// declaration.
|
||||
///
|
||||
/// Recursively walks the declaration to find all the dependent Decls as well.
|
||||
void addToCallGraph(Decl *D) {
|
||||
TraverseDecl(D);
|
||||
}
|
||||
|
||||
/// \brief Determine if a declaration should be included in the graph.
|
||||
static bool includeInGraph(const Decl *D);
|
||||
|
||||
/// \brief Lookup the node for the given declaration.
|
||||
CallGraphNode *getNode(const Decl *) const;
|
||||
|
||||
/// \brief Lookup the node for the given declaration. If none found, insert
|
||||
/// one into the graph.
|
||||
CallGraphNode *getOrInsertNode(Decl *);
|
||||
|
||||
/// Iterators through all the elements in the graph. Note, this gives
|
||||
/// non-deterministic order.
|
||||
typedef FunctionMapTy::iterator iterator;
|
||||
typedef FunctionMapTy::const_iterator const_iterator;
|
||||
iterator begin() { return FunctionMap.begin(); }
|
||||
iterator end() { return FunctionMap.end(); }
|
||||
const_iterator begin() const { return FunctionMap.begin(); }
|
||||
const_iterator end() const { return FunctionMap.end(); }
|
||||
|
||||
/// \brief Get the number of nodes in the graph.
|
||||
unsigned size() const { return FunctionMap.size(); }
|
||||
|
||||
/// \ brief Get the virtual root of the graph, all the functions available
|
||||
/// externally are represented as callees of the node.
|
||||
CallGraphNode *getRoot() const { return Root; }
|
||||
|
||||
/// Iterators through all the nodes of the graph that have no parent. These
|
||||
/// are the unreachable nodes, which are either unused or are due to us
|
||||
/// failing to add a call edge due to the analysis imprecision.
|
||||
typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator;
|
||||
typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator;
|
||||
nodes_iterator parentless_begin() { return ParentlessNodes.begin(); }
|
||||
nodes_iterator parentless_end() { return ParentlessNodes.end(); }
|
||||
const_nodes_iterator
|
||||
parentless_begin() const { return ParentlessNodes.begin(); }
|
||||
const_nodes_iterator
|
||||
parentless_end() const { return ParentlessNodes.end(); }
|
||||
|
||||
void print(raw_ostream &os) const;
|
||||
void dump() const;
|
||||
void viewGraph() const;
|
||||
|
||||
/// Part of recursive declaration visitation.
|
||||
bool VisitFunctionDecl(FunctionDecl *FD) {
|
||||
// We skip function template definitions, as their semantics is
|
||||
// only determined when they are instantiated.
|
||||
if (includeInGraph(FD))
|
||||
// If this function has external linkage, anything could call it.
|
||||
// Note, we are not precise here. For example, the function could have
|
||||
// its address taken.
|
||||
addNodeForDecl(FD, FD->isGlobal());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Part of recursive declaration visitation.
|
||||
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
|
||||
if (includeInGraph(MD))
|
||||
addNodeForDecl(MD, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Add the given declaration to the call graph.
|
||||
void addNodeForDecl(Decl *D, bool IsGlobal);
|
||||
|
||||
/// \brief Allocate a new node in the graph.
|
||||
CallGraphNode *allocateNewNode(Decl *);
|
||||
};
|
||||
|
||||
class CallGraphNode {
|
||||
public:
|
||||
typedef CallGraphNode* CallRecord;
|
||||
|
||||
private:
|
||||
/// \brief The function/method declaration.
|
||||
Decl *FD;
|
||||
|
||||
/// \brief The list of functions called from this node.
|
||||
// Small vector might be more efficient since we are only tracking functions
|
||||
// whose definition is in the current TU.
|
||||
llvm::SmallVector<CallRecord, 5> CalledFunctions;
|
||||
|
||||
public:
|
||||
CallGraphNode(Decl *D) : FD(D) {}
|
||||
|
||||
typedef llvm::SmallVector<CallRecord, 5>::iterator iterator;
|
||||
typedef llvm::SmallVector<CallRecord, 5>::const_iterator const_iterator;
|
||||
|
||||
/// Iterators through all the callees/children of the node.
|
||||
inline iterator begin() { return CalledFunctions.begin(); }
|
||||
inline iterator end() { return CalledFunctions.end(); }
|
||||
inline const_iterator begin() const { return CalledFunctions.begin(); }
|
||||
inline const_iterator end() const { return CalledFunctions.end(); }
|
||||
|
||||
inline bool empty() const {return CalledFunctions.empty(); }
|
||||
inline unsigned size() const {return CalledFunctions.size(); }
|
||||
|
||||
void addCallee(CallGraphNode *N, CallGraph *CG) {
|
||||
CalledFunctions.push_back(N);
|
||||
CG->ParentlessNodes.remove(N);
|
||||
}
|
||||
|
||||
Decl *getDecl() const { return FD; }
|
||||
|
||||
StringRef getName() const;
|
||||
|
||||
void print(raw_ostream &os) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
// Graph traits for iteration, viewing.
|
||||
namespace llvm {
|
||||
template <> struct GraphTraits<clang::CallGraphNode*> {
|
||||
typedef clang::CallGraphNode NodeType;
|
||||
typedef clang::CallGraphNode::CallRecord CallRecordTy;
|
||||
typedef std::pointer_to_unary_function<CallRecordTy,
|
||||
clang::CallGraphNode*> CGNDerefFun;
|
||||
static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; }
|
||||
typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType;
|
||||
static inline ChildIteratorType child_begin(NodeType *N) {
|
||||
return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
static inline ChildIteratorType child_end (NodeType *N) {
|
||||
return map_iterator(N->end(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
static clang::CallGraphNode *CGNDeref(CallRecordTy P) {
|
||||
return P;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const clang::CallGraphNode*> {
|
||||
typedef const clang::CallGraphNode NodeType;
|
||||
typedef NodeType::const_iterator ChildIteratorType;
|
||||
static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; }
|
||||
static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();}
|
||||
static inline ChildIteratorType child_end (NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<clang::CallGraph*>
|
||||
: public GraphTraits<clang::CallGraphNode*> {
|
||||
|
||||
static NodeType *getEntryNode(clang::CallGraph *CGN) {
|
||||
return CGN->getRoot(); // Start at the external node!
|
||||
}
|
||||
typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy;
|
||||
typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun;
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef mapped_iterator<clang::CallGraph::iterator, DerefFun> nodes_iterator;
|
||||
|
||||
static nodes_iterator nodes_begin(clang::CallGraph *CG) {
|
||||
return map_iterator(CG->begin(), DerefFun(CGdereference));
|
||||
}
|
||||
static nodes_iterator nodes_end (clang::CallGraph *CG) {
|
||||
return map_iterator(CG->end(), DerefFun(CGdereference));
|
||||
}
|
||||
static clang::CallGraphNode &CGdereference(PairTy P) {
|
||||
return *(P.second);
|
||||
}
|
||||
|
||||
static unsigned size(clang::CallGraph *CG) {
|
||||
return CG->size();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const clang::CallGraph*> :
|
||||
public GraphTraits<const clang::CallGraphNode*> {
|
||||
static NodeType *getEntryNode(const clang::CallGraph *CGN) {
|
||||
return CGN->getRoot();
|
||||
}
|
||||
typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy;
|
||||
typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun;
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef mapped_iterator<clang::CallGraph::const_iterator,
|
||||
DerefFun> nodes_iterator;
|
||||
|
||||
static nodes_iterator nodes_begin(const clang::CallGraph *CG) {
|
||||
return map_iterator(CG->begin(), DerefFun(CGdereference));
|
||||
}
|
||||
static nodes_iterator nodes_end(const clang::CallGraph *CG) {
|
||||
return map_iterator(CG->end(), DerefFun(CGdereference));
|
||||
}
|
||||
static clang::CallGraphNode &CGdereference(PairTy P) {
|
||||
return *(P.second);
|
||||
}
|
||||
|
||||
static unsigned size(const clang::CallGraph *CG) {
|
||||
return CG->size();
|
||||
}
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
|
|
@ -14,25 +14,15 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA
|
||||
#define LLVM_CLANG_ANALYSIS_DS_COCOA
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
class FunctionDecl;
|
||||
class ObjCMethodDecl;
|
||||
class QualType;
|
||||
|
||||
namespace ento {
|
||||
namespace cocoa {
|
||||
|
||||
enum NamingConvention { NoConvention, CreateRule, InitRule };
|
||||
|
||||
NamingConvention deriveNamingConvention(Selector S, const ObjCMethodDecl *MD);
|
||||
|
||||
static inline bool followsFundamentalRule(Selector S,
|
||||
const ObjCMethodDecl *MD) {
|
||||
return deriveNamingConvention(S, MD) == CreateRule;
|
||||
}
|
||||
|
||||
bool isRefType(QualType RetTy, StringRef Prefix,
|
||||
StringRef Name = StringRef());
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
|
@ -28,7 +29,7 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
class AnalysisContext;
|
||||
class AnalysisDeclContext;
|
||||
class FunctionDecl;
|
||||
class LocationContext;
|
||||
class ProgramPointTag;
|
||||
|
|
@ -51,44 +52,72 @@ public:
|
|||
CallEnterKind,
|
||||
CallExitKind,
|
||||
MinPostStmtKind = PostStmtKind,
|
||||
MaxPostStmtKind = CallExitKind };
|
||||
MaxPostStmtKind = CallExitKind,
|
||||
EpsilonKind};
|
||||
|
||||
private:
|
||||
std::pair<const void *, const void *> Data;
|
||||
Kind K;
|
||||
llvm::PointerIntPair<const void *, 2, unsigned> Data1;
|
||||
llvm::PointerIntPair<const void *, 2, unsigned> Data2;
|
||||
|
||||
// The LocationContext could be NULL to allow ProgramPoint to be used in
|
||||
// context insensitive analysis.
|
||||
const LocationContext *L;
|
||||
llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
|
||||
|
||||
const ProgramPointTag *Tag;
|
||||
|
||||
ProgramPoint();
|
||||
|
||||
protected:
|
||||
ProgramPoint(const void *P, Kind k, const LocationContext *l,
|
||||
ProgramPoint(const void *P,
|
||||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {}
|
||||
|
||||
ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l,
|
||||
: Data1(P, ((unsigned) k) & 0x3),
|
||||
Data2(0, (((unsigned) k) >> 2) & 0x3),
|
||||
L(l, (((unsigned) k) >> 4) & 0x3),
|
||||
Tag(tag) {
|
||||
assert(getKind() == k);
|
||||
assert(getLocationContext() == l);
|
||||
assert(getData1() == P);
|
||||
}
|
||||
|
||||
ProgramPoint(const void *P1,
|
||||
const void *P2,
|
||||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: Data(P1, P2), K(k), L(l), Tag(tag) {}
|
||||
: Data1(P1, ((unsigned) k) & 0x3),
|
||||
Data2(P2, (((unsigned) k) >> 2) & 0x3),
|
||||
L(l, (((unsigned) k) >> 4) & 0x3),
|
||||
Tag(tag) {}
|
||||
|
||||
protected:
|
||||
const void *getData1() const { return Data.first; }
|
||||
const void *getData2() const { return Data.second; }
|
||||
const void *getData1() const { return Data1.getPointer(); }
|
||||
const void *getData2() const { return Data2.getPointer(); }
|
||||
void setData2(const void *d) { Data2.setPointer(d); }
|
||||
|
||||
public:
|
||||
/// Create a new ProgramPoint object that is the same as the original
|
||||
/// except for using the specified tag value.
|
||||
ProgramPoint withTag(const ProgramPointTag *tag) const {
|
||||
return ProgramPoint(Data.first, Data.second, K, L, tag);
|
||||
return ProgramPoint(getData1(), getData2(), getKind(),
|
||||
getLocationContext(), tag);
|
||||
}
|
||||
|
||||
Kind getKind() const { return K; }
|
||||
Kind getKind() const {
|
||||
unsigned x = L.getInt();
|
||||
x <<= 2;
|
||||
x |= Data2.getInt();
|
||||
x <<= 2;
|
||||
x |= Data1.getInt();
|
||||
return (Kind) x;
|
||||
}
|
||||
|
||||
const ProgramPointTag *getTag() const { return Tag; }
|
||||
|
||||
const LocationContext *getLocationContext() const { return L; }
|
||||
const LocationContext *getLocationContext() const {
|
||||
return L.getPointer();
|
||||
}
|
||||
|
||||
// For use with DenseMap. This hash is probably slow.
|
||||
unsigned getHashValue() const {
|
||||
|
|
@ -100,25 +129,30 @@ public:
|
|||
static bool classof(const ProgramPoint*) { return true; }
|
||||
|
||||
bool operator==(const ProgramPoint & RHS) const {
|
||||
return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag;
|
||||
return Data1 == Data1 &&
|
||||
Data2 == RHS.Data2 &&
|
||||
L == RHS.L &&
|
||||
Tag == RHS.Tag;
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramPoint &RHS) const {
|
||||
return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag;
|
||||
return Data1 != RHS.Data1 ||
|
||||
Data2 != RHS.Data2 ||
|
||||
L != RHS.L ||
|
||||
Tag != RHS.Tag;
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddInteger((unsigned) K);
|
||||
ID.AddPointer(Data.first);
|
||||
ID.AddPointer(Data.second);
|
||||
ID.AddPointer(L);
|
||||
ID.AddInteger((unsigned) getKind());
|
||||
ID.AddPointer(getData1());
|
||||
ID.AddPointer(getData2());
|
||||
ID.AddPointer(getLocationContext());
|
||||
ID.AddPointer(Tag);
|
||||
}
|
||||
|
||||
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
|
||||
const LocationContext *LC,
|
||||
const ProgramPointTag *tag);
|
||||
|
||||
};
|
||||
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
|
|
@ -195,7 +229,7 @@ public:
|
|||
class PostStmt : public StmtPoint {
|
||||
protected:
|
||||
PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
|
||||
const ProgramPointTag *tag =0)
|
||||
const ProgramPointTag *tag = 0)
|
||||
: StmtPoint(S, data, k, L, tag) {}
|
||||
|
||||
public:
|
||||
|
|
@ -270,15 +304,29 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \class Represents a program point after a store evaluation.
|
||||
class PostStore : public PostStmt {
|
||||
public:
|
||||
PostStore(const Stmt *S, const LocationContext *L,
|
||||
/// Construct the post store point.
|
||||
/// \param Loc can be used to store the information about the location
|
||||
/// used in the form it was uttered in the code.
|
||||
PostStore(const Stmt *S, const LocationContext *L, const void *Loc,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: PostStmt(S, PostStoreKind, L, tag) {}
|
||||
: PostStmt(S, PostStoreKind, L, tag) {
|
||||
assert(getData2() == 0);
|
||||
setData2(Loc);
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostStoreKind;
|
||||
}
|
||||
|
||||
/// \brief Returns the information about the location used in the store,
|
||||
/// how it was uttered in the code.
|
||||
const void *getLocationValue() const {
|
||||
return getData2();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class PostLValue : public PostStmt {
|
||||
|
|
@ -365,6 +413,21 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// This is a meta program point, which should be skipped by all the diagnostic
|
||||
/// reasoning etc.
|
||||
class EpsilonPoint : public ProgramPoint {
|
||||
public:
|
||||
EpsilonPoint(const LocationContext *L, const void *Data1,
|
||||
const void *Data2 = 0, const ProgramPointTag *tag = 0)
|
||||
: ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
|
||||
|
||||
const void *getData() const { return getData1(); }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == EpsilonKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// ProgramPoints can be "tagged" as representing points specific to a given
|
||||
/// analysis entity. Tags are abstract annotations, with an associated
|
||||
/// description and potentially other information.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue