Vendor import of clang trunk r154661:

http://llvm.org/svn/llvm-project/cfe/trunk@r154661
This commit is contained in:
Dimitry Andric 2012-04-14 14:01:31 +00:00
parent 9da628931e
commit dbe13110f5
2685 changed files with 181522 additions and 52786 deletions

View file

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

View file

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

View file

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

View file

@ -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.
//===---------------------------------------------------------------------===//

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View 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
View 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) &amp;&amp; __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>

View file

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

View file

@ -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 &mdash; for example, creating a
CF value, assigning it to an ObjC-typed local, and then
calling <tt>CFRelease</tt> when done &mdash; 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&amp;</tt> and <tt>U&amp;</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>&amp;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">

View file

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

View file

@ -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 &amp; 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>

View file

@ -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 ('&gt;&gt;') in template argument will require parentheses in C++0x
test.cpp:3:7: warning: use of right-shift operator ('&gt;&gt;') in template argument will require parentheses in C++11
A&lt;100 &gt;&gt; 2&gt; *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&amp;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

View file

@ -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>&gt&gt, &lt&lt</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>&amp;</code> or <code>&amp;&amp;</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>&lt;stdatomic.h&gt;</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) -&gt; 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>&lt;stdatomic.h&gt;</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>

View 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>&LT;objc/objc.h&GT;</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>&LT;NSCopying&GT;</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>

View file

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

View file

@ -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
View 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>&lt;atomic&gt;</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>

View file

@ -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 &quot;\&quot;&quot;) 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>

View file

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

View file

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

View file

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

View file

@ -9,6 +9,6 @@
CLANG_LEVEL := ..
PARALLEL_DIRS := clang-interpreter PrintFunctionNames
PARALLEL_DIRS := analyzer-plugin clang-interpreter PrintFunctionNames
include $(CLANG_LEVEL)/Makefile

View file

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

View file

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

View file

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

View file

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

View file

@ -11,7 +11,7 @@ CLANG_LEVEL := ../..
LIBRARYNAME = SampleAnalyzerPlugin
LINK_LIBS_IN_SHARED = 0
SHARED_LIBRARY = 1
LOADABLE_MODULE = 1
include $(CLANG_LEVEL)/Makefile

View file

@ -25,6 +25,7 @@ set(LLVM_LINK_COMPONENTS
bitwriter
codegen
ipo
linker
selectiondag
)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
};
}
}

View file

@ -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());

View file

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

View file

@ -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() {}

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

@ -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) {}

View 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

View file

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

View file

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

View file

@ -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());

View 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

View file

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

View file

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

View file

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

View file

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

View file

@ -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.
//===--------------------------------------------------------------------===//

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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, { })

View file

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

View file

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

View file

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

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

@ -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);
}

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

@ -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());

View file

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