Vendor import of clang release_30 branch r142614:
http://llvm.org/svn/llvm-project/cfe/branches/release_30@142614
This commit is contained in:
parent
180abc3db9
commit
36981b17ed
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=226586 svn path=/vendor/clang/clang-r142614/; revision=226587; tag=vendor/clang/clang-r142614
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
#==============================================================================#
|
||||
# This file specifies intentionally untracked files that git should ignore.
|
||||
# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
|
||||
#
|
||||
# This file is intentionally different from the output of `git svn show-ignore`,
|
||||
# as most of those are useless.
|
||||
#==============================================================================#
|
||||
|
||||
#==============================================================================#
|
||||
# File extensions to be ignored anywhere in the tree.
|
||||
#==============================================================================#
|
||||
# Temp files created by most text editors.
|
||||
*~
|
||||
# Merge files created by git.
|
||||
*.orig
|
||||
# Byte compiled python modules.
|
||||
*.pyc
|
||||
# vim swap files
|
||||
.*.swp
|
||||
|
||||
#==============================================================================#
|
||||
# Explicit files to ignore (only matches one).
|
||||
#==============================================================================#
|
||||
cscope.files
|
||||
cscope.out
|
@ -19,10 +19,10 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
# Looking for bin/Debug/tblgen is a complete hack. How can we get
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
# Looking for bin/Debug/llvm-tblgen is a complete hack. How can we get
|
||||
# around this?
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
if( NOT EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
message(FATAL_ERROR "Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
|
||||
endif()
|
||||
endif()
|
||||
@ -46,11 +46,11 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
||||
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
|
||||
link_directories("${PATH_TO_LLVM_BUILD}/lib")
|
||||
|
||||
if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/tblgen")
|
||||
if( EXISTS "${CLANG_PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}" )
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
else()
|
||||
# FIXME: This is an utter hack.
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/tblgen")
|
||||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
endif()
|
||||
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
|
||||
@ -153,7 +153,7 @@ function(clang_tablegen)
|
||||
endif()
|
||||
|
||||
set( LLVM_TARGET_DEFINITIONS ${CTG_SOURCE} )
|
||||
tablegen( ${CTG_DEFAULT_ARGS} )
|
||||
tablegen( CLANG ${CTG_DEFAULT_ARGS} )
|
||||
|
||||
list( GET CTG_DEFAULT_ARGS 0 output_file )
|
||||
if( CTG_TARGET )
|
||||
@ -244,6 +244,7 @@ set(LIBCLANG_LIBRARY_VERSION
|
||||
"Version number that will be placed into the libclang library , in the form XX.YY")
|
||||
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)
|
||||
@ -272,3 +273,6 @@ if( CLANG_BUILT_STANDALONE AND MSVC_VERSION EQUAL 1600 )
|
||||
file(APPEND "${CLANG_SLN_FILENAME}" "\n# This should be regenerated!\n")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
|
||||
"Default URL where bug reports are to be submitted.")
|
||||
|
59
INPUTS/cfg-nested-var-scopes.cpp
Normal file
59
INPUTS/cfg-nested-var-scopes.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
// Hammer the CFG with large numbers of overlapping variable scopes, which
|
||||
// implicit destructors triggered at each edge.
|
||||
|
||||
#define EXPAND_BASIC_STRUCT(i) struct X##i { X##i(int); ~X##i(); };
|
||||
#define EXPAND_NORET_STRUCT(i) struct X##i { X##i(int); ~X##i() __attribute__((noreturn)); };
|
||||
EXPAND_BASIC_STRUCT(0000); EXPAND_NORET_STRUCT(0001);
|
||||
EXPAND_BASIC_STRUCT(0010); EXPAND_BASIC_STRUCT(0011);
|
||||
EXPAND_BASIC_STRUCT(0100); EXPAND_NORET_STRUCT(0101);
|
||||
EXPAND_NORET_STRUCT(0110); EXPAND_BASIC_STRUCT(0111);
|
||||
EXPAND_BASIC_STRUCT(1000); EXPAND_NORET_STRUCT(1001);
|
||||
EXPAND_BASIC_STRUCT(1010); EXPAND_BASIC_STRUCT(1011);
|
||||
EXPAND_NORET_STRUCT(1100); EXPAND_NORET_STRUCT(1101);
|
||||
EXPAND_BASIC_STRUCT(1110); EXPAND_BASIC_STRUCT(1111);
|
||||
|
||||
#define EXPAND_2_VARS(c, i, x) const X##i var_##c##_##i##0(x), &var_##c##_##i##1 = X##i(x)
|
||||
#define EXPAND_4_VARS(c, i, x) EXPAND_2_VARS(c, i##0, x); EXPAND_2_VARS(c, i##1, x)
|
||||
#define EXPAND_8_VARS(c, i, x) EXPAND_4_VARS(c, i##0, x); EXPAND_4_VARS(c, i##1, x)
|
||||
#define EXPAND_16_VARS(c, i, x) EXPAND_8_VARS(c, i##0, x); EXPAND_8_VARS(c, i##1, x)
|
||||
#define EXPAND_32_VARS(c, x) EXPAND_16_VARS(c, 0, x); EXPAND_16_VARS(c, 1, x)
|
||||
|
||||
#define EXPAND_2_INNER_CASES(i, x, y) INNER_CASE(i, x, y); INNER_CASE(i + 1, x, y);
|
||||
#define EXPAND_4_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i, x, y) EXPAND_2_INNER_CASES(i + 2, x, y)
|
||||
#define EXPAND_8_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i, x, y) EXPAND_4_INNER_CASES(i + 4, x, y)
|
||||
#define EXPAND_16_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i, x, y) EXPAND_8_INNER_CASES(i + 8, x, y)
|
||||
#define EXPAND_32_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i, x, y) EXPAND_16_INNER_CASES(i + 16, x, y)
|
||||
|
||||
#define EXPAND_2_OUTER_CASES(i, x, y) OUTER_CASE(i, x, y); OUTER_CASE(i + 1, x, y);
|
||||
#define EXPAND_4_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i, x, y) EXPAND_2_OUTER_CASES(i + 2, x, y)
|
||||
#define EXPAND_8_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i, x, y) EXPAND_4_OUTER_CASES(i + 4, x, y)
|
||||
#define EXPAND_16_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i, x, y) EXPAND_8_OUTER_CASES(i + 8, x, y)
|
||||
#define EXPAND_32_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i, x, y) EXPAND_16_OUTER_CASES(i + 16, x, y)
|
||||
|
||||
unsigned cfg_nested_vars(int x) {
|
||||
int y = 0;
|
||||
while (x > 0) {
|
||||
EXPAND_32_VARS(a, x);
|
||||
switch (x) {
|
||||
#define INNER_CASE(i, x, y) \
|
||||
case i: { \
|
||||
int case_var = 3*x + i; \
|
||||
EXPAND_32_VARS(c, case_var); \
|
||||
y += case_var - 1; \
|
||||
break; \
|
||||
}
|
||||
#define OUTER_CASE(i, x, y) \
|
||||
case i: { \
|
||||
int case_var = y >> 8; \
|
||||
EXPAND_32_VARS(b, y); \
|
||||
switch (case_var) { \
|
||||
EXPAND_32_INNER_CASES(0, x, y); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
EXPAND_32_OUTER_CASES(0, x, y);
|
||||
}
|
||||
--x;
|
||||
}
|
||||
return y;
|
||||
}
|
14
Makefile
14
Makefile
@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
|
||||
|
||||
IS_TOP_LEVEL := 1
|
||||
CLANG_LEVEL := .
|
||||
DIRS := include lib tools runtime docs unittests
|
||||
DIRS := utils/TableGen include lib tools runtime docs unittests
|
||||
|
||||
PARALLEL_DIRS :=
|
||||
|
||||
@ -60,6 +60,16 @@ endif
|
||||
# We can revisit this when LLVM/Clang support it.
|
||||
CXX.Flags += -fno-strict-aliasing
|
||||
|
||||
# Set up Clang's tblgen.
|
||||
ifndef CLANG_TBLGEN
|
||||
ifeq ($(LLVM_CROSS_COMPILING),1)
|
||||
CLANG_TBLGEN := $(BuildLLVMToolDir)/clang-tblgen$(BUILD_EXEEXT)
|
||||
else
|
||||
CLANG_TBLGEN := $(LLVMToolDir)/clang-tblgen$(EXEEXT)
|
||||
endif
|
||||
endif
|
||||
ClangTableGen = $(CLANG_TBLGEN) $(TableGen.Flags)
|
||||
|
||||
###
|
||||
# Clang Top Level specific stuff.
|
||||
|
||||
@ -68,7 +78,7 @@ ifeq ($(IS_TOP_LEVEL),1)
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
$(RecursiveTargets)::
|
||||
$(Verb) for dir in test unittests; do \
|
||||
if [ ! -f $${dir}/Makefile ]; then \
|
||||
if [ -f $(PROJ_SRC_DIR)/$${dir}/Makefile ] && [ ! -f $${dir}/Makefile ]; then \
|
||||
$(MKDIR) $${dir}; \
|
||||
$(CP) $(PROJ_SRC_DIR)/$${dir}/Makefile $${dir}/Makefile; \
|
||||
fi \
|
||||
|
18
NOTES.txt
18
NOTES.txt
@ -83,3 +83,21 @@ enum VerifyConstraintResult {
|
||||
};
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Blocks should not capture variables that are only used in dead code.
|
||||
|
||||
The rule that we came up with is that blocks are required to capture
|
||||
variables if they're referenced in evaluated code, even if that code
|
||||
doesn't actually rely on the value of the captured variable.
|
||||
|
||||
For example, this requires a capture:
|
||||
(void) var;
|
||||
But this does not:
|
||||
if (false) puts(var);
|
||||
|
||||
Summary of <rdar://problem/9851835>: if we implement this, we should
|
||||
warn about non-POD variables that are referenced but not captured, but
|
||||
only if the non-reachability is not due to macro or template
|
||||
metaprogramming.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
75
TODO.txt
75
TODO.txt
@ -1,75 +0,0 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Minor random things that can be improved
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Warn about "X && 0x1000" saying that the user may mean "X & 0x1000".
|
||||
We should do this for any immediate except zero, so long as it doesn't come
|
||||
from a macro expansion. Likewise for ||.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Lexer-related diagnostics should point to the problematic character, not the
|
||||
start of the token. For example:
|
||||
|
||||
int y = 0000\
|
||||
00080;
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
int y = 0000\
|
||||
^
|
||||
|
||||
should be:
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
00080;
|
||||
^
|
||||
|
||||
This specific diagnostic is implemented, but others should be updated.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C++ (checker): For iterators, warn of the use of "iterator++" instead
|
||||
of "++iterator" when when the value returned by operator++(int) is
|
||||
ignored.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
We want to keep more source range information in Declarator to help
|
||||
produce better diagnostics. Declarator::getSourceRange() should be
|
||||
implemented to give a range for the whole declarator with all of its
|
||||
specifiers, and DeclaratorChunk::ParamInfo should also have a source
|
||||
range covering the whole parameter, so that an error message like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^
|
||||
can be turned into something like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^ ~~~~~~~~~~~~~~
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
For terminal output, we should consider limiting the amount of
|
||||
diagnostic text we print once the first error has been
|
||||
encountered. For example, once we have produced an error diagnostic,
|
||||
we should only continue producing diagnostics until we have produced a
|
||||
page full of results (say, 50 lines of text). Beyond that, (1) the
|
||||
remaining errors are likely to be less interesting, and (2) the poor
|
||||
user has to scroll his terminal to find out where things went wrong.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
More ideas for code modification hints:
|
||||
- If no member of a given name is found in a class/struct, search through the names of entities that do exist in the class and suggest the closest candidate. e.g., if I write "DS.setTypeSpecType", it would suggest "DS.SetTypeSpecType" (edit distance = 1).
|
||||
- If a class member is defined out-of-line but isn't in the class declaration (and there are no close matches!), provide the option to add an in-class declaration.
|
||||
- Fix-it hints for the inclusion of headers when needed for particular features (e.g., <typeinfo> for typeid)
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Options to support:
|
||||
-ftabstop=width
|
||||
-fpreprocessed mode.
|
||||
-nostdinc++
|
||||
-imultilib
|
||||
|
@ -112,7 +112,7 @@ def _get_instantiation(self):
|
||||
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
|
||||
self._data = (f, int(l.value), int(c.value), int(c.value))
|
||||
self._data = (f, int(l.value), int(c.value), int(o.value))
|
||||
return self._data
|
||||
|
||||
@property
|
||||
@ -451,6 +451,19 @@ def __repr__(self):
|
||||
# A C++ using declaration
|
||||
CursorKind.USING_DECLARATION = CursorKind(35)
|
||||
|
||||
# A Type alias decl.
|
||||
CursorKind.TYPE_ALIAS_DECL = CursorKind(36)
|
||||
|
||||
# A Objective-C synthesize decl
|
||||
CursorKind.OBJC_SYNTHESIZE_DECL = CursorKind(37)
|
||||
|
||||
# A Objective-C dynamic decl
|
||||
CursorKind.OBJC_DYNAMIC_DECL = CursorKind(38)
|
||||
|
||||
# A C++ access specifier decl.
|
||||
CursorKind.CXX_ACCESS_SPEC_DECL = CursorKind(39)
|
||||
|
||||
|
||||
###
|
||||
# Reference Kinds
|
||||
|
||||
@ -524,6 +537,154 @@ def __repr__(self):
|
||||
# An expression that represents a block literal.
|
||||
CursorKind.BLOCK_EXPR = CursorKind(105)
|
||||
|
||||
# An integer literal.
|
||||
CursorKind.INTEGER_LITERAL = CursorKind(106)
|
||||
|
||||
# A floating point number literal.
|
||||
CursorKind.FLOATING_LITERAL = CursorKind(107)
|
||||
|
||||
# An imaginary number literal.
|
||||
CursorKind.IMAGINARY_LITERAL = CursorKind(108)
|
||||
|
||||
# A string literal.
|
||||
CursorKind.STRING_LITERAL = CursorKind(109)
|
||||
|
||||
# A character literal.
|
||||
CursorKind.CHARACTER_LITERAL = CursorKind(110)
|
||||
|
||||
# A parenthesized expression, e.g. "(1)".
|
||||
#
|
||||
# This AST node is only formed if full location information is requested.
|
||||
CursorKind.PAREN_EXPR = CursorKind(111)
|
||||
|
||||
# This represents the unary-expression's (except sizeof and
|
||||
# alignof).
|
||||
CursorKind.UNARY_OPERATOR = CursorKind(112)
|
||||
|
||||
# [C99 6.5.2.1] Array Subscripting.
|
||||
CursorKind.ARRAY_SUBSCRIPT_EXPR = CursorKind(113)
|
||||
|
||||
# A builtin binary operation expression such as "x + y" or
|
||||
# "x <= y".
|
||||
CursorKind.BINARY_OPERATOR = CursorKind(114)
|
||||
|
||||
# Compound assignment such as "+=".
|
||||
CursorKind.COMPOUND_ASSIGNMENT_OPERATOR = CursorKind(115)
|
||||
|
||||
# The ?: ternary operator.
|
||||
CursorKind.CONDITONAL_OPERATOR = CursorKind(116)
|
||||
|
||||
# An explicit cast in C (C99 6.5.4) or a C-style cast in C++
|
||||
# (C++ [expr.cast]), which uses the syntax (Type)expr.
|
||||
#
|
||||
# For example: (int)f.
|
||||
CursorKind.CSTYLE_CAST_EXPR = CursorKind(117)
|
||||
|
||||
# [C99 6.5.2.5]
|
||||
CursorKind.COMPOUND_LITERAL_EXPR = CursorKind(118)
|
||||
|
||||
# Describes an C or C++ initializer list.
|
||||
CursorKind.INIT_LIST_EXPR = CursorKind(119)
|
||||
|
||||
# The GNU address of label extension, representing &&label.
|
||||
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.
|
||||
CursorKind.GENERIC_SELECTION_EXPR = CursorKind(122)
|
||||
|
||||
# Implements the GNU __null extension, which is a name for a null
|
||||
# pointer constant that has integral type (e.g., int or long) and is the same
|
||||
# size and alignment as a pointer.
|
||||
#
|
||||
# The __null extension is typically only used by system headers, which define
|
||||
# NULL as __null in C++ rather than using 0 (which is an integer that may not
|
||||
# match the size of a pointer).
|
||||
CursorKind.GNU_NULL_EXPR = CursorKind(123)
|
||||
|
||||
# C++'s static_cast<> expression.
|
||||
CursorKind.CXX_STATIC_CAST_EXPR = CursorKind(124)
|
||||
|
||||
# C++'s dynamic_cast<> expression.
|
||||
CursorKind.CXX_DYNAMIC_CAST_EXPR = CursorKind(125)
|
||||
|
||||
# C++'s reinterpret_cast<> expression.
|
||||
CursorKind.CXX_REINTERPRET_CAST_EXPR = CursorKind(126)
|
||||
|
||||
# C++'s const_cast<> expression.
|
||||
CursorKind.CXX_CONST_CAST_EXPR = CursorKind(127)
|
||||
|
||||
# Represents an explicit C++ type conversion that uses "functional"
|
||||
# notion (C++ [expr.type.conv]).
|
||||
#
|
||||
# Example:
|
||||
# \code
|
||||
# x = int(0.5);
|
||||
# \endcode
|
||||
CursorKind.CXX_FUNCTIONAL_CAST_EXPR = CursorKind(128)
|
||||
|
||||
# A C++ typeid expression (C++ [expr.typeid]).
|
||||
CursorKind.CXX_TYPEID_EXPR = CursorKind(129)
|
||||
|
||||
# [C++ 2.13.5] C++ Boolean Literal.
|
||||
CursorKind.CXX_BOOL_LITERAL_EXPR = CursorKind(130)
|
||||
|
||||
# [C++0x 2.14.7] C++ Pointer Literal.
|
||||
CursorKind.CXX_NULL_PTR_LITERAL_EXPR = CursorKind(131)
|
||||
|
||||
# Represents the "this" expression in C++
|
||||
CursorKind.CXX_THIS_EXPR = CursorKind(132)
|
||||
|
||||
# [C++ 15] C++ Throw Expression.
|
||||
#
|
||||
# This handles 'throw' and 'throw' assignment-expression. When
|
||||
# assignment-expression isn't present, Op will be null.
|
||||
CursorKind.CXX_THROW_EXPR = CursorKind(133)
|
||||
|
||||
# A new expression for memory allocation and constructor calls, e.g:
|
||||
# "new CXXNewExpr(foo)".
|
||||
CursorKind.CXX_NEW_EXPR = CursorKind(134)
|
||||
|
||||
# A delete expression for memory deallocation and destructor calls,
|
||||
# e.g. "delete[] pArray".
|
||||
CursorKind.CXX_DELETE_EXPR = CursorKind(135)
|
||||
|
||||
# Represents a unary expression.
|
||||
CursorKind.CXX_UNARY_EXPR = CursorKind(136)
|
||||
|
||||
# ObjCStringLiteral, used for Objective-C string literals i.e. "foo".
|
||||
CursorKind.OBJC_STRING_LITERAL = CursorKind(137)
|
||||
|
||||
# ObjCEncodeExpr, used for in Objective-C.
|
||||
CursorKind.OBJC_ENCODE_EXPR = CursorKind(138)
|
||||
|
||||
# ObjCSelectorExpr used for in Objective-C.
|
||||
CursorKind.OBJC_SELECTOR_EXPR = CursorKind(139)
|
||||
|
||||
# Objective-C's protocol expression.
|
||||
CursorKind.OBJC_PROTOCOL_EXPR = CursorKind(140)
|
||||
|
||||
# An Objective-C "bridged" cast expression, which casts between
|
||||
# Objective-C pointers and C pointers, transferring ownership in the process.
|
||||
#
|
||||
# \code
|
||||
# NSString *str = (__bridge_transfer NSString *)CFCreateString();
|
||||
# \endcode
|
||||
CursorKind.OBJC_BRIDGE_CAST_EXPR = CursorKind(141)
|
||||
|
||||
# Represents a C++0x pack expansion that produces a sequence of
|
||||
# expressions.
|
||||
#
|
||||
# A pack expansion expression contains a pattern (which itself is an
|
||||
# expression) followed by an ellipsis. For example:
|
||||
CursorKind.PACK_EXPANSION_EXPR = CursorKind(142)
|
||||
|
||||
# Represents an expression that computes the length of a parameter
|
||||
# pack.
|
||||
CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143)
|
||||
|
||||
# A statement whose specific kind is not exposed via this interface.
|
||||
#
|
||||
# Unexposed statements have the same operations as any other kind of statement;
|
||||
@ -534,6 +695,92 @@ def __repr__(self):
|
||||
# A labelled statement in a function.
|
||||
CursorKind.LABEL_STMT = CursorKind(201)
|
||||
|
||||
# A compound statement
|
||||
CursorKind.COMPOUND_STMT = CursorKind(202)
|
||||
|
||||
# A case statement.
|
||||
CursorKind.CASE_STMT = CursorKind(203)
|
||||
|
||||
# A default statement.
|
||||
CursorKind.DEFAULT_STMT = CursorKind(204)
|
||||
|
||||
# An if statement.
|
||||
CursorKind.IF_STMT = CursorKind(205)
|
||||
|
||||
# A switch statement.
|
||||
CursorKind.SWITCH_STMT = CursorKind(206)
|
||||
|
||||
# A while statement.
|
||||
CursorKind.WHILE_STMT = CursorKind(207)
|
||||
|
||||
# A do statement.
|
||||
CursorKind.DO_STMT = CursorKind(208)
|
||||
|
||||
# A for statement.
|
||||
CursorKind.FOR_STMT = CursorKind(209)
|
||||
|
||||
# A goto statement.
|
||||
CursorKind.GOTO_STMT = CursorKind(210)
|
||||
|
||||
# An indirect goto statement.
|
||||
CursorKind.INDIRECT_GOTO_STMT = CursorKind(211)
|
||||
|
||||
# A continue statement.
|
||||
CursorKind.CONTINUE_STMT = CursorKind(212)
|
||||
|
||||
# A break statement.
|
||||
CursorKind.BREAK_STMT = CursorKind(213)
|
||||
|
||||
# A return statement.
|
||||
CursorKind.RETURN_STMT = CursorKind(214)
|
||||
|
||||
# A GNU-style inline assembler statement.
|
||||
CursorKind.ASM_STMT = CursorKind(215)
|
||||
|
||||
# Objective-C's overall @try-@catch-@finally statement.
|
||||
CursorKind.OBJC_AT_TRY_STMT = CursorKind(216)
|
||||
|
||||
# Objective-C's @catch statement.
|
||||
CursorKind.OBJC_AT_CATCH_STMT = CursorKind(217)
|
||||
|
||||
# Objective-C's @finally statement.
|
||||
CursorKind.OBJC_AT_FINALLY_STMT = CursorKind(218)
|
||||
|
||||
# Objective-C's @throw statement.
|
||||
CursorKind.OBJC_AT_THROW_STMT = CursorKind(219)
|
||||
|
||||
# Objective-C's @synchronized statement.
|
||||
CursorKind.OBJC_AT_SYNCHRONIZED_STMT = CursorKind(220)
|
||||
|
||||
# Objective-C's autorealease pool statement.
|
||||
CursorKind.OBJC_AUTORELEASE_POOL_STMT = CursorKind(221)
|
||||
|
||||
# Objective-C's for collection statement.
|
||||
CursorKind.OBJC_FOR_COLLECTION_STMT = CursorKind(222)
|
||||
|
||||
# C++'s catch statement.
|
||||
CursorKind.CXX_CATCH_STMT = CursorKind(223)
|
||||
|
||||
# C++'s try statement.
|
||||
CursorKind.CXX_TRY_STMT = CursorKind(224)
|
||||
|
||||
# C++'s for (* : *) statement.
|
||||
CursorKind.CXX_FOR_RANGE_STMT = CursorKind(225)
|
||||
|
||||
# Windows Structured Exception Handling's try statement.
|
||||
CursorKind.SEH_TRY_STMT = CursorKind(226)
|
||||
|
||||
# Windows Structured Exception Handling's except statement.
|
||||
CursorKind.SEH_EXCEPT_STMT = CursorKind(227)
|
||||
|
||||
# Windows Structured Exception Handling's finally statement.
|
||||
CursorKind.SEH_FINALLY_STMT = CursorKind(228)
|
||||
|
||||
# The null statement.
|
||||
CursorKind.NULL_STMT = CursorKind(230)
|
||||
|
||||
# Adaptor class for mixing declarations with statements and expressions.
|
||||
CursorKind.DECL_STMT = CursorKind(231)
|
||||
|
||||
###
|
||||
# Other Kinds
|
||||
@ -616,7 +863,22 @@ def spelling(self):
|
||||
# FIXME: clang_getCursorSpelling should be fixed to not assert on
|
||||
# this, for consistency with clang_getCursorUSR.
|
||||
return None
|
||||
return Cursor_spelling(self)
|
||||
if not hasattr(self, '_spelling'):
|
||||
self._spelling = Cursor_spelling(self)
|
||||
return self._spelling
|
||||
|
||||
@property
|
||||
def displayname(self):
|
||||
"""
|
||||
Return the display name for the entity referenced by this cursor.
|
||||
|
||||
The display name contains extra information that helps identify the cursor,
|
||||
such as the parameters of a function or template or the arguments of a
|
||||
class template specialization.
|
||||
"""
|
||||
if not hasattr(self, '_displayname'):
|
||||
self._displayname = Cursor_displayname(self)
|
||||
return self._displayname
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
@ -624,7 +886,9 @@ def location(self):
|
||||
Return the source location (the starting character) of the entity
|
||||
pointed at by the cursor.
|
||||
"""
|
||||
return Cursor_loc(self)
|
||||
if not hasattr(self, '_loc'):
|
||||
self._loc = Cursor_loc(self)
|
||||
return self._loc
|
||||
|
||||
@property
|
||||
def extent(self):
|
||||
@ -632,7 +896,19 @@ def extent(self):
|
||||
Return the source range (the range of text) occupied by the entity
|
||||
pointed at by the cursor.
|
||||
"""
|
||||
return Cursor_extent(self)
|
||||
if not hasattr(self, '_extent'):
|
||||
self._extent = Cursor_extent(self)
|
||||
return self._extent
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Retrieve the type (if any) of of the entity pointed at by the
|
||||
cursor.
|
||||
"""
|
||||
if not hasattr(self, '_type'):
|
||||
self._type = Cursor_type(self)
|
||||
return self._type
|
||||
|
||||
def get_children(self):
|
||||
"""Return an iterator for accessing the children of this cursor."""
|
||||
@ -656,6 +932,165 @@ def from_result(res, fn, args):
|
||||
return None
|
||||
return res
|
||||
|
||||
|
||||
### Type Kinds ###
|
||||
|
||||
class TypeKind(object):
|
||||
"""
|
||||
Describes the kind of type.
|
||||
"""
|
||||
|
||||
# The unique kind objects, indexed by id.
|
||||
_kinds = []
|
||||
_name_map = None
|
||||
|
||||
def __init__(self, value):
|
||||
if value >= len(TypeKind._kinds):
|
||||
TypeKind._kinds += [None] * (value - len(TypeKind._kinds) + 1)
|
||||
if TypeKind._kinds[value] is not None:
|
||||
raise ValueError,'TypeKind already loaded'
|
||||
self.value = value
|
||||
TypeKind._kinds[value] = self
|
||||
TypeKind._name_map = None
|
||||
|
||||
def from_param(self):
|
||||
return self.value
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Get the enumeration name of this cursor kind."""
|
||||
if self._name_map is None:
|
||||
self._name_map = {}
|
||||
for key,value in TypeKind.__dict__.items():
|
||||
if isinstance(value,TypeKind):
|
||||
self._name_map[value] = key
|
||||
return self._name_map[self]
|
||||
|
||||
@staticmethod
|
||||
def from_id(id):
|
||||
if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
|
||||
raise ValueError,'Unknown cursor kind'
|
||||
return TypeKind._kinds[id]
|
||||
|
||||
def __repr__(self):
|
||||
return 'TypeKind.%s' % (self.name,)
|
||||
|
||||
|
||||
|
||||
TypeKind.INVALID = TypeKind(0)
|
||||
TypeKind.UNEXPOSED = TypeKind(1)
|
||||
TypeKind.VOID = TypeKind(2)
|
||||
TypeKind.BOOL = TypeKind(3)
|
||||
TypeKind.CHAR_U = TypeKind(4)
|
||||
TypeKind.UCHAR = TypeKind(5)
|
||||
TypeKind.CHAR16 = TypeKind(6)
|
||||
TypeKind.CHAR32 = TypeKind(7)
|
||||
TypeKind.USHORT = TypeKind(8)
|
||||
TypeKind.UINT = TypeKind(9)
|
||||
TypeKind.ULONG = TypeKind(10)
|
||||
TypeKind.ULONGLONG = TypeKind(11)
|
||||
TypeKind.UINT128 = TypeKind(12)
|
||||
TypeKind.CHAR_S = TypeKind(13)
|
||||
TypeKind.SCHAR = TypeKind(14)
|
||||
TypeKind.WCHAR = TypeKind(15)
|
||||
TypeKind.SHORT = TypeKind(16)
|
||||
TypeKind.INT = TypeKind(17)
|
||||
TypeKind.LONG = TypeKind(18)
|
||||
TypeKind.LONGLONG = TypeKind(19)
|
||||
TypeKind.INT128 = TypeKind(20)
|
||||
TypeKind.FLOAT = TypeKind(21)
|
||||
TypeKind.DOUBLE = TypeKind(22)
|
||||
TypeKind.LONGDOUBLE = TypeKind(23)
|
||||
TypeKind.NULLPTR = TypeKind(24)
|
||||
TypeKind.OVERLOAD = TypeKind(25)
|
||||
TypeKind.DEPENDENT = TypeKind(26)
|
||||
TypeKind.OBJCID = TypeKind(27)
|
||||
TypeKind.OBJCCLASS = TypeKind(28)
|
||||
TypeKind.OBJCSEL = TypeKind(29)
|
||||
TypeKind.COMPLEX = TypeKind(100)
|
||||
TypeKind.POINTER = TypeKind(101)
|
||||
TypeKind.BLOCKPOINTER = TypeKind(102)
|
||||
TypeKind.LVALUEREFERENCE = TypeKind(103)
|
||||
TypeKind.RVALUEREFERENCE = TypeKind(104)
|
||||
TypeKind.RECORD = TypeKind(105)
|
||||
TypeKind.ENUM = TypeKind(106)
|
||||
TypeKind.TYPEDEF = TypeKind(107)
|
||||
TypeKind.OBJCINTERFACE = TypeKind(108)
|
||||
TypeKind.OBJCOBJECTPOINTER = TypeKind(109)
|
||||
TypeKind.FUNCTIONNOPROTO = TypeKind(110)
|
||||
TypeKind.FUNCTIONPROTO = TypeKind(111)
|
||||
|
||||
|
||||
class Type(Structure):
|
||||
"""
|
||||
The type of an element in the abstract syntax tree.
|
||||
"""
|
||||
_fields_ = [("_kind_id", c_int), ("data", c_void_p * 2)]
|
||||
|
||||
@property
|
||||
def kind(self):
|
||||
"""Return the kind of this type."""
|
||||
return TypeKind.from_id(self._kind_id)
|
||||
|
||||
@staticmethod
|
||||
def from_result(res, fn, args):
|
||||
assert isinstance(res, Type)
|
||||
return res
|
||||
|
||||
def get_canonical(self):
|
||||
"""
|
||||
Return the canonical type for a Type.
|
||||
|
||||
Clang's type system explicitly models typedefs and all the
|
||||
ways a specific type can be represented. The canonical type
|
||||
is the underlying type with all the "sugar" removed. For
|
||||
example, if 'T' is a typedef for 'int', the canonical type for
|
||||
'T' would be 'int'.
|
||||
"""
|
||||
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"
|
||||
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.
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
return Type_is_restrict_qualified(self)
|
||||
|
||||
def get_pointee(self):
|
||||
"""
|
||||
For pointer types, returns the type of the pointee.
|
||||
"""
|
||||
return Type_get_pointee(self)
|
||||
|
||||
def get_declaration(self):
|
||||
"""
|
||||
Return the cursor for the declaration of the given type.
|
||||
"""
|
||||
return Type_get_declaration(self)
|
||||
|
||||
def get_result(self):
|
||||
"""
|
||||
Retrieve the result type associated with a function type.
|
||||
"""
|
||||
return Type_get_result(self)
|
||||
|
||||
## CIndex Objects ##
|
||||
|
||||
# CIndex objects (derived from ClangObject) are essentially lightweight
|
||||
@ -1210,11 +1645,50 @@ def is_input_file(self):
|
||||
Cursor_ref.restype = Cursor
|
||||
Cursor_ref.errcheck = Cursor.from_result
|
||||
|
||||
Cursor_type = lib.clang_getCursorType
|
||||
Cursor_type.argtypes = [Cursor]
|
||||
Cursor_type.restype = Type
|
||||
Cursor_type.errcheck = Type.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]
|
||||
Cursor_visit.restype = c_uint
|
||||
|
||||
# Type Functions
|
||||
Type_get_canonical = lib.clang_getCanonicalType
|
||||
Type_get_canonical.argtypes = [Type]
|
||||
Type_get_canonical.restype = Type
|
||||
Type_get_canonical.errcheck = Type.from_result
|
||||
|
||||
Type_is_const_qualified = lib.clang_isConstQualifiedType
|
||||
Type_is_const_qualified.argtypes = [Type]
|
||||
Type_is_const_qualified.restype = bool
|
||||
|
||||
Type_is_volatile_qualified = lib.clang_isVolatileQualifiedType
|
||||
Type_is_volatile_qualified.argtypes = [Type]
|
||||
Type_is_volatile_qualified.restype = bool
|
||||
|
||||
Type_is_restrict_qualified = lib.clang_isRestrictQualifiedType
|
||||
Type_is_restrict_qualified.argtypes = [Type]
|
||||
Type_is_restrict_qualified.restype = bool
|
||||
|
||||
Type_get_pointee = lib.clang_getPointeeType
|
||||
Type_get_pointee.argtypes = [Type]
|
||||
Type_get_pointee.restype = Type
|
||||
Type_get_pointee.errcheck = Type.from_result
|
||||
|
||||
Type_get_declaration = lib.clang_getTypeDeclaration
|
||||
Type_get_declaration.argtypes = [Type]
|
||||
Type_get_declaration.restype = Cursor
|
||||
Type_get_declaration.errcheck = Cursor.from_result
|
||||
|
||||
Type_get_result = lib.clang_getResultType
|
||||
Type_get_result.argtypes = [Type]
|
||||
Type_get_result.restype = Type
|
||||
Type_get_result.errcheck = Type.from_result
|
||||
|
||||
|
||||
# Index Functions
|
||||
Index_create = lib.clang_createIndex
|
||||
Index_create.argtypes = [c_int, c_int]
|
||||
@ -1313,6 +1787,6 @@ def is_input_file(self):
|
||||
|
||||
###
|
||||
|
||||
__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind',
|
||||
__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind', 'Type', 'TypeKind',
|
||||
'Diagnostic', 'FixIt', 'CodeCompletionResults', 'SourceRange',
|
||||
'SourceLocation', 'File']
|
||||
|
@ -1,4 +1,4 @@
|
||||
from clang.cindex import Index, CursorKind
|
||||
from clang.cindex import Index, CursorKind, TypeKind
|
||||
|
||||
kInput = """\
|
||||
// FIXME: Find nicer way to drop builtins and other cruft.
|
||||
@ -47,13 +47,17 @@ def test_get_children():
|
||||
assert len(s0_nodes) == 2
|
||||
assert s0_nodes[0].kind == CursorKind.FIELD_DECL
|
||||
assert s0_nodes[0].spelling == 'a'
|
||||
assert s0_nodes[0].type.kind == TypeKind.INT
|
||||
assert s0_nodes[1].kind == CursorKind.FIELD_DECL
|
||||
assert s0_nodes[1].spelling == 'b'
|
||||
assert s0_nodes[1].type.kind == TypeKind.INT
|
||||
|
||||
assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
|
||||
assert tu_nodes[1].spelling == 's1'
|
||||
assert tu_nodes[1].displayname == 's1'
|
||||
assert tu_nodes[1].is_definition() == False
|
||||
|
||||
assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
|
||||
assert tu_nodes[2].spelling == 'f0'
|
||||
assert tu_nodes[2].displayname == 'f0(int, int)'
|
||||
assert tu_nodes[2].is_definition() == True
|
||||
|
@ -36,7 +36,7 @@ def test_diagnostic_fixit():
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 31
|
||||
assert tu.diagnostics[0].location.column == 26
|
||||
assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
|
||||
assert len(tu.diagnostics[0].fixits) == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.start.line == 1
|
||||
|
50
bindings/python/tests/cindex/test_location.py
Normal file
50
bindings/python/tests/cindex/test_location.py
Normal file
@ -0,0 +1,50 @@
|
||||
from clang.cindex import Index
|
||||
|
||||
baseInput="int one;\nint two;\n"
|
||||
|
||||
def assert_location(loc, line, column, offset):
|
||||
assert loc.line == line
|
||||
assert loc.column == column
|
||||
assert loc.offset == offset
|
||||
|
||||
def test_location():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
|
||||
|
||||
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)
|
||||
|
||||
# adding a linebreak at top should keep columns same
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',"\n"+baseInput)])
|
||||
|
||||
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)
|
||||
|
||||
# adding a space should affect column on first line only
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c'," "+baseInput)])
|
||||
|
||||
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)
|
||||
|
||||
def test_extent():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
|
||||
|
||||
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"
|
76
bindings/python/tests/cindex/test_type.py
Normal file
76
bindings/python/tests/cindex/test_type.py
Normal file
@ -0,0 +1,76 @@
|
||||
from clang.cindex import Index, CursorKind, TypeKind
|
||||
|
||||
kInput = """\
|
||||
|
||||
typedef int I;
|
||||
|
||||
struct teststruct {
|
||||
int a;
|
||||
I b;
|
||||
long c;
|
||||
unsigned long d;
|
||||
signed long e;
|
||||
const int f;
|
||||
int *g;
|
||||
int ***h;
|
||||
};
|
||||
|
||||
"""
|
||||
|
||||
def test_a_struct():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
|
||||
|
||||
for n in tu.cursor.get_children():
|
||||
if n.spelling == 'teststruct':
|
||||
fields = list(n.get_children())
|
||||
|
||||
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[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[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[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??"
|
File diff suppressed because it is too large
Load Diff
@ -1315,6 +1315,39 @@ and only if the value is not demonstrably already retained.</p>
|
||||
<p>The complete optimization rules are quite complicated, but it would
|
||||
still be useful to document them here.</p>
|
||||
|
||||
<div id="optimization.precise">
|
||||
<h1>Precise lifetime semantics</h1>
|
||||
|
||||
<p>In general, ARC maintains an invariant that a retainable object
|
||||
pointer held in a <tt>__strong</tt> object will be retained for the
|
||||
full formal lifetime of the object. Objects subject to this invariant
|
||||
have <span class="term">precise lifetime semantics</span>.</p>
|
||||
|
||||
<p>By default, local variables of automatic storage duration do not
|
||||
have precise lifetime semantics. Such objects are simply strong
|
||||
references which hold values of retainable object pointer type, and
|
||||
these values are still fully subject to the optimizations on values
|
||||
under local control.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: applying these precise-lifetime
|
||||
semantics strictly would be prohibitive. Many useful optimizations
|
||||
that might theoretically decrease the lifetime of an object would be
|
||||
rendered impossible. Essentially, it promises too much.</p></div>
|
||||
|
||||
<p>A local variable of retainable object owner type and automatic
|
||||
storage duration may be annotated with the <tt>objc_precise_lifetime</tt>
|
||||
attribute to indicate that it should be considered to be an object
|
||||
with precise lifetime semantics.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: nonetheless, it is sometimes
|
||||
useful to be able to force an object to be released at a precise time,
|
||||
even if that object does not appear to be used. This is likely to be
|
||||
uncommon enough that the syntactic weight of explicitly requesting
|
||||
these semantics will not be burdensome, and may even make the code
|
||||
clearer.</p></div>
|
||||
|
||||
</div> <!-- optimization.precise -->
|
||||
|
||||
</div>
|
||||
|
||||
<div id="misc">
|
||||
@ -1562,6 +1595,56 @@ from exceptions.</p></div>
|
||||
|
||||
</div> <!-- misc.exceptions -->
|
||||
|
||||
<div id="misc.interior">
|
||||
<h1>Interior pointers</h1>
|
||||
|
||||
<p>An Objective-C method returning a non-retainable pointer may be
|
||||
annotated with the <tt>objc_returns_inner_pointer</tt> attribute to
|
||||
indicate that it returns a handle to the internal data of an object,
|
||||
and that this reference will be invalidated if the object is
|
||||
destroyed. When such a message is sent to an object, the object's
|
||||
lifetime will be extended until at least the earliest of:</p>
|
||||
|
||||
<ul>
|
||||
<li>the last use of the returned pointer, or any pointer derived from
|
||||
it, in the calling function or</li>
|
||||
<li>the autorelease pool is restored to a previous state.</li>
|
||||
</ul>
|
||||
|
||||
<div class="rationale"><p>Rationale: not all memory and resources are
|
||||
managed with reference counts; it is common for objects to manage
|
||||
private resources in their own, private way. Typically these
|
||||
resources are completely encapsulated within the object, but some
|
||||
classes offer their users direct access for efficiency. If ARC is not
|
||||
aware of methods that return such <q>interior</q> pointers, its
|
||||
optimizations can cause the owning object to be reclaimed too soon.
|
||||
This attribute informs ARC that it must tread lightly.</p>
|
||||
|
||||
<p>The extension rules are somewhat intentionally vague. The
|
||||
autorelease pool limit is there to permit a simple implementation to
|
||||
simply retain and autorelease the receiver. The other limit permits
|
||||
some amount of optimization. The phrase <q>derived from</q> is
|
||||
intended to encompass the results both of pointer transformations,
|
||||
such as casts and arithmetic, and of loading from such derived
|
||||
pointers; furthermore, it applies whether or not such derivations are
|
||||
applied directly in the calling code or by other utility code (for
|
||||
example, the C library routine <tt>strchr</tt>). However, the
|
||||
implementation never need account for uses after a return from the
|
||||
code which calls the method returning an interior pointer.</p></div>
|
||||
|
||||
<p>As an exception, no extension is required if the receiver is loaded
|
||||
directly from a <tt>__strong</tt> object
|
||||
with <a href="#optimization.precise">precise lifetime semantics</a>.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: implicit autoreleases carry the
|
||||
risk of significantly inflating memory use, so it's important to
|
||||
provide users a way of avoiding these autoreleases. Tying this to
|
||||
precise lifetime semantics is ideal, as for local variables this
|
||||
requires a very explicit annotation, which allows ARC to trust the
|
||||
user with good cheer.</p></div>
|
||||
|
||||
</div> <!-- misc.interior -->
|
||||
|
||||
</div> <!-- misc -->
|
||||
|
||||
<div id="runtime">
|
||||
|
@ -71,6 +71,7 @@ td {
|
||||
<li><a href="#Howtos">Howto guides</a>
|
||||
<ul>
|
||||
<li><a href="#AddingAttributes">How to add an attribute</a></li>
|
||||
<li><a href="#AddingExprStmt">How to add a new expression or statement</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@ -1785,6 +1786,228 @@ Check for the attribute's presence using <tt>Decl::getAttr<YourAttr>()</tt>.<
|
||||
<p>Update the <a href="LanguageExtensions.html">Clang Language Extensions</a>
|
||||
document to describe your new attribute.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="AddingExprStmt">How to add an expression or statement</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Expressions and statements are one of the most fundamental constructs within a
|
||||
compiler, because they interact with many different parts of the AST,
|
||||
semantic analysis, and IR generation. Therefore, adding a new
|
||||
expression or statement kind into Clang requires some care. The following list
|
||||
details the various places in Clang where an expression or statement needs to be
|
||||
introduced, along with patterns to follow to ensure that the new
|
||||
expression or statement works well across all of the C languages. We
|
||||
focus on expressions, but statements are similar.</p>
|
||||
|
||||
<ol>
|
||||
<li>Introduce parsing actions into the parser. Recursive-descent
|
||||
parsing is mostly self-explanatory, but there are a few things that
|
||||
are worth keeping in mind:
|
||||
<ul>
|
||||
<li>Keep as much source location information as possible! You'll
|
||||
want it later to produce great diagnostics and support Clang's
|
||||
various features that map between source code and the AST.</li>
|
||||
<li>Write tests for all of the "bad" parsing cases, to make sure
|
||||
your recovery is good. If you have matched delimiters (e.g.,
|
||||
parentheses, square brackets, etc.), use
|
||||
<tt>Parser::BalancedDelimiterTracker</tt> to give nice diagnostics when
|
||||
things go wrong.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Introduce semantic analysis actions into <tt>Sema</tt>. Semantic
|
||||
analysis should always involve two functions: an <tt>ActOnXXX</tt>
|
||||
function that will be called directly from the parser, and a
|
||||
<tt>BuildXXX</tt> function that performs the actual semantic
|
||||
analysis and will (eventually!) build the AST node. It's fairly
|
||||
common for the <tt>ActOnCXX</tt> function to do very little (often
|
||||
just some minor translation from the parser's representation to
|
||||
<tt>Sema</tt>'s representation of the same thing), but the separation
|
||||
is still important: C++ template instantiation, for example,
|
||||
should always call the <tt>BuildXXX</tt> variant. Several notes on
|
||||
semantic analysis before we get into construction of the AST:
|
||||
<ul>
|
||||
<li>Your expression probably involves some types and some
|
||||
subexpressions. Make sure to fully check that those types, and the
|
||||
types of those subexpressions, meet your expectations. Add
|
||||
implicit conversions where necessary to make sure that all of the
|
||||
types line up exactly the way you want them. Write extensive tests
|
||||
to check that you're getting good diagnostics for mistakes and
|
||||
that you can use various forms of subexpressions with your
|
||||
expression.</li>
|
||||
<li>When type-checking a type or subexpression, make sure to first
|
||||
check whether the type is "dependent"
|
||||
(<tt>Type::isDependentType()</tt>) or whether a subexpression is
|
||||
type-dependent (<tt>Expr::isTypeDependent()</tt>). If any of these
|
||||
return true, then you're inside a template and you can't do much
|
||||
type-checking now. That's normal, and your AST node (when you get
|
||||
there) will have to deal with this case. At this point, you can
|
||||
write tests that use your expression within templates, but don't
|
||||
try to instantiate the templates.</li>
|
||||
<li>For each subexpression, be sure to call
|
||||
<tt>Sema::CheckPlaceholderExpr()</tt> to deal with "weird"
|
||||
expressions that don't behave well as subexpressions. Then,
|
||||
determine whether you need to perform
|
||||
lvalue-to-rvalue conversions
|
||||
(<tt>Sema::DefaultLvalueConversion</tt>e) or
|
||||
the usual unary conversions
|
||||
(<tt>Sema::UsualUnaryConversions</tt>), for places where the
|
||||
subexpression is producing a value you intend to use.</li>
|
||||
<li>Your <tt>BuildXXX</tt> function will probably just return
|
||||
<tt>ExprError()</tt> at this point, since you don't have an AST.
|
||||
That's perfectly fine, and shouldn't impact your testing.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Introduce an AST node for your new expression. This starts with
|
||||
declaring the node in <tt>include/Basic/StmtNodes.td</tt> and
|
||||
creating a new class for your expression in the appropriate
|
||||
<tt>include/AST/Expr*.h</tt> header. It's best to look at the class
|
||||
for a similar expression to get ideas, and there are some specific
|
||||
things to watch for:
|
||||
<ul>
|
||||
<li>If you need to allocate memory, use the <tt>ASTContext</tt>
|
||||
allocator to allocate memory. Never use raw <tt>malloc</tt> or
|
||||
<tt>new</tt>, and never hold any resources in an AST node, because
|
||||
the destructor of an AST node is never called.</li>
|
||||
|
||||
<li>Make sure that <tt>getSourceRange()</tt> covers the exact
|
||||
source range of your expression. This is needed for diagnostics
|
||||
and for IDE support.</li>
|
||||
|
||||
<li>Make sure that <tt>children()</tt> visits all of the
|
||||
subexpressions. This is important for a number of features (e.g., IDE
|
||||
support, C++ variadic templates). If you have sub-types, you'll
|
||||
also need to visit those sub-types in the
|
||||
<tt>RecursiveASTVisitor</tt>.</li>
|
||||
|
||||
<li>Add printing support (<tt>StmtPrinter.cpp</tt>) and dumping
|
||||
support (<tt>StmtDumper.cpp</tt>) for your expression.</li>
|
||||
|
||||
<li>Add profiling support (<tt>StmtProfile.cpp</tt>) for your AST
|
||||
node, noting the distinguishing (non-source location)
|
||||
characteristics of an instance of your expression. Omitting this
|
||||
step will lead to hard-to-diagnose failures regarding matching of
|
||||
template declarations.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Teach semantic analysis to build your AST node! At this point,
|
||||
you can wire up your <tt>Sema::BuildXXX</tt> function to actually
|
||||
create your AST. A few things to check at this point:
|
||||
<ul>
|
||||
<li>If your expression can construct a new C++ class or return a
|
||||
new Objective-C object, be sure to update and then call
|
||||
<tt>Sema::MaybeBindToTemporary</tt> for your just-created AST node
|
||||
to be sure that the object gets properly destructed. An easy way
|
||||
to test this is to return a C++ class with a private destructor:
|
||||
semantic analysis should flag an error here with the attempt to
|
||||
call the destructor.</li>
|
||||
<li>Inspect the generated AST by printing it using <tt>clang -cc1
|
||||
-ast-print</tt>, to make sure you're capturing all of the
|
||||
important information about how the AST was written.</li>
|
||||
<li>Inspect the generated AST under <tt>clang -cc1 -ast-dump</tt>
|
||||
to verify that all of the types in the generated AST line up the
|
||||
way you want them. Remember that clients of the AST should never
|
||||
have to "think" to understand what's going on. For example, all
|
||||
implicit conversions should show up explicitly in the AST.</li>
|
||||
<li>Write tests that use your expression as a subexpression of
|
||||
other, well-known expressions. Can you call a function using your
|
||||
expression as an argument? Can you use the ternary operator?</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Teach code generation to create IR to your AST node. This step
|
||||
is the first (and only) that requires knowledge of LLVM IR. There
|
||||
are several things to keep in mind:
|
||||
<ul>
|
||||
<li>Code generation is separated into scalar/aggregate/complex and
|
||||
lvalue/rvalue paths, depending on what kind of result your
|
||||
expression produces. On occasion, this requires some careful
|
||||
factoring of code to avoid duplication.</li>
|
||||
|
||||
<li><tt>CodeGenFunction</tt> contains functions
|
||||
<tt>ConvertType</tt> and <tt>ConvertTypeForMem</tt> that convert
|
||||
Clang's types (<tt>clang::Type*</tt> or <tt>clang::QualType</tt>)
|
||||
to LLVM types.
|
||||
Use the former for values, and the later for memory locations:
|
||||
test with the C++ "bool" type to check this. If you find
|
||||
that you are having to use LLVM bitcasts to make
|
||||
the subexpressions of your expression have the type that your
|
||||
expression expects, STOP! Go fix semantic analysis and the AST so
|
||||
that you don't need these bitcasts.</li>
|
||||
|
||||
<li>The <tt>CodeGenFunction</tt> class has a number of helper
|
||||
functions to make certain operations easy, such as generating code
|
||||
to produce an lvalue or an rvalue, or to initialize a memory
|
||||
location with a given value. Prefer to use these functions rather
|
||||
than directly writing loads and stores, because these functions
|
||||
take care of some of the tricky details for you (e.g., for
|
||||
exceptions).</li>
|
||||
|
||||
<li>If your expression requires some special behavior in the event
|
||||
of an exception, look at the <tt>push*Cleanup</tt> functions in
|
||||
<tt>CodeGenFunction</tt> to introduce a cleanup. You shouldn't
|
||||
have to deal with exception-handling directly.</li>
|
||||
|
||||
<li>Testing is extremely important in IR generation. Use <tt>clang
|
||||
-cc1 -emit-llvm</tt> and <a
|
||||
href="http://llvm.org/cmds/FileCheck.html">FileCheck</a> to verify
|
||||
that you're generating the right IR.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Teach template instantiation how to cope with your AST
|
||||
node, which requires some fairly simple code:
|
||||
<ul>
|
||||
<li>Make sure that your expression's constructor properly
|
||||
computes the flags for type dependence (i.e., the type your
|
||||
expression produces can change from one instantiation to the
|
||||
next), value dependence (i.e., the constant value your expression
|
||||
produces can change from one instantiation to the next),
|
||||
instantiation dependence (i.e., a template parameter occurs
|
||||
anywhere in your expression), and whether your expression contains
|
||||
a parameter pack (for variadic templates). Often, computing these
|
||||
flags just means combining the results from the various types and
|
||||
subexpressions.</li>
|
||||
|
||||
<li>Add <tt>TransformXXX</tt> and <tt>RebuildXXX</tt> functions to
|
||||
the
|
||||
<tt>TreeTransform</tt> class template in <tt>Sema</tt>.
|
||||
<tt>TransformXXX</tt> should (recursively) transform all of the
|
||||
subexpressions and types
|
||||
within your expression, using <tt>getDerived().TransformYYY</tt>.
|
||||
If all of the subexpressions and types transform without error, it
|
||||
will then call the <tt>RebuildXXX</tt> function, which will in
|
||||
turn call <tt>getSema().BuildXXX</tt> to perform semantic analysis
|
||||
and build your expression.</li>
|
||||
|
||||
<li>To test template instantiation, take those tests you wrote to
|
||||
make sure that you were type checking with type-dependent
|
||||
expressions and dependent types (from step #2) and instantiate
|
||||
those templates with various types, some of which type-check and
|
||||
some that don't, and test the error messages in each case.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>There are some "extras" that make other features work better.
|
||||
It's worth handling these extras to give your expression complete
|
||||
integration into Clang:
|
||||
<ul>
|
||||
<li>Add code completion support for your expression in
|
||||
<tt>SemaCodeComplete.cpp</tt>.</li>
|
||||
|
||||
<li>If your expression has types in it, or has any "interesting"
|
||||
features other than subexpressions, extend libclang's
|
||||
<tt>CursorVisitor</tt> to provide proper visitation for your
|
||||
expression, enabling various IDE features such as syntax
|
||||
highlighting, cross-referencing, and so on. The
|
||||
<tt>c-index-test</tt> helper program can be used to test these
|
||||
features.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Clang LanguageExtensions</title>
|
||||
<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">
|
||||
@ -38,29 +38,41 @@
|
||||
<ul>
|
||||
<li><a href="#cxx0x">C++0x</a>
|
||||
<ul>
|
||||
<li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
|
||||
<li><a href="#cxx_access_control_sfinae">C++0x SFINAE includes access control</a></li>
|
||||
<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_variadic_templates">C++0x variadic templates</a></li>
|
||||
<li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
|
||||
<li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</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_noexcept">C++0x noexcept specification</a></li>
|
||||
</ul></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>
|
||||
<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>
|
||||
@ -71,9 +83,11 @@
|
||||
<ul>
|
||||
<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>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
|
||||
<li><a href="#complex-list-init">Initializer lists for complex numbers in C</a></li>
|
||||
<li><a href="#builtins">Builtin Functions</a>
|
||||
<ul>
|
||||
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
|
||||
@ -87,6 +101,27 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
|
||||
<li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
|
||||
<ul>
|
||||
<li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>
|
||||
<li><a href="#ts_lockable"><tt>lockable</tt></a></li>
|
||||
<li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>
|
||||
<li><a href="#ts_guardedvar"><tt>guarded_var</tt></a></li>
|
||||
<li><a href="#ts_ptguardedvar"><tt>pt_guarded_var</tt></a></li>
|
||||
<li><a href="#ts_guardedby"><tt>guarded_by(l)</tt></a></li>
|
||||
<li><a href="#ts_ptguardedby"><tt>pt_guarded_by(l)</tt></a></li>
|
||||
<li><a href="#ts_acquiredbefore"><tt>acquired_before(...)</tt></a></li>
|
||||
<li><a href="#ts_acquiredafter"><tt>acquired_after(...)</tt></a></li>
|
||||
<li><a href="#ts_elf"><tt>exclusive_lock_function(...)</tt></a></li>
|
||||
<li><a href="#ts_slf"><tt>shared_lock_function(...)</tt></a></li>
|
||||
<li><a href="#ts_etf"><tt>exclusive_trylock_function(...)</tt></a></li>
|
||||
<li><a href="#ts_stf"><tt>shared_trylock_function(...)</tt></a></li>
|
||||
<li><a href="#ts_uf"><tt>unlock_function(...)</tt></a></li>
|
||||
<li><a href="#ts_lr"><tt>lock_returned(l)</tt></a></li>
|
||||
<li><a href="#ts_le"><tt>locks_excluded(...)</tt></a></li>
|
||||
<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>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
@ -267,6 +302,23 @@ and will issue a warning if used in the top-level compilation
|
||||
file. A warning will also be issued if an absolute path
|
||||
is used in the file argument.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3><a name="__has_warning">__has_warning</a></h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This function-like macro takes a string literal that represents a command
|
||||
line option for a warning and returns true if that is a valid warning
|
||||
option.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#if __has_warning("-Wformat")
|
||||
...
|
||||
#endif
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="builtinmacros">Builtin Macros</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@ -416,12 +468,6 @@ noted.</p>
|
||||
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_decltype">C++0x <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>
|
||||
|
||||
<h4 id="cxx_access_control_sfinae">C++0x 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>
|
||||
@ -432,12 +478,30 @@ with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
|
||||
<tt>__has_extension(cxx_alias_templates)</tt> to determine if support for
|
||||
C++0x's alias declarations and alias templates is enabled.</p>
|
||||
|
||||
<h4 id="cxx_alignas">C++0x 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>
|
||||
|
||||
<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>
|
||||
|
||||
<h4 id="cxx_constexpr">C++0x 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>
|
||||
|
||||
<h4 id="cxx_decltype">C++0x <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>
|
||||
|
||||
<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
|
||||
@ -455,11 +519,46 @@ support for delegating constructors is enabled.</p>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<h4 id="cxx_implicit_moves">C++0x 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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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. Clang does not currently implement this feature.</p>
|
||||
|
||||
<h4 id="cxx_noexcept">C++0x 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>
|
||||
|
||||
<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>
|
||||
|
||||
@ -486,6 +585,9 @@ is enabled.</p>
|
||||
<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_rvalue_references">C++0x rvalue references</h4>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
|
||||
@ -505,17 +607,11 @@ compile-time assertions using <tt>static_assert</tt> is enabled.</p>
|
||||
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_variadic_templates">C++0x variadic templates</h4>
|
||||
<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</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>
|
||||
|
||||
<h4 id="cxx_inline_namespaces">C++0x 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>
|
||||
<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>
|
||||
|
||||
@ -523,17 +619,23 @@ inline namespaces is enabled.</p>
|
||||
<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_noexcept">C++0x noexcept</h4>
|
||||
<h4 id="cxx_unicode_literals">C++0x Unicode string literals</h4>
|
||||
<p>Use <tt>__has_feature(cxx_unicode_literals)</tt> to determine if
|
||||
support for Unicode string literals is enabled.</p>
|
||||
|
||||
<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_unrestricted_unions">C++0x unrestricted unions</h4>
|
||||
|
||||
<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</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_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_user_literals">C++0x 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>
|
||||
|
||||
<h4 id="cxx_variadic_templates">C++0x 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>
|
||||
|
||||
@ -541,6 +643,12 @@ strongly typed, scoped enumerations is enabled.</p>
|
||||
C1X standard. As a result, all these features are enabled
|
||||
with the <tt>-std=c1x</tt> option when compiling C code.</p>
|
||||
|
||||
<h4 id="c_alignas">C1X 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>
|
||||
|
||||
<p>Use <tt>__has_feature(c_generic_selections)</tt> or
|
||||
@ -599,6 +707,7 @@ 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>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
@ -648,7 +757,19 @@ related result type. Similarly, the type of the expression
|
||||
<code>init</code> has a related result type and its receiver is known
|
||||
to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code>init</code> had a related result type, the expressions would have had type <code>id</code>, as declared in the method signature.</p>
|
||||
|
||||
<p>To determine whether a method has a related result type, the first
|
||||
<p>A method with a related result type can be declared by using the
|
||||
type <tt>instancetype</tt> as its result type. <tt>instancetype</tt>
|
||||
is a contextual keyword that is only permitted in the result type of
|
||||
an Objective-C method, e.g.</p>
|
||||
|
||||
<pre>
|
||||
@interface A
|
||||
+ (<b>instancetype</b>)constructAnA;
|
||||
@end
|
||||
</pre>
|
||||
|
||||
<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
|
||||
type is compatible with the type of its class and if</p>
|
||||
@ -677,8 +798,11 @@ with the subclass type. For example:</p>
|
||||
|
||||
<p>Related result types only affect the type of a message send or
|
||||
property access via the given method. In all other respects, a method
|
||||
with a related result type is treated the same way as method without a
|
||||
related result type.</p>
|
||||
with a related result type is treated the same way as method that
|
||||
returns <tt>id</tt>.</p>
|
||||
|
||||
<p>Use <tt>__has_feature(objc_instancetype)</tt> to determine whether
|
||||
the <tt>instancetype</tt> contextual keyword is available.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objc_arc">Automatic reference counting </h2>
|
||||
@ -686,6 +810,24 @@ related result type.</p>
|
||||
|
||||
<p>Clang provides support for <a href="AutomaticReferenceCounting.html">automated reference counting</a> in Objective-C, which eliminates the need for manual retain/release/autorelease message sends. There are two feature macros associated with automatic reference counting: <code>__has_feature(objc_arc)</code> indicates the availability of automated reference counting in general, while <code>__has_feature(objc_arc_weak)</code> indicates that automated reference counting also includes support for <code>__weak</code> pointers to Objective-C objects.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objc_fixed_enum">Enumerations with a fixed underlying type</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides support for C++0x enumerations with a fixed
|
||||
underlying type within Objective-C. For example, one can write an
|
||||
enumeration type as:</p>
|
||||
|
||||
<pre>
|
||||
typedef enum : unsigned char { Red, Green, Blue } Color;
|
||||
</pre>
|
||||
|
||||
<p>This specifies that the underlying type, which is used to store the
|
||||
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="overloading-in-c">Function Overloading in C</h2>
|
||||
<!-- ======================================================================= -->
|
||||
@ -786,6 +928,41 @@ caveats to this use of name mangling:</p>
|
||||
|
||||
<p>Query for this feature with __has_extension(attribute_overloadable).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="complex-list-init">Initializer lists for complex numbers in C</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>clang supports an extension which allows the following in C:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <math.h>
|
||||
#include <complex.h>
|
||||
complex float x = { 1.0f, INFINITY }; // Init to (1, Inf)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>This construct is useful because there is no way to separately
|
||||
initialize the real and imaginary parts of a complex variable in
|
||||
standard C, given that clang does not support <code>_Imaginary</code>.
|
||||
(clang also supports the <code>__real__</code> and <code>__imag__</code>
|
||||
extensions from gcc, which help in some cases, but are not usable in
|
||||
static initializers.)
|
||||
|
||||
<p>Note that this extension does not allow eliding the braces; the
|
||||
meaning of the following two lines is different:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
complex float x[] = { { 1.0f, 1.0f } }; // [0] = (1, 1)
|
||||
complex float x[] = { 1.0f, 1.0f }; // [0] = (1, 0), [1] = (1, 0)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>This extension also works in C++ mode, as far as that goes, but does not
|
||||
apply to the C++ <code>std::complex</code>. (In C++11, list
|
||||
initialization allows the same syntax to be used with
|
||||
<code>std::complex</code> with the same meaning.)
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="builtins">Builtin Functions</h2>
|
||||
@ -1087,6 +1264,149 @@ 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="threadsafety">Thread-Safety Annotation Checking</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang supports additional attributes for checking basic locking policies in
|
||||
multithreaded programs.
|
||||
Clang currently parses the following list of attributes, although
|
||||
<b>the implementation for these annotations is currently in development.</b>
|
||||
For more details, see the
|
||||
<a href="http://gcc.gnu.org/wiki/ThreadSafetyAnnotation">GCC implementation</a>.
|
||||
</p>
|
||||
|
||||
<h4 id="ts_noanal">no_thread_safety_analysis</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> on a function
|
||||
declaration to specify that the thread safety analysis should not be run on that
|
||||
function. This attribute provides an escape hatch (e.g. for situations when it
|
||||
is difficult to annotate the locking policy). </p>
|
||||
|
||||
<h4 id="ts_lockable">lockable</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((lockable))</tt> on a class definition to specify
|
||||
that it has a lockable type (e.g. a Mutex class). This annotation is primarily
|
||||
used to check consistency.</p>
|
||||
|
||||
<h4 id="ts_scopedlockable">scoped_lockable</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((scoped_lockable))</tt> on a class definition to
|
||||
specify that it has a "scoped" lockable type. Objects of this type will acquire
|
||||
the lock upon construction and release it upon going out of scope.
|
||||
This annotation is primarily used to check
|
||||
consistency.</p>
|
||||
|
||||
<h4 id="ts_guardedvar">guarded_var</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to
|
||||
specify that the variable must be accessed while holding some lock.</p>
|
||||
|
||||
<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to
|
||||
specify that the pointer must be dereferenced while holding some lock.</p>
|
||||
|
||||
<h4 id="ts_guardedby">guarded_by(l)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((guarded_by(l)))</tt> on a variable declaration to
|
||||
specify that the variable must be accessed while holding lock <tt>l</tt>.</p>
|
||||
|
||||
<h4 id="ts_ptguardedby">pt_guarded_by(l)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((pt_guarded_by(l)))</tt> on a pointer declaration to
|
||||
specify that the pointer must be dereferenced while holding lock <tt>l</tt>.</p>
|
||||
|
||||
<h4 id="ts_acquiredbefore">acquired_before(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((acquired_before(...)))</tt> on a declaration
|
||||
of a lockable variable to specify that the lock must be acquired before all
|
||||
attribute arguments. Arguments must be lockable type, and there must be at
|
||||
least one argument.</p>
|
||||
|
||||
<h4 id="ts_acquiredafter">acquired_after(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((acquired_after(...)))</tt> on a declaration
|
||||
of a lockable variable to specify that the lock must be acquired after all
|
||||
attribute arguments. Arguments must be lockable type, and there must be at
|
||||
least one argument.</p>
|
||||
|
||||
<h4 id="ts_elf">exclusive_lock_function(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> on a function
|
||||
declaration to specify that the function acquires all listed locks
|
||||
exclusively. This attribute takes zero or more arguments: either of lockable
|
||||
type or integers indexing into function parameters of lockable type. If no
|
||||
arguments are given, the acquired lock is implicitly <tt>this</tt> of the
|
||||
enclosing object.</p>
|
||||
|
||||
<h4 id="ts_slf">shared_lock_function(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> on a function
|
||||
declaration to specify that the function acquires all listed locks, although
|
||||
the locks may be shared (e.g. read locks). This attribute takes zero or more
|
||||
arguments: either of lockable type or integers indexing into function
|
||||
parameters of lockable type. If no arguments are given, the acquired lock is
|
||||
implicitly <tt>this</tt> of the enclosing object.</p>
|
||||
|
||||
<h4 id="ts_etf">exclusive_trylock_function(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> on a function
|
||||
declaration to specify that the function will try (without blocking) to acquire
|
||||
all listed locks exclusively. This attribute takes one or more arguments. The
|
||||
first argument is an integer or boolean value specifying the return value of a
|
||||
successful lock acquisition. The remaining arugments are either of lockable type
|
||||
or integers indexing into function parameters of lockable type. If only one
|
||||
argument is given, the acquired lock is implicitly <tt>this</tt> of the
|
||||
enclosing object.</p>
|
||||
|
||||
<h4 id="ts_stf">shared_trylock_function(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> on a function
|
||||
declaration to specify that the function will try (without blocking) to acquire
|
||||
all listed locks, although the locks may be shared (e.g. read locks). This
|
||||
attribute takes one or more arguments. The first argument is an integer or
|
||||
boolean value specifying the return value of a successful lock acquisition. The
|
||||
remaining arugments are either of lockable type or integers indexing into
|
||||
function parameters of lockable type. If only one argument is given, the
|
||||
acquired lock is implicitly <tt>this</tt> of the enclosing object.</p>
|
||||
|
||||
<h4 id="ts_uf">unlock_function(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((unlock_function(...)))</tt> on a function
|
||||
declaration to specify that the function release all listed locks. This
|
||||
attribute takes zero or more arguments: either of lockable type or integers
|
||||
indexing into function parameters of lockable type. If no arguments are given,
|
||||
the acquired lock is implicitly <tt>this</tt> of the enclosing object.</p>
|
||||
|
||||
<h4 id="ts_lr">lock_returned(l)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((lock_returned(l)))</tt> on a function
|
||||
declaration to specify that the function returns lock <tt>l</tt> (<tt>l</tt>
|
||||
must be of lockable type). This annotation is used to aid in resolving lock
|
||||
expressions.</p>
|
||||
|
||||
<h4 id="ts_le">locks_excluded(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((locks_excluded(...)))</tt> on a function declaration
|
||||
to specify that the function must not be called with the listed locks. Arguments
|
||||
must be lockable type, and there must be at least one argument.</p>
|
||||
|
||||
<h4 id="ts_elr">exclusive_locks_required(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((exclusive_locks_required(...)))</tt> on a function
|
||||
declaration to specify that the function must be called while holding the listed
|
||||
exclusive locks. Arguments must be lockable type, and there must be at
|
||||
least one argument.</p>
|
||||
|
||||
<h4 id="ts_slr">shared_locks_required(...)</h4>
|
||||
|
||||
<p>Use <tt>__attribute__((shared_locks_required(...)))</tt> on a function
|
||||
declaration to specify that the function must be called while holding the listed
|
||||
shared locks. Arguments must be lockable type, and there must be at
|
||||
least one argument.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -39,6 +39,7 @@ td {
|
||||
<li><a href="#diagnostics_categories">Diagnostic Categories</a></li>
|
||||
<li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li>
|
||||
<li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
|
||||
<li><a href="#diagnostics_enable_everything">Enabling All Warnings</a></li>
|
||||
<li><a href="#analyzer_diagnositics">Controlling Static Analyzer Diagnostics</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@ -626,6 +627,16 @@ GCC do not support the exact same set of warnings, so even when using GCC
|
||||
compatible #pragmas there is no guarantee that they will have identical behaviour
|
||||
on both compilers. </p>
|
||||
|
||||
<h4 id="diagnostics_enable_everything">Enabling All Warnings</h4>
|
||||
|
||||
<p>In addition to the traditional <tt>-W</tt> flags, one can enable <b>all</b>
|
||||
warnings by passing <tt>-Weverything</tt>.
|
||||
This works as expected with <tt>-Werror</tt>,
|
||||
and also includes the warnings from <tt>-pedantic</tt>.</p>
|
||||
|
||||
<p>Note that when combined with <tt>-w</tt> (which disables all warnings), that
|
||||
flag wins.</p>
|
||||
|
||||
<h4 id="analyzer_diagnositics">Controlling Static Analyzer Diagnostics</h4>
|
||||
|
||||
<p>While not strictly part of the compiler, the diagnostics from Clang's <a
|
||||
@ -1059,18 +1070,28 @@ Clang assumes directories as below;</p>
|
||||
|
||||
<h5>MinGW-w64</h5>
|
||||
|
||||
<p>For x32(i686-w64-mingw32), it is not supported yet.</p>
|
||||
|
||||
<p>For x64(x86_64-w64-mingw32), <a href="http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20110321/118499.html">an essential patch(LLVM's r128206)</a> would be needed. It is incompatible to <a href="http://tdm-gcc.tdragon.net/development">TDM-GCC</a> due to the definition of symbol "<code>___chkstk</code>". Clang assumes as below;<p>
|
||||
<p>For 32-bit (i686-w64-mingw32), and 64-bit (x86_64-w64-mingw32), Clang assumes as below;<p>
|
||||
|
||||
<ul>
|
||||
<li><tt>C:/mingw/x86_64-w64-mingw32/include</tt></li>
|
||||
<li><tt>C:/mingw/x86_64-w64-mingw32/include/c++/4.5.[23]</tt></li>
|
||||
<li>GCC driver "gcc.exe" to build x86_64-w64-mingw32 binary.</li>
|
||||
<li><tt>GCC versions 4.5.0 to 4.5.3, 4.6.0 to 4.6.2, or 4.7.0 (for the C++ header search path)</tt></li>
|
||||
<li><tt>some_directory/bin/gcc.exe</tt></li>
|
||||
<li><tt>some_directory/bin/clang.exe</tt></li>
|
||||
<li><tt>some_directory/bin/clang++.exe</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version/x86_64-w64-mingw32</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version/i686-w64-mingw32</tt></li>
|
||||
<li><tt>some_directory/bin/../include/c++/GCC_version/backward</tt></li>
|
||||
<li><tt>some_directory/bin/../x86_64-w64-mingw32/include</tt></li>
|
||||
<li><tt>some_directory/bin/../i686-w64-mingw32/include</tt></li>
|
||||
<li><tt>some_directory/bin/../include</tt></li>
|
||||
</ul>
|
||||
|
||||
<p><a href="http://llvm.org/bugs/show_bug.cgi?id=8833">Some tests might fail</a>
|
||||
on x64.</p>
|
||||
<p>This directory layout is standard for any toolchain you will find on the official <a href="mingw-w64.sourceforge.net">MinGW-w64 website</a>.
|
||||
|
||||
<p>Clang expects the GCC executable "gcc.exe" compiled for i686-w64-mingw32 (or x86_64-w64-mingw32) to be present on PATH.</p>
|
||||
|
||||
<p><a href="http://llvm.org/bugs/show_bug.cgi?id=9072">Some tests might fail</a>
|
||||
on x86_64-w64-mingw32.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
@ -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 = NO
|
||||
CREATE_SUBDIRS = YES
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
|
@ -370,9 +370,39 @@ H2 {
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
H2, H3 {
|
||||
border-bottom: 2px solid;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
A.qindex {}
|
||||
A.qindexRef {}
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code { text-decoration: none; font-weight: normal; color: #4444ee }
|
||||
A.codeRef { font-weight: normal; color: #4444ee }
|
||||
|
||||
div.memitem {
|
||||
border: 1px solid #999999;
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 1.0em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-webkit-box-shadow: 3px 3px 6px #777777;
|
||||
-moz-border-radius: 0.5em;
|
||||
-moz-box-shadow: black 3px 3px 3px;
|
||||
}
|
||||
|
||||
div.memproto {
|
||||
background-color: #E3E4E5;
|
||||
padding: 0.25em 0.5em;
|
||||
-webkit-border-top-left-radius: 0.5em;
|
||||
-webkit-border-top-right-radius: 0.5em;
|
||||
-moz-border-radius-topleft: 0.5em;
|
||||
-moz-border-radius-topright: 0.5em;
|
||||
}
|
||||
|
||||
div.memdoc {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
@ -459,7 +459,13 @@ Add the specified directory to the search path for framework include files.
|
||||
|
||||
=item B<-nostdinc>
|
||||
|
||||
Do not search the standard system directories for include files.
|
||||
Do not search the standard system directories or compiler builtin directories
|
||||
for include files.
|
||||
|
||||
=item B<-nostdlibinc>
|
||||
|
||||
Do not search the standard system directories for include files, but do search
|
||||
compiler builting include directories.
|
||||
|
||||
=item B<-nobuiltininc>
|
||||
|
||||
|
@ -45,9 +45,9 @@ class PrintFunctionNamesAction : public PluginASTAction {
|
||||
|
||||
// Example error handling.
|
||||
if (args[i] == "-an-error") {
|
||||
Diagnostic &D = CI.getDiagnostics();
|
||||
DiagnosticsEngine &D = CI.getDiagnostics();
|
||||
unsigned DiagID = D.getCustomDiagID(
|
||||
Diagnostic::Error, "invalid argument '" + args[i] + "'");
|
||||
DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
|
||||
D.Report(DiagID);
|
||||
return false;
|
||||
}
|
||||
|
14
examples/analyzer-plugin/CMakeLists.txt
Normal file
14
examples/analyzer-plugin/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
set(MODULE TRUE)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangStaticAnalyzerCore
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(SampleAnalyzerPlugin SampleAnalyzerPlugin)
|
||||
|
||||
set_target_properties(SampleAnalyzerPlugin
|
||||
PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
PREFIX "")
|
52
examples/analyzer-plugin/MainCallChecker.cpp
Normal file
52
examples/analyzer-plugin/MainCallChecker.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class MainCallChecker : public Checker < check::PreStmt<CallExpr> > {
|
||||
mutable llvm::OwningPtr<BugType> BT;
|
||||
|
||||
public:
|
||||
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
|
||||
const ProgramState *state = C.getState();
|
||||
const Expr *Callee = CE->getCallee();
|
||||
const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
|
||||
|
||||
if (!FD)
|
||||
return;
|
||||
|
||||
// Get the name of the callee.
|
||||
IdentifierInfo *II = FD->getIdentifier();
|
||||
if (!II) // if no identifier, not a simple C function
|
||||
return;
|
||||
|
||||
if (II->isStr("main")) {
|
||||
ExplodedNode *N = C.generateSink();
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
if (!BT)
|
||||
BT.reset(new BugType("call to main", "example analyzer plugin"));
|
||||
|
||||
BugReport *report = new BugReport(*BT, BT->getName(), N);
|
||||
report->addRange(Callee->getSourceRange());
|
||||
C.EmitReport(report);
|
||||
}
|
||||
}
|
||||
|
||||
// Register plugin!
|
||||
extern "C"
|
||||
void clang_registerCheckers (CheckerRegistry ®istry) {
|
||||
registry.addChecker<MainCallChecker>("example.MainCallChecker", "Disallows calls to functions called main");
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char clang_analyzerAPIVersionString[] = CLANG_ANALYZER_API_VERSION_STRING;
|
20
examples/analyzer-plugin/Makefile
Normal file
20
examples/analyzer-plugin/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
##===- examples/analyzer-plugin/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 := ../..
|
||||
LIBRARYNAME = SampleAnalyzerPlugin
|
||||
|
||||
LINK_LIBS_IN_SHARED = 0
|
||||
SHARED_LIBRARY = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
LDFLAGS=-Wl,-undefined,dynamic_lookup
|
||||
endif
|
@ -22,12 +22,13 @@
|
||||
#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"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Target/TargetSelect.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
using namespace clang;
|
||||
using namespace clang::driver;
|
||||
|
||||
@ -74,10 +75,9 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
|
||||
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
Diagnostic Diags(DiagID, DiagClient);
|
||||
DiagnosticsEngine Diags(DiagID, DiagClient);
|
||||
Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
|
||||
"a.out", /*IsProduction=*/false, /*CXXIsProduction=*/false,
|
||||
Diags);
|
||||
"a.out", /*IsProduction=*/false, Diags);
|
||||
TheDriver.setTitle("clang interpreter");
|
||||
|
||||
// FIXME: This is a hack to try to force the driver to do something we can
|
||||
|
@ -115,7 +115,12 @@ enum CXAvailabilityKind {
|
||||
/**
|
||||
* \brief The entity is not available; any use of it will be an error.
|
||||
*/
|
||||
CXAvailability_NotAvailable
|
||||
CXAvailability_NotAvailable,
|
||||
/**
|
||||
* \brief The entity is available, but not accessible; any use of it will be
|
||||
* an error.
|
||||
*/
|
||||
CXAvailability_NotAccessible
|
||||
};
|
||||
|
||||
/**
|
||||
@ -263,7 +268,7 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
|
||||
* \brief Identifies a specific source location within a translation
|
||||
* unit.
|
||||
*
|
||||
* Use clang_getInstantiationLocation() or clang_getSpellingLocation()
|
||||
* Use clang_getExpansionLocation() or clang_getSpellingLocation()
|
||||
* to map a source location to a particular file, line, and column.
|
||||
*/
|
||||
typedef struct {
|
||||
@ -327,12 +332,25 @@ CINDEX_LINKAGE CXSourceRange clang_getNullRange();
|
||||
CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin,
|
||||
CXSourceLocation end);
|
||||
|
||||
/**
|
||||
* \brief Determine whether two ranges are equivalent.
|
||||
*
|
||||
* \returns non-zero if the ranges are the same, zero if they differ.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_equalRanges(CXSourceRange range1,
|
||||
CXSourceRange range2);
|
||||
|
||||
/**
|
||||
* \brief Returns non-zero if \arg range is null.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the file, line, column, and offset represented by
|
||||
* the given source location.
|
||||
*
|
||||
* If the location refers into a macro instantiation, retrieves the
|
||||
* location of the macro instantiation.
|
||||
* If the location refers into a macro expansion, retrieves the
|
||||
* location of the macro expansion.
|
||||
*
|
||||
* \param location the location within a source file that will be decomposed
|
||||
* into its parts.
|
||||
@ -349,6 +367,63 @@ CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin,
|
||||
* \param offset [out] if non-NULL, will be set to the offset into the
|
||||
* buffer to which the given source location points.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location,
|
||||
CXFile *file,
|
||||
unsigned *line,
|
||||
unsigned *column,
|
||||
unsigned *offset);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the file, line, column, and offset represented by
|
||||
* the given source location, as specified in a # line directive.
|
||||
*
|
||||
* Example: given the following source code in a file somefile.c
|
||||
*
|
||||
* #123 "dummy.c" 1
|
||||
*
|
||||
* static int func(void)
|
||||
* {
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* the location information returned by this function would be
|
||||
*
|
||||
* File: dummy.c Line: 124 Column: 12
|
||||
*
|
||||
* whereas clang_getExpansionLocation would have returned
|
||||
*
|
||||
* File: somefile.c Line: 3 Column: 12
|
||||
*
|
||||
* \param location the location within a source file that will be decomposed
|
||||
* into its parts.
|
||||
*
|
||||
* \param filename [out] if non-NULL, will be set to the filename of the
|
||||
* source location. Note that filenames returned will be for "virtual" files,
|
||||
* which don't necessarily exist on the machine running clang - e.g. when
|
||||
* parsing preprocessed output obtained from a different environment. If
|
||||
* a non-NULL value is passed in, remember to dispose of the returned value
|
||||
* using \c clang_disposeString() once you've finished with it. For an invalid
|
||||
* source location, an empty string is returned.
|
||||
*
|
||||
* \param line [out] if non-NULL, will be set to the line number of the
|
||||
* source location. For an invalid source location, zero is returned.
|
||||
*
|
||||
* \param column [out] if non-NULL, will be set to the column number of the
|
||||
* source location. For an invalid source location, zero is returned.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_getPresumedLocation(CXSourceLocation location,
|
||||
CXString *filename,
|
||||
unsigned *line,
|
||||
unsigned *column);
|
||||
|
||||
/**
|
||||
* \brief Legacy API to retrieve the file, line, column, and offset represented
|
||||
* by the given source location.
|
||||
*
|
||||
* This interface has been replaced by the newer interface
|
||||
* \see clang_getExpansionLocation(). See that interface's documentation for
|
||||
* details.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location,
|
||||
CXFile *file,
|
||||
unsigned *line,
|
||||
@ -816,18 +891,18 @@ enum CXTranslationUnit_Flags {
|
||||
*/
|
||||
CXTranslationUnit_CacheCompletionResults = 0x08,
|
||||
/**
|
||||
* \brief Enable precompiled preambles in C++.
|
||||
* \brief DEPRECATED: Enable precompiled preambles in C++.
|
||||
*
|
||||
* Note: this is a *temporary* option that is available only while
|
||||
* we are testing C++ precompiled preamble support.
|
||||
* we are testing C++ precompiled preamble support. It is deprecated.
|
||||
*/
|
||||
CXTranslationUnit_CXXPrecompiledPreamble = 0x10,
|
||||
|
||||
/**
|
||||
* \brief Enabled chained precompiled preambles in C++.
|
||||
* \brief DEPRECATED: Enabled chained precompiled preambles in C++.
|
||||
*
|
||||
* Note: this is a *temporary* option that is available only while
|
||||
* we are testing C++ precompiled preamble support.
|
||||
* we are testing C++ precompiled preamble support. It is deprecated.
|
||||
*/
|
||||
CXTranslationUnit_CXXChainedPCH = 0x20,
|
||||
|
||||
@ -1094,12 +1169,14 @@ enum CXTUResourceUsageKind {
|
||||
CXTUResourceUsage_ExternalASTSource_Membuffer_MMap = 10,
|
||||
CXTUResourceUsage_Preprocessor = 11,
|
||||
CXTUResourceUsage_PreprocessingRecord = 12,
|
||||
CXTUResourceUsage_SourceManager_DataStructures = 13,
|
||||
CXTUResourceUsage_Preprocessor_HeaderSearch = 14,
|
||||
CXTUResourceUsage_MEMORY_IN_BYTES_BEGIN = CXTUResourceUsage_AST,
|
||||
CXTUResourceUsage_MEMORY_IN_BYTES_END =
|
||||
CXTUResourceUsage_PreprocessingRecord,
|
||||
CXTUResourceUsage_Preprocessor_HeaderSearch,
|
||||
|
||||
CXTUResourceUsage_First = CXTUResourceUsage_AST,
|
||||
CXTUResourceUsage_Last = CXTUResourceUsage_PreprocessingRecord
|
||||
CXTUResourceUsage_Last = CXTUResourceUsage_Preprocessor_HeaderSearch
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1237,8 +1314,11 @@ enum CXCursorKind {
|
||||
CXCursor_ObjCSynthesizeDecl = 37,
|
||||
/** \brief An Objective-C @dynamic definition. */
|
||||
CXCursor_ObjCDynamicDecl = 38,
|
||||
/** \brief An access specifier. */
|
||||
CXCursor_CXXAccessSpecifier = 39,
|
||||
|
||||
CXCursor_FirstDecl = CXCursor_UnexposedDecl,
|
||||
CXCursor_LastDecl = CXCursor_ObjCDynamicDecl,
|
||||
CXCursor_LastDecl = CXCursor_CXXAccessSpecifier,
|
||||
|
||||
/* References */
|
||||
CXCursor_FirstRef = 40, /* Decl references */
|
||||
@ -1377,7 +1457,207 @@ enum CXCursorKind {
|
||||
/** \brief An expression that represents a block literal. */
|
||||
CXCursor_BlockExpr = 105,
|
||||
|
||||
CXCursor_LastExpr = 105,
|
||||
/** \brief An integer literal.
|
||||
*/
|
||||
CXCursor_IntegerLiteral = 106,
|
||||
|
||||
/** \brief A floating point number literal.
|
||||
*/
|
||||
CXCursor_FloatingLiteral = 107,
|
||||
|
||||
/** \brief An imaginary number literal.
|
||||
*/
|
||||
CXCursor_ImaginaryLiteral = 108,
|
||||
|
||||
/** \brief A string literal.
|
||||
*/
|
||||
CXCursor_StringLiteral = 109,
|
||||
|
||||
/** \brief A character literal.
|
||||
*/
|
||||
CXCursor_CharacterLiteral = 110,
|
||||
|
||||
/** \brief A parenthesized expression, e.g. "(1)".
|
||||
*
|
||||
* This AST node is only formed if full location information is requested.
|
||||
*/
|
||||
CXCursor_ParenExpr = 111,
|
||||
|
||||
/** \brief This represents the unary-expression's (except sizeof and
|
||||
* alignof).
|
||||
*/
|
||||
CXCursor_UnaryOperator = 112,
|
||||
|
||||
/** \brief [C99 6.5.2.1] Array Subscripting.
|
||||
*/
|
||||
CXCursor_ArraySubscriptExpr = 113,
|
||||
|
||||
/** \brief A builtin binary operation expression such as "x + y" or
|
||||
* "x <= y".
|
||||
*/
|
||||
CXCursor_BinaryOperator = 114,
|
||||
|
||||
/** \brief Compound assignment such as "+=".
|
||||
*/
|
||||
CXCursor_CompoundAssignOperator = 115,
|
||||
|
||||
/** \brief The ?: ternary operator.
|
||||
*/
|
||||
CXCursor_ConditionalOperator = 116,
|
||||
|
||||
/** \brief An explicit cast in C (C99 6.5.4) or a C-style cast in C++
|
||||
* (C++ [expr.cast]), which uses the syntax (Type)expr.
|
||||
*
|
||||
* For example: (int)f.
|
||||
*/
|
||||
CXCursor_CStyleCastExpr = 117,
|
||||
|
||||
/** \brief [C99 6.5.2.5]
|
||||
*/
|
||||
CXCursor_CompoundLiteralExpr = 118,
|
||||
|
||||
/** \brief Describes an C or C++ initializer list.
|
||||
*/
|
||||
CXCursor_InitListExpr = 119,
|
||||
|
||||
/** \brief The GNU address of label extension, representing &&label.
|
||||
*/
|
||||
CXCursor_AddrLabelExpr = 120,
|
||||
|
||||
/** \brief This is the GNU Statement Expression extension: ({int X=4; X;})
|
||||
*/
|
||||
CXCursor_StmtExpr = 121,
|
||||
|
||||
/** \brief Represents a C1X generic selection.
|
||||
*/
|
||||
CXCursor_GenericSelectionExpr = 122,
|
||||
|
||||
/** \brief Implements the GNU __null extension, which is a name for a null
|
||||
* pointer constant that has integral type (e.g., int or long) and is the same
|
||||
* size and alignment as a pointer.
|
||||
*
|
||||
* The __null extension is typically only used by system headers, which define
|
||||
* NULL as __null in C++ rather than using 0 (which is an integer that may not
|
||||
* match the size of a pointer).
|
||||
*/
|
||||
CXCursor_GNUNullExpr = 123,
|
||||
|
||||
/** \brief C++'s static_cast<> expression.
|
||||
*/
|
||||
CXCursor_CXXStaticCastExpr = 124,
|
||||
|
||||
/** \brief C++'s dynamic_cast<> expression.
|
||||
*/
|
||||
CXCursor_CXXDynamicCastExpr = 125,
|
||||
|
||||
/** \brief C++'s reinterpret_cast<> expression.
|
||||
*/
|
||||
CXCursor_CXXReinterpretCastExpr = 126,
|
||||
|
||||
/** \brief C++'s const_cast<> expression.
|
||||
*/
|
||||
CXCursor_CXXConstCastExpr = 127,
|
||||
|
||||
/** \brief Represents an explicit C++ type conversion that uses "functional"
|
||||
* notion (C++ [expr.type.conv]).
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* x = int(0.5);
|
||||
* \endcode
|
||||
*/
|
||||
CXCursor_CXXFunctionalCastExpr = 128,
|
||||
|
||||
/** \brief A C++ typeid expression (C++ [expr.typeid]).
|
||||
*/
|
||||
CXCursor_CXXTypeidExpr = 129,
|
||||
|
||||
/** \brief [C++ 2.13.5] C++ Boolean Literal.
|
||||
*/
|
||||
CXCursor_CXXBoolLiteralExpr = 130,
|
||||
|
||||
/** \brief [C++0x 2.14.7] C++ Pointer Literal.
|
||||
*/
|
||||
CXCursor_CXXNullPtrLiteralExpr = 131,
|
||||
|
||||
/** \brief Represents the "this" expression in C++
|
||||
*/
|
||||
CXCursor_CXXThisExpr = 132,
|
||||
|
||||
/** \brief [C++ 15] C++ Throw Expression.
|
||||
*
|
||||
* This handles 'throw' and 'throw' assignment-expression. When
|
||||
* assignment-expression isn't present, Op will be null.
|
||||
*/
|
||||
CXCursor_CXXThrowExpr = 133,
|
||||
|
||||
/** \brief A new expression for memory allocation and constructor calls, e.g:
|
||||
* "new CXXNewExpr(foo)".
|
||||
*/
|
||||
CXCursor_CXXNewExpr = 134,
|
||||
|
||||
/** \brief A delete expression for memory deallocation and destructor calls,
|
||||
* e.g. "delete[] pArray".
|
||||
*/
|
||||
CXCursor_CXXDeleteExpr = 135,
|
||||
|
||||
/** \brief A unary expression.
|
||||
*/
|
||||
CXCursor_UnaryExpr = 136,
|
||||
|
||||
/** \brief ObjCStringLiteral, used for Objective-C string literals i.e. "foo".
|
||||
*/
|
||||
CXCursor_ObjCStringLiteral = 137,
|
||||
|
||||
/** \brief ObjCEncodeExpr, used for in Objective-C.
|
||||
*/
|
||||
CXCursor_ObjCEncodeExpr = 138,
|
||||
|
||||
/** \brief ObjCSelectorExpr used for in Objective-C.
|
||||
*/
|
||||
CXCursor_ObjCSelectorExpr = 139,
|
||||
|
||||
/** \brief Objective-C's protocol expression.
|
||||
*/
|
||||
CXCursor_ObjCProtocolExpr = 140,
|
||||
|
||||
/** \brief An Objective-C "bridged" cast expression, which casts between
|
||||
* Objective-C pointers and C pointers, transferring ownership in the process.
|
||||
*
|
||||
* \code
|
||||
* NSString *str = (__bridge_transfer NSString *)CFCreateString();
|
||||
* \endcode
|
||||
*/
|
||||
CXCursor_ObjCBridgedCastExpr = 141,
|
||||
|
||||
/** \brief Represents a C++0x pack expansion that produces a sequence of
|
||||
* expressions.
|
||||
*
|
||||
* A pack expansion expression contains a pattern (which itself is an
|
||||
* expression) followed by an ellipsis. For example:
|
||||
*
|
||||
* \code
|
||||
* template<typename F, typename ...Types>
|
||||
* void forward(F f, Types &&...args) {
|
||||
* f(static_cast<Types&&>(args)...);
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
CXCursor_PackExpansionExpr = 142,
|
||||
|
||||
/** \brief Represents an expression that computes the length of a parameter
|
||||
* pack.
|
||||
*
|
||||
* \code
|
||||
* template<typename ...Types>
|
||||
* struct count {
|
||||
* static const unsigned value = sizeof...(Types);
|
||||
* };
|
||||
* \endcode
|
||||
*/
|
||||
CXCursor_SizeOfPackExpr = 143,
|
||||
|
||||
CXCursor_LastExpr = CXCursor_SizeOfPackExpr,
|
||||
|
||||
/* Statements */
|
||||
CXCursor_FirstStmt = 200,
|
||||
@ -1404,8 +1684,130 @@ enum CXCursorKind {
|
||||
*
|
||||
*/
|
||||
CXCursor_LabelStmt = 201,
|
||||
|
||||
CXCursor_LastStmt = CXCursor_LabelStmt,
|
||||
|
||||
/** \brief A group of statements like { stmt stmt }.
|
||||
*
|
||||
* This cursor kind is used to describe compound statements, e.g. function
|
||||
* bodies.
|
||||
*/
|
||||
CXCursor_CompoundStmt = 202,
|
||||
|
||||
/** \brief A case statment.
|
||||
*/
|
||||
CXCursor_CaseStmt = 203,
|
||||
|
||||
/** \brief A default statement.
|
||||
*/
|
||||
CXCursor_DefaultStmt = 204,
|
||||
|
||||
/** \brief An if statement
|
||||
*/
|
||||
CXCursor_IfStmt = 205,
|
||||
|
||||
/** \brief A switch statement.
|
||||
*/
|
||||
CXCursor_SwitchStmt = 206,
|
||||
|
||||
/** \brief A while statement.
|
||||
*/
|
||||
CXCursor_WhileStmt = 207,
|
||||
|
||||
/** \brief A do statement.
|
||||
*/
|
||||
CXCursor_DoStmt = 208,
|
||||
|
||||
/** \brief A for statement.
|
||||
*/
|
||||
CXCursor_ForStmt = 209,
|
||||
|
||||
/** \brief A goto statement.
|
||||
*/
|
||||
CXCursor_GotoStmt = 210,
|
||||
|
||||
/** \brief An indirect goto statement.
|
||||
*/
|
||||
CXCursor_IndirectGotoStmt = 211,
|
||||
|
||||
/** \brief A continue statement.
|
||||
*/
|
||||
CXCursor_ContinueStmt = 212,
|
||||
|
||||
/** \brief A break statement.
|
||||
*/
|
||||
CXCursor_BreakStmt = 213,
|
||||
|
||||
/** \brief A return statement.
|
||||
*/
|
||||
CXCursor_ReturnStmt = 214,
|
||||
|
||||
/** \brief A GNU inline assembly statement extension.
|
||||
*/
|
||||
CXCursor_AsmStmt = 215,
|
||||
|
||||
/** \brief Objective-C's overall @try-@catc-@finall statement.
|
||||
*/
|
||||
CXCursor_ObjCAtTryStmt = 216,
|
||||
|
||||
/** \brief Objective-C's @catch statement.
|
||||
*/
|
||||
CXCursor_ObjCAtCatchStmt = 217,
|
||||
|
||||
/** \brief Objective-C's @finally statement.
|
||||
*/
|
||||
CXCursor_ObjCAtFinallyStmt = 218,
|
||||
|
||||
/** \brief Objective-C's @throw statement.
|
||||
*/
|
||||
CXCursor_ObjCAtThrowStmt = 219,
|
||||
|
||||
/** \brief Objective-C's @synchronized statement.
|
||||
*/
|
||||
CXCursor_ObjCAtSynchronizedStmt = 220,
|
||||
|
||||
/** \brief Objective-C's autorelease pool statement.
|
||||
*/
|
||||
CXCursor_ObjCAutoreleasePoolStmt = 221,
|
||||
|
||||
/** \brief Objective-C's collection statement.
|
||||
*/
|
||||
CXCursor_ObjCForCollectionStmt = 222,
|
||||
|
||||
/** \brief C++'s catch statement.
|
||||
*/
|
||||
CXCursor_CXXCatchStmt = 223,
|
||||
|
||||
/** \brief C++'s try statement.
|
||||
*/
|
||||
CXCursor_CXXTryStmt = 224,
|
||||
|
||||
/** \brief C++'s for (* : *) statement.
|
||||
*/
|
||||
CXCursor_CXXForRangeStmt = 225,
|
||||
|
||||
/** \brief Windows Structured Exception Handling's try statement.
|
||||
*/
|
||||
CXCursor_SEHTryStmt = 226,
|
||||
|
||||
/** \brief Windows Structured Exception Handling's except statement.
|
||||
*/
|
||||
CXCursor_SEHExceptStmt = 227,
|
||||
|
||||
/** \brief Windows Structured Exception Handling's finally statement.
|
||||
*/
|
||||
CXCursor_SEHFinallyStmt = 228,
|
||||
|
||||
/** \brief The null satement ";": C99 6.8.3p3.
|
||||
*
|
||||
* This cursor kind is used to describe the null statement.
|
||||
*/
|
||||
CXCursor_NullStmt = 230,
|
||||
|
||||
/** \brief Adaptor class for mixing declarations with statements and
|
||||
* expressions.
|
||||
*/
|
||||
CXCursor_DeclStmt = 231,
|
||||
|
||||
CXCursor_LastStmt = CXCursor_DeclStmt,
|
||||
|
||||
/**
|
||||
* \brief Cursor that represents the translation unit itself.
|
||||
@ -1426,7 +1828,10 @@ enum CXCursorKind {
|
||||
CXCursor_IBActionAttr = 401,
|
||||
CXCursor_IBOutletAttr = 402,
|
||||
CXCursor_IBOutletCollectionAttr = 403,
|
||||
CXCursor_LastAttr = CXCursor_IBOutletCollectionAttr,
|
||||
CXCursor_CXXFinalAttr = 404,
|
||||
CXCursor_CXXOverrideAttr = 405,
|
||||
CXCursor_AnnotateAttr = 406,
|
||||
CXCursor_LastAttr = CXCursor_AnnotateAttr,
|
||||
|
||||
/* Preprocessing */
|
||||
CXCursor_PreprocessingDirective = 500,
|
||||
@ -1458,6 +1863,7 @@ enum CXCursorKind {
|
||||
*/
|
||||
typedef struct {
|
||||
enum CXCursorKind kind;
|
||||
int xdata;
|
||||
void *data[3];
|
||||
} CXCursor;
|
||||
|
||||
@ -1485,6 +1891,11 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Returns non-zero if \arg cursor is null.
|
||||
*/
|
||||
int clang_Cursor_isNull(CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Compute a hash value for the given cursor.
|
||||
*/
|
||||
@ -1600,6 +2011,11 @@ CINDEX_LINKAGE enum CXLanguageKind {
|
||||
*/
|
||||
CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Returns the translation unit that a cursor originated from.
|
||||
*/
|
||||
CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor);
|
||||
|
||||
|
||||
/**
|
||||
* \brief A fast container representing a set of CXCursors.
|
||||
@ -1886,7 +2302,8 @@ enum CXTypeKind {
|
||||
CXType_ObjCInterface = 108,
|
||||
CXType_ObjCObjectPointer = 109,
|
||||
CXType_FunctionNoProto = 110,
|
||||
CXType_FunctionProto = 111
|
||||
CXType_FunctionProto = 111,
|
||||
CXType_ConstantArray = 112
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1977,6 +2394,20 @@ CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_isPODType(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Return the element type of an array type.
|
||||
*
|
||||
* If a non-array type is passed in, an invalid type is returned.
|
||||
*/
|
||||
CINDEX_LINKAGE CXType clang_getArrayElementType(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Return the the array size of a constant array.
|
||||
*
|
||||
* If a non-array type is passed in, -1 is returned.
|
||||
*/
|
||||
CINDEX_LINKAGE long long clang_getArraySize(CXType T);
|
||||
|
||||
/**
|
||||
* \brief Returns 1 if the base class specified by the cursor with kind
|
||||
* CX_CXXBaseSpecifier is virtual.
|
||||
@ -1996,7 +2427,8 @@ enum CX_CXXAccessSpecifier {
|
||||
|
||||
/**
|
||||
* \brief Returns the access control level for the C++ base specifier
|
||||
* represented by a cursor with kind CX_CXXBaseSpecifier.
|
||||
* represented by a cursor with kind CXCursor_CXXBaseSpecifier or
|
||||
* CXCursor_AccessSpecifier.
|
||||
*/
|
||||
CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor);
|
||||
|
||||
@ -2377,6 +2809,54 @@ CINDEX_LINKAGE enum CXCursorKind clang_getTemplateCursorKind(CXCursor C);
|
||||
* from which it was instantiated. Otherwise, returns a NULL cursor.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getSpecializedCursorTemplate(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Given a cursor that references something else, return the source range
|
||||
* covering that reference.
|
||||
*
|
||||
* \param C A cursor pointing to a member reference, a declaration reference, or
|
||||
* an operator call.
|
||||
* \param NameFlags A bitset with three independent flags:
|
||||
* CXNameRange_WantQualifier, CXNameRange_WantTemplateArgs, and
|
||||
* CXNameRange_WantSinglePiece.
|
||||
* \param PieceIndex For contiguous names or when passing the flag
|
||||
* CXNameRange_WantSinglePiece, only one piece with index 0 is
|
||||
* available. When the CXNameRange_WantSinglePiece flag is not passed for a
|
||||
* non-contiguous names, this index can be used to retreive the individual
|
||||
* pieces of the name. See also CXNameRange_WantSinglePiece.
|
||||
*
|
||||
* \returns The piece of the name pointed to by the given cursor. If there is no
|
||||
* name, or if the PieceIndex is out-of-range, a null-cursor will be returned.
|
||||
*/
|
||||
CINDEX_LINKAGE CXSourceRange clang_getCursorReferenceNameRange(CXCursor C,
|
||||
unsigned NameFlags,
|
||||
unsigned PieceIndex);
|
||||
|
||||
enum CXNameRefFlags {
|
||||
/**
|
||||
* \brief Include the nested-name-specifier, e.g. Foo:: in x.Foo::y, in the
|
||||
* range.
|
||||
*/
|
||||
CXNameRange_WantQualifier = 0x1,
|
||||
|
||||
/**
|
||||
* \brief Include the explicit template arguments, e.g. <int> in x.f<int>, in
|
||||
* the range.
|
||||
*/
|
||||
CXNameRange_WantTemplateArgs = 0x2,
|
||||
|
||||
/**
|
||||
* \brief If the name is non-contiguous, return the full spanning range.
|
||||
*
|
||||
* Non-contiguous names occur in Objective-C when a selector with two or more
|
||||
* parameters is used, or in C++ when using an operator:
|
||||
* \code
|
||||
* [object doSomething:here withValue:there]; // ObjC
|
||||
* return some_vector[1]; // C++
|
||||
* \endcode
|
||||
*/
|
||||
CXNameRange_WantSinglePiece = 0x4
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -2801,8 +3281,7 @@ clang_getCompletionChunkText(CXCompletionString completion_string,
|
||||
* \param chunk_number the 0-based index of the chunk in the completion string.
|
||||
*
|
||||
* \returns the completion string associated with the chunk at index
|
||||
* \c chunk_number, or NULL if that chunk is not represented by a completion
|
||||
* string.
|
||||
* \c chunk_number.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompletionString
|
||||
clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
|
||||
@ -2840,6 +3319,45 @@ clang_getCompletionPriority(CXCompletionString completion_string);
|
||||
CINDEX_LINKAGE enum CXAvailabilityKind
|
||||
clang_getCompletionAvailability(CXCompletionString completion_string);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the number of annotations associated with the given
|
||||
* completion string.
|
||||
*
|
||||
* \param completion_string the completion string to query.
|
||||
*
|
||||
* \returns the number of annotations associated with the given completion
|
||||
* string.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned
|
||||
clang_getCompletionNumAnnotations(CXCompletionString completion_string);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the annotation associated with the given completion string.
|
||||
*
|
||||
* \param completion_string the completion string to query.
|
||||
*
|
||||
* \param annotation_number the 0-based index of the annotation of the
|
||||
* completion string.
|
||||
*
|
||||
* \returns annotation string associated with the completion at index
|
||||
* \c annotation_number, or a NULL string if that annotation is not available.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_getCompletionAnnotation(CXCompletionString completion_string,
|
||||
unsigned annotation_number);
|
||||
|
||||
/**
|
||||
* \brief Retrieve a completion string for an arbitrary declaration or macro
|
||||
* definition cursor.
|
||||
*
|
||||
* \param cursor The cursor to query.
|
||||
*
|
||||
* \returns A non-context-sensitive completion string for declaration and macro
|
||||
* definition cursors, or NULL for other kinds of cursors.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompletionString
|
||||
clang_getCursorCompletionString(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Contains the results of code-completion.
|
||||
*
|
||||
@ -3144,6 +3662,54 @@ CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
|
||||
CINDEX_LINKAGE
|
||||
unsigned long long clang_codeCompleteGetContexts(
|
||||
CXCodeCompleteResults *Results);
|
||||
|
||||
/**
|
||||
* \brief Returns the cursor kind for the container for the current code
|
||||
* completion context. The container is only guaranteed to be set for
|
||||
* contexts where a container exists (i.e. member accesses or Objective-C
|
||||
* message sends); if there is not a container, this function will return
|
||||
* CXCursor_InvalidCode.
|
||||
*
|
||||
* \param Results the code completion results to query
|
||||
*
|
||||
* \param IsIncomplete on return, this value will be false if Clang has complete
|
||||
* information about the container. If Clang does not have complete
|
||||
* information, this value will be true.
|
||||
*
|
||||
* \returns the container kind, or CXCursor_InvalidCode if there is not a
|
||||
* container
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
enum CXCursorKind clang_codeCompleteGetContainerKind(
|
||||
CXCodeCompleteResults *Results,
|
||||
unsigned *IsIncomplete);
|
||||
|
||||
/**
|
||||
* \brief Returns the USR for the container for the current code completion
|
||||
* context. If there is not a container for the current context, this
|
||||
* function will return the empty string.
|
||||
*
|
||||
* \param Results the code completion results to query
|
||||
*
|
||||
* \returns the USR for the container
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *Results);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns the currently-entered selector for an Objective-C message
|
||||
* send, formatted like "initWithFoo:bar:". Only guaranteed to return a
|
||||
* non-empty string for CXCompletionContext_ObjCInstanceMessage and
|
||||
* CXCompletionContext_ObjCClassMessage.
|
||||
*
|
||||
* \param Results the code completion results to query
|
||||
*
|
||||
* \returns the selector (or partial selector) that has been entered thus far
|
||||
* for an Objective-C message send.
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results);
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -3242,6 +3808,53 @@ CINDEX_LINKAGE void clang_remap_getFilenames(CXRemapping, unsigned index,
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_remap_dispose(CXRemapping);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** \defgroup CINDEX_HIGH Higher level API functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
enum CXVisitorResult {
|
||||
CXVisit_Break,
|
||||
CXVisit_Continue
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void *context;
|
||||
enum CXVisitorResult (*visit)(void *context, CXCursor, CXSourceRange);
|
||||
} CXCursorAndRangeVisitor;
|
||||
|
||||
/**
|
||||
* \brief Find references of a declaration in a specific file.
|
||||
*
|
||||
* \param cursor pointing to a declaration or a reference of one.
|
||||
*
|
||||
* \param file to search for references.
|
||||
*
|
||||
* \param visitor callback that will receive pairs of CXCursor/CXSourceRange for
|
||||
* each reference found.
|
||||
* The CXSourceRange will point inside the file; if the reference is inside
|
||||
* a macro (and not a macro argument) the CXSourceRange will be invalid.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_findReferencesInFile(CXCursor cursor, CXFile file,
|
||||
CXCursorAndRangeVisitor visitor);
|
||||
|
||||
#ifdef __has_feature
|
||||
# if __has_feature(blocks)
|
||||
|
||||
typedef enum CXVisitorResult
|
||||
(^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange);
|
||||
|
||||
CINDEX_LINKAGE
|
||||
void clang_findReferencesInFileWithBlock(CXCursor, CXFile,
|
||||
CXCursorAndRangeVisitorBlock);
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class DiagnosticClient;
|
||||
class DiagnosticConsumer;
|
||||
|
||||
namespace arcmt {
|
||||
class MigrationPass;
|
||||
@ -28,35 +28,53 @@ namespace arcmt {
|
||||
/// It then checks the AST and produces errors/warning for ARC migration issues
|
||||
/// that the user needs to handle manually.
|
||||
///
|
||||
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
|
||||
/// even if the migrator can fix them, but the function will still return false
|
||||
/// if all ARC errors can be fixed.
|
||||
///
|
||||
/// \param plistOut if non-empty, it is the file path to store the plist with
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool checkForManualIssues(CompilerInvocation &CI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient);
|
||||
StringRef Filename, InputKind Kind,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
bool emitPremigrationARCErrors = false,
|
||||
StringRef plistOut = StringRef());
|
||||
|
||||
/// \brief Works similar to checkForManualIssues but instead of checking, it
|
||||
/// applies automatic modifications to source files to conform to ARC.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool applyTransformations(CompilerInvocation &origCI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient);
|
||||
StringRef Filename, InputKind Kind,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
/// \brief Applies automatic modifications and produces temporary files
|
||||
/// and metadata into the \arg outputDir path.
|
||||
///
|
||||
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
|
||||
/// even if the migrator can fix them, but the function will still return false
|
||||
/// if all ARC errors can be fixed.
|
||||
///
|
||||
/// \param plistOut if non-empty, it is the file path to store the plist with
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient,
|
||||
llvm::StringRef outputDir);
|
||||
StringRef Filename, InputKind Kind,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
StringRef plistOut);
|
||||
|
||||
/// \brief Get the set of file remappings from the \arg outputDir path that
|
||||
/// migrateWithTemporaryFiles produced.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
|
||||
llvm::StringRef outputDir,
|
||||
DiagnosticClient *DiagClient);
|
||||
StringRef outputDir,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
typedef void (*TransformFn)(MigrationPass &pass);
|
||||
|
||||
@ -64,12 +82,12 @@ std::vector<TransformFn> getAllTransformations();
|
||||
|
||||
class MigrationProcess {
|
||||
CompilerInvocation OrigCI;
|
||||
DiagnosticClient *DiagClient;
|
||||
DiagnosticConsumer *DiagClient;
|
||||
FileRemapper Remapper;
|
||||
|
||||
public:
|
||||
MigrationProcess(const CompilerInvocation &CI, DiagnosticClient *diagClient,
|
||||
llvm::StringRef outputDir = llvm::StringRef());
|
||||
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
class RewriteListener {
|
||||
public:
|
||||
@ -78,7 +96,7 @@ class MigrationProcess {
|
||||
virtual void start(ASTContext &Ctx) { }
|
||||
virtual void finish() { }
|
||||
|
||||
virtual void insert(SourceLocation loc, llvm::StringRef text) { }
|
||||
virtual void insert(SourceLocation loc, StringRef text) { }
|
||||
virtual void remove(CharSourceRange range) { }
|
||||
};
|
||||
|
||||
|
@ -34,11 +34,15 @@ class ModifyAction : public WrapperFrontendAction {
|
||||
|
||||
class MigrateAction : public WrapperFrontendAction {
|
||||
std::string MigrateDir;
|
||||
std::string PlistOut;
|
||||
bool EmitPremigrationARCErros;
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
|
||||
public:
|
||||
MigrateAction(FrontendAction *WrappedAction, llvm::StringRef migrateDir);
|
||||
MigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
|
||||
StringRef plistOut,
|
||||
bool emitPremigrationARCErrors);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
|
||||
#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
@ -22,7 +23,7 @@ namespace llvm {
|
||||
namespace clang {
|
||||
class FileManager;
|
||||
class FileEntry;
|
||||
class Diagnostic;
|
||||
class DiagnosticsEngine;
|
||||
class CompilerInvocation;
|
||||
|
||||
namespace arcmt {
|
||||
@ -41,32 +42,32 @@ class FileRemapper {
|
||||
FileRemapper();
|
||||
~FileRemapper();
|
||||
|
||||
bool initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
|
||||
bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
|
||||
bool ignoreIfFilesChanged);
|
||||
bool flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag);
|
||||
bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag);
|
||||
|
||||
bool overwriteOriginal(Diagnostic &Diag,
|
||||
llvm::StringRef outputDir = llvm::StringRef());
|
||||
bool overwriteOriginal(DiagnosticsEngine &Diag,
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
void remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf);
|
||||
void remap(llvm::StringRef filePath, llvm::StringRef newPath);
|
||||
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
|
||||
void remap(StringRef filePath, StringRef newPath);
|
||||
|
||||
void applyMappings(CompilerInvocation &CI) const;
|
||||
|
||||
void transferMappingsAndClear(CompilerInvocation &CI);
|
||||
|
||||
void clear(llvm::StringRef outputDir = llvm::StringRef());
|
||||
void clear(StringRef outputDir = StringRef());
|
||||
|
||||
private:
|
||||
void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf);
|
||||
void remap(const FileEntry *file, const FileEntry *newfile);
|
||||
|
||||
const FileEntry *getOriginalFile(llvm::StringRef filePath);
|
||||
const FileEntry *getOriginalFile(StringRef filePath);
|
||||
void resetTarget(Target &targ);
|
||||
|
||||
bool report(const std::string &err, Diagnostic &Diag);
|
||||
bool report(const Twine &err, DiagnosticsEngine &Diag);
|
||||
|
||||
std::string getRemapInfoFile(llvm::StringRef outputDir);
|
||||
std::string getRemapInfoFile(StringRef outputDir);
|
||||
};
|
||||
|
||||
} // end namespace arcmt
|
||||
|
@ -14,11 +14,13 @@
|
||||
#ifndef LLVM_CLANG_AST_APVALUE_H
|
||||
#define LLVM_CLANG_AST_APVALUE_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
|
||||
namespace clang {
|
||||
class CharUnits;
|
||||
class DiagnosticBuilder;
|
||||
class Expr;
|
||||
|
||||
/// APValue - This class implements a discriminated union of [uninitialized]
|
||||
@ -103,7 +105,7 @@ class APValue {
|
||||
bool isLValue() const { return Kind == LValue; }
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
|
||||
void print(llvm::raw_ostream &OS) const;
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
APSInt &getInt() {
|
||||
@ -233,11 +235,15 @@ class APValue {
|
||||
void MakeLValue();
|
||||
};
|
||||
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
|
||||
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
|
||||
|
@ -37,7 +37,6 @@
|
||||
|
||||
namespace llvm {
|
||||
struct fltSemantics;
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -45,7 +44,7 @@ namespace clang {
|
||||
class ASTRecordLayout;
|
||||
class BlockExpr;
|
||||
class CharUnits;
|
||||
class Diagnostic;
|
||||
class DiagnosticsEngine;
|
||||
class Expr;
|
||||
class ExternalASTSource;
|
||||
class ASTMutationListener;
|
||||
@ -64,6 +63,7 @@ namespace clang {
|
||||
class ObjCIvarDecl;
|
||||
class ObjCIvarRefExpr;
|
||||
class ObjCPropertyDecl;
|
||||
class ParmVarDecl;
|
||||
class RecordDecl;
|
||||
class StoredDeclsMap;
|
||||
class TagDecl;
|
||||
@ -120,6 +120,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
|
||||
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
|
||||
mutable llvm::FoldingSet<AutoType> AutoTypes;
|
||||
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
|
||||
llvm::FoldingSet<AttributedType> AttributedTypes;
|
||||
|
||||
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
|
||||
@ -149,10 +150,19 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
|
||||
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
|
||||
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
|
||||
|
||||
/// \brief Mapping from ObjCMethod to its duplicate declaration in the same
|
||||
/// interface.
|
||||
llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls;
|
||||
|
||||
/// \brief Mapping from __block VarDecls to their copy initialization expr.
|
||||
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
|
||||
|
||||
/// \brief Mapping from class scope functions specialization to their
|
||||
/// template patterns.
|
||||
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
|
||||
ClassScopeSpecializationPattern;
|
||||
|
||||
/// \brief Representation of a "canonical" template template parameter that
|
||||
/// is used in canonical template names.
|
||||
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
|
||||
@ -175,34 +185,41 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
TemplateTemplateParmDecl *
|
||||
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
|
||||
|
||||
/// \brief Whether __[u]int128_t identifier is installed.
|
||||
bool IsInt128Installed;
|
||||
/// \brief The typedef for the __int128_t type.
|
||||
mutable TypedefDecl *Int128Decl;
|
||||
|
||||
/// \brief The typedef for the __uint128_t type.
|
||||
mutable TypedefDecl *UInt128Decl;
|
||||
|
||||
/// BuiltinVaListType - built-in va list type.
|
||||
/// This is initially null and set by Sema::LazilyCreateBuiltin when
|
||||
/// a builtin that takes a valist is encountered.
|
||||
QualType BuiltinVaListType;
|
||||
|
||||
/// ObjCIdType - a pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCIdTypedefType;
|
||||
/// \brief The typedef for the predefined 'id' type.
|
||||
mutable TypedefDecl *ObjCIdDecl;
|
||||
|
||||
/// \brief The typedef for the predefined 'SEL' type.
|
||||
mutable TypedefDecl *ObjCSelDecl;
|
||||
|
||||
/// ObjCSelType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCSelTypedefType;
|
||||
|
||||
/// ObjCProtoType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCProtoType;
|
||||
const RecordType *ProtoStructType;
|
||||
|
||||
/// ObjCClassType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCClassTypedefType;
|
||||
/// \brief The typedef for the predefined 'Class' type.
|
||||
mutable TypedefDecl *ObjCClassDecl;
|
||||
|
||||
// Typedefs which may be provided defining the structure of Objective-C
|
||||
// pseudo-builtins
|
||||
QualType ObjCIdRedefinitionType;
|
||||
QualType ObjCClassRedefinitionType;
|
||||
QualType ObjCSelRedefinitionType;
|
||||
|
||||
QualType ObjCConstantStringType;
|
||||
mutable RecordDecl *CFConstantStringTypeDecl;
|
||||
|
||||
mutable RecordDecl *NSConstantStringTypeDecl;
|
||||
|
||||
mutable RecordDecl *ObjCFastEnumerationStateTypeDecl;
|
||||
|
||||
/// \brief The typedef declaration for the Objective-C "instancetype" type.
|
||||
TypedefDecl *ObjCInstanceTypeDecl;
|
||||
|
||||
/// \brief The type for the C FILE type.
|
||||
TypeDecl *FILEDecl;
|
||||
|
||||
@ -213,9 +230,15 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
TypeDecl *sigjmp_bufDecl;
|
||||
|
||||
/// \brief Type for the Block descriptor for Blocks CodeGen.
|
||||
///
|
||||
/// Since this is only used for generation of debug info, it is not
|
||||
/// serialized.
|
||||
mutable RecordDecl *BlockDescriptorType;
|
||||
|
||||
/// \brief Type for the Block descriptor for Blocks CodeGen.
|
||||
///
|
||||
/// Since this is only used for generation of debug info, it is not
|
||||
/// serialized.
|
||||
mutable RecordDecl *BlockDescriptorExtendedType;
|
||||
|
||||
/// \brief Declaration for the CUDA cudaConfigureCall function.
|
||||
@ -295,6 +318,12 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
typedef UsuallyTinyPtrVector<const CXXMethodDecl> CXXMethodVector;
|
||||
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
|
||||
|
||||
/// \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;
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
|
||||
/// SourceMgr - The associated SourceManager object.
|
||||
@ -302,7 +331,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
|
||||
/// LangOpts - The language options used to create the AST associated with
|
||||
/// this ASTContext object.
|
||||
LangOptions LangOpts;
|
||||
LangOptions &LangOpts;
|
||||
|
||||
/// \brief The allocator used to create AST objects.
|
||||
///
|
||||
@ -318,26 +347,29 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
CXXABI *createCXXABI(const TargetInfo &T);
|
||||
|
||||
/// \brief The logical -> physical address space map.
|
||||
const LangAS::Map &AddrSpaceMap;
|
||||
const LangAS::Map *AddrSpaceMap;
|
||||
|
||||
friend class ASTDeclReader;
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTWriter;
|
||||
|
||||
const TargetInfo *Target;
|
||||
clang::PrintingPolicy PrintingPolicy;
|
||||
|
||||
public:
|
||||
const TargetInfo &Target;
|
||||
IdentifierTable &Idents;
|
||||
SelectorTable &Selectors;
|
||||
Builtin::Context &BuiltinInfo;
|
||||
mutable DeclarationNameTable DeclarationNames;
|
||||
llvm::OwningPtr<ExternalASTSource> ExternalSource;
|
||||
ASTMutationListener *Listener;
|
||||
clang::PrintingPolicy PrintingPolicy;
|
||||
|
||||
// Typedefs which may be provided defining the structure of Objective-C
|
||||
// pseudo-builtins
|
||||
QualType ObjCIdRedefinitionType;
|
||||
QualType ObjCClassRedefinitionType;
|
||||
QualType ObjCSelRedefinitionType;
|
||||
clang::PrintingPolicy getPrintingPolicy() const { return PrintingPolicy; }
|
||||
|
||||
void setPrintingPolicy(clang::PrintingPolicy Policy) {
|
||||
PrintingPolicy = Policy;
|
||||
}
|
||||
|
||||
SourceManager& getSourceManager() { return SourceMgr; }
|
||||
const SourceManager& getSourceManager() const { return SourceMgr; }
|
||||
void *Allocate(unsigned Size, unsigned Align = 8) const {
|
||||
@ -357,9 +389,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
return DiagAllocator;
|
||||
}
|
||||
|
||||
const TargetInfo &getTargetInfo() const { return *Target; }
|
||||
|
||||
const LangOptions& getLangOptions() const { return LangOpts; }
|
||||
|
||||
Diagnostic &getDiagnostics() const;
|
||||
DiagnosticsEngine &getDiagnostics() const;
|
||||
|
||||
FullSourceLoc getFullLoc(SourceLocation Loc) const {
|
||||
return FullSourceLoc(Loc,SourceMgr);
|
||||
@ -377,6 +411,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
|
||||
const VarDecl *Var);
|
||||
|
||||
FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
|
||||
|
||||
void setClassScopeSpecializationPattern(FunctionDecl *FD,
|
||||
FunctionDecl *Pattern);
|
||||
|
||||
/// \brief Note that the static data member \p Inst is an instantiation of
|
||||
/// the static data member template \p Tmpl of a class template.
|
||||
void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
||||
@ -413,17 +452,17 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
/// BitfieldFollowsBitfield - return 'true" if 'FD' is a
|
||||
/// bitfield which follows the bitfield 'LastFD'.
|
||||
bool BitfieldFollowsBitfield(const FieldDecl *FD,
|
||||
const FieldDecl *LastFD) const;
|
||||
const FieldDecl *LastFD) const;
|
||||
|
||||
/// NoneBitfieldFollowsBitfield - return 'true" if 'FD' is not a
|
||||
/// NonBitfieldFollowsBitfield - return 'true" if 'FD' is not a
|
||||
/// bitfield which follows the bitfield 'LastFD'.
|
||||
bool NoneBitfieldFollowsBitfield(const FieldDecl *FD,
|
||||
const FieldDecl *LastFD) const;
|
||||
bool NonBitfieldFollowsBitfield(const FieldDecl *FD,
|
||||
const FieldDecl *LastFD) const;
|
||||
|
||||
/// BitfieldFollowsNoneBitfield - return 'true" if 'FD' is a
|
||||
/// BitfieldFollowsNonBitfield - return 'true" if 'FD' is a
|
||||
/// bitfield which follows the none bitfield 'LastFD'.
|
||||
bool BitfieldFollowsNoneBitfield(const FieldDecl *FD,
|
||||
const FieldDecl *LastFD) const;
|
||||
bool BitfieldFollowsNonBitfield(const FieldDecl *FD,
|
||||
const FieldDecl *LastFD) const;
|
||||
|
||||
// Access to the set of methods overridden by the given C++ method.
|
||||
typedef CXXMethodVector::iterator overridden_cxx_method_iterator;
|
||||
@ -454,6 +493,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
|
||||
CanQualType UnsignedLongLongTy, UnsignedInt128Ty;
|
||||
CanQualType FloatTy, DoubleTy, LongDoubleTy;
|
||||
CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
|
||||
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
CanQualType VoidPtrTy, NullPtrTy;
|
||||
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
|
||||
@ -463,10 +503,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
mutable QualType AutoDeductTy; // Deduction against 'auto'.
|
||||
mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'.
|
||||
|
||||
ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t,
|
||||
ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
Builtin::Context &builtins,
|
||||
unsigned size_reserve);
|
||||
unsigned size_reserve,
|
||||
bool DelayInitialization = false);
|
||||
|
||||
~ASTContext();
|
||||
|
||||
@ -497,6 +538,12 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
void PrintStats() const;
|
||||
const std::vector<Type*>& getTypes() const { return Types; }
|
||||
|
||||
/// \brief Retrieve the declaration for the 128-bit signed integer type.
|
||||
TypedefDecl *getInt128Decl() const;
|
||||
|
||||
/// \brief Retrieve the declaration for the 128-bit unsigned integer type.
|
||||
TypedefDecl *getUInt128Decl() const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Constructors
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -560,6 +607,10 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
|
||||
}
|
||||
|
||||
/// getAtomicType - Return the uniqued reference to the atomic type for
|
||||
/// the specified type.
|
||||
QualType getAtomicType(QualType T) const;
|
||||
|
||||
/// getBlockPointerType - Return the uniqued reference to the type for a block
|
||||
/// of the specified type.
|
||||
QualType getBlockPointerType(QualType T) const;
|
||||
@ -568,29 +619,10 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
/// blocks.
|
||||
QualType getBlockDescriptorType() const;
|
||||
|
||||
// Set the type for a Block descriptor type.
|
||||
void setBlockDescriptorType(QualType T);
|
||||
/// Get the BlockDescriptorType type, or NULL if it hasn't yet been built.
|
||||
QualType getRawBlockdescriptorType() {
|
||||
if (BlockDescriptorType)
|
||||
return getTagDeclType(BlockDescriptorType);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
/// This gets the struct used to keep track of the extended descriptor for
|
||||
/// pointer to blocks.
|
||||
QualType getBlockDescriptorExtendedType() const;
|
||||
|
||||
// Set the type for a Block descriptor extended type.
|
||||
void setBlockDescriptorExtendedType(QualType T);
|
||||
/// Get the BlockDescriptorExtendedType type, or NULL if it hasn't yet been
|
||||
/// built.
|
||||
QualType getRawBlockdescriptorExtendedType() const {
|
||||
if (BlockDescriptorExtendedType)
|
||||
return getTagDeclType(BlockDescriptorExtendedType);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
void setcudaConfigureCallDecl(FunctionDecl *FD) {
|
||||
cudaConfigureCallDecl = FD;
|
||||
}
|
||||
@ -599,7 +631,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
}
|
||||
|
||||
/// This builds the struct used for __block variables.
|
||||
QualType BuildByRefType(llvm::StringRef DeclName, QualType Ty) const;
|
||||
QualType BuildByRefType(StringRef DeclName, QualType Ty) const;
|
||||
|
||||
/// Returns true iff we need copy/dispose helpers for the given type.
|
||||
bool BlockRequiresCopying(QualType Ty) const;
|
||||
@ -824,19 +856,6 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
// constant CFStrings.
|
||||
QualType getCFConstantStringType() const;
|
||||
|
||||
// getNSConstantStringType - Return the C structure type used to represent
|
||||
// constant NSStrings.
|
||||
QualType getNSConstantStringType() const;
|
||||
/// Get the structure type used to representation NSStrings, or NULL
|
||||
/// if it hasn't yet been built.
|
||||
QualType getRawNSConstantStringType() const {
|
||||
if (NSConstantStringTypeDecl)
|
||||
return getTagDeclType(NSConstantStringTypeDecl);
|
||||
return QualType();
|
||||
}
|
||||
void setNSConstantStringType(QualType T);
|
||||
|
||||
|
||||
/// Get the structure type used to representation CFStrings, or NULL
|
||||
/// if it hasn't yet been built.
|
||||
QualType getRawCFConstantStringType() const {
|
||||
@ -852,19 +871,56 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
return ObjCConstantStringType;
|
||||
}
|
||||
|
||||
//// This gets the struct used to keep track of fast enumerations.
|
||||
QualType getObjCFastEnumerationStateType() const;
|
||||
|
||||
/// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet
|
||||
/// been built.
|
||||
QualType getRawObjCFastEnumerationStateType() const {
|
||||
if (ObjCFastEnumerationStateTypeDecl)
|
||||
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
|
||||
return QualType();
|
||||
/// \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 {
|
||||
if (ObjCIdRedefinitionType.isNull())
|
||||
return getObjCIdType();
|
||||
return ObjCIdRedefinitionType;
|
||||
}
|
||||
|
||||
/// \brief Set the user-written type that redefines 'id'.
|
||||
void setObjCIdRedefinitionType(QualType RedefType) {
|
||||
ObjCIdRedefinitionType = RedefType;
|
||||
}
|
||||
|
||||
void setObjCFastEnumerationStateType(QualType T);
|
||||
/// \brief Retrieve the type that 'Class' has been defined to, which may be
|
||||
/// different from the built-in 'Class' if 'Class' has been typedef'd.
|
||||
QualType getObjCClassRedefinitionType() const {
|
||||
if (ObjCClassRedefinitionType.isNull())
|
||||
return getObjCClassType();
|
||||
return ObjCClassRedefinitionType;
|
||||
}
|
||||
|
||||
/// \brief Set the user-written type that redefines 'SEL'.
|
||||
void setObjCClassRedefinitionType(QualType RedefType) {
|
||||
ObjCClassRedefinitionType = RedefType;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type that 'SEL' has been defined to, which may be
|
||||
/// different from the built-in 'SEL' if 'SEL' has been typedef'd.
|
||||
QualType getObjCSelRedefinitionType() const {
|
||||
if (ObjCSelRedefinitionType.isNull())
|
||||
return getObjCSelType();
|
||||
return ObjCSelRedefinitionType;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Set the user-written type that redefines 'SEL'.
|
||||
void setObjCSelRedefinitionType(QualType RedefType) {
|
||||
ObjCSelRedefinitionType = RedefType;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the Objective-C "instancetype" type, if already known;
|
||||
/// otherwise, returns a NULL type;
|
||||
QualType getObjCInstanceType() {
|
||||
return getTypeDeclType(getObjCInstanceTypeDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the typedef declaration corresponding to the Objective-C
|
||||
/// "instancetype" type.
|
||||
TypedefDecl *getObjCInstanceTypeDecl();
|
||||
|
||||
/// \brief Set the type for the C FILE type.
|
||||
void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
|
||||
|
||||
@ -950,26 +1006,39 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
/// purpose in characters.
|
||||
CharUnits getObjCEncodingTypeSize(QualType t) const;
|
||||
|
||||
/// \brief Whether __[u]int128_t identifier is installed.
|
||||
bool isInt128Installed() const { return IsInt128Installed; }
|
||||
void setInt128Installed() { IsInt128Installed = true; }
|
||||
|
||||
/// \brief Retrieve the typedef corresponding to the predefined 'id' type
|
||||
/// in Objective-C.
|
||||
TypedefDecl *getObjCIdDecl() const;
|
||||
|
||||
/// This setter/getter represents the ObjC 'id' type. It is setup lazily, by
|
||||
/// Sema. id is always a (typedef for a) pointer type, a pointer to a struct.
|
||||
QualType getObjCIdType() const { return ObjCIdTypedefType; }
|
||||
void setObjCIdType(QualType T);
|
||||
QualType getObjCIdType() const {
|
||||
return getTypeDeclType(getObjCIdDecl());
|
||||
}
|
||||
|
||||
void setObjCSelType(QualType T);
|
||||
QualType getObjCSelType() const { return ObjCSelTypedefType; }
|
||||
/// \brief Retrieve the typedef corresponding to the predefined 'SEL' type
|
||||
/// in Objective-C.
|
||||
TypedefDecl *getObjCSelDecl() const;
|
||||
|
||||
/// \brief Retrieve the type that corresponds to the predefined Objective-C
|
||||
/// 'SEL' type.
|
||||
QualType getObjCSelType() const {
|
||||
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;
|
||||
|
||||
/// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by
|
||||
/// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a
|
||||
/// struct.
|
||||
QualType getObjCClassType() const { return ObjCClassTypedefType; }
|
||||
void setObjCClassType(QualType T);
|
||||
QualType getObjCClassType() const {
|
||||
return getTypeDeclType(getObjCClassDecl());
|
||||
}
|
||||
|
||||
void setBuiltinVaListType(QualType T);
|
||||
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
|
||||
@ -1145,7 +1214,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D)
|
||||
const;
|
||||
|
||||
void DumpRecordLayout(const RecordDecl *RD, llvm::raw_ostream &OS) const;
|
||||
void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS) const;
|
||||
|
||||
/// getASTObjCImplementationLayout - Get or compute information about
|
||||
/// the layout of the specified Objective-C implementation. This may
|
||||
@ -1164,13 +1233,9 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
|
||||
|
||||
MangleContext *createMangleContext();
|
||||
|
||||
void ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
|
||||
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars)
|
||||
const;
|
||||
|
||||
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
|
||||
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const;
|
||||
SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
|
||||
|
||||
unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const;
|
||||
void CollectInheritedProtocols(const Decl *CDecl,
|
||||
@ -1261,7 +1326,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
/// \brief Retrieves the canonical representation of the given
|
||||
/// calling convention.
|
||||
CallingConv getCanonicalCallConv(CallingConv CC) const {
|
||||
if (CC == CC_C)
|
||||
if (!LangOpts.MRTD && CC == CC_C)
|
||||
return CC_Default;
|
||||
return CC;
|
||||
}
|
||||
@ -1400,7 +1465,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count)
|
||||
return AS;
|
||||
else
|
||||
return AddrSpaceMap[AS - LangAS::Offset];
|
||||
return (*AddrSpaceMap)[AS - LangAS::Offset];
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1421,13 +1486,13 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
bool typesAreBlockPointerCompatible(QualType, QualType);
|
||||
|
||||
bool isObjCIdType(QualType T) const {
|
||||
return T == ObjCIdTypedefType;
|
||||
return T == getObjCIdType();
|
||||
}
|
||||
bool isObjCClassType(QualType T) const {
|
||||
return T == ObjCClassTypedefType;
|
||||
return T == getObjCClassType();
|
||||
}
|
||||
bool isObjCSelType(QualType T) const {
|
||||
return T == ObjCSelTypedefType;
|
||||
return T == getObjCSelType();
|
||||
}
|
||||
bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
|
||||
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
|
||||
@ -1462,6 +1527,10 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
bool Unqualified = false);
|
||||
|
||||
QualType mergeObjCGCQualifiers(QualType, QualType);
|
||||
|
||||
bool FunctionTypesMatchOnNSConsumedAttrs(
|
||||
const FunctionProtoType *FromFunctionType,
|
||||
const FunctionProtoType *ToFunctionType);
|
||||
|
||||
void ResetObjCLayout(const ObjCContainerDecl *CD) {
|
||||
ObjCLayouts[CD] = 0;
|
||||
@ -1521,6 +1590,22 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
/// \brief Set the implementation of ObjCCategoryDecl.
|
||||
void setObjCImplementation(ObjCCategoryDecl *CatD,
|
||||
ObjCCategoryImplDecl *ImplD);
|
||||
|
||||
/// \brief Get the duplicate declaration of a ObjCMethod in the same
|
||||
/// interface, or null if non exists.
|
||||
const ObjCMethodDecl *getObjCMethodRedeclaration(
|
||||
const ObjCMethodDecl *MD) const {
|
||||
llvm::DenseMap<const ObjCMethodDecl*, const ObjCMethodDecl*>::const_iterator
|
||||
I = ObjCMethodRedecls.find(MD);
|
||||
if (I == ObjCMethodRedecls.end())
|
||||
return 0;
|
||||
return I->second;
|
||||
}
|
||||
|
||||
void setObjCMethodRedeclaration(const ObjCMethodDecl *MD,
|
||||
const ObjCMethodDecl *Redecl) {
|
||||
ObjCMethodRedecls[MD] = Redecl;
|
||||
}
|
||||
|
||||
/// \brief Set the copy inialization expression of a block var decl.
|
||||
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
|
||||
@ -1570,6 +1655,15 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
/// it is not used.
|
||||
bool DeclMustBeEmitted(const Decl *D);
|
||||
|
||||
|
||||
/// \brief Used by ParmVarDecl to store on the side the
|
||||
/// index of the parameter when it exceeds the size of the normal bitfield.
|
||||
void setParameterIndex(const ParmVarDecl *D, unsigned index);
|
||||
|
||||
/// \brief Used by ParmVarDecl to retrieve on the side the
|
||||
/// index of the parameter when it exceeds the size of the normal bitfield.
|
||||
unsigned getParameterIndex(const ParmVarDecl *D) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Statistics
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -1620,7 +1714,18 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
ASTContext(const ASTContext&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTContext&); // DO NOT IMPLEMENT
|
||||
|
||||
void InitBuiltinTypes();
|
||||
public:
|
||||
/// \brief Initialize built-in types.
|
||||
///
|
||||
/// This routine may only be invoked once for a given ASTContext object.
|
||||
/// It is normally invoked by the ASTContext constructor. However, the
|
||||
/// constructor can be asked to delay initialization, which places the burden
|
||||
/// of calling this function on the user of that object.
|
||||
///
|
||||
/// \param Target The target
|
||||
void InitBuiltinTypes(const TargetInfo &Target);
|
||||
|
||||
private:
|
||||
void InitBuiltinType(CanQualType &R, BuiltinType::Kind K);
|
||||
|
||||
// Return the ObjC type encoding for a given type.
|
||||
@ -1644,7 +1749,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
private:
|
||||
/// \brief A set of deallocations that should be performed when the
|
||||
/// ASTContext is destroyed.
|
||||
llvm::SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations;
|
||||
SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations;
|
||||
|
||||
// FIXME: This currently contains the set of StoredDeclMaps used
|
||||
// by DeclContext objects. This probably should not be in ASTContext,
|
||||
@ -1660,13 +1765,13 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
};
|
||||
|
||||
/// @brief Utility function for constructing a nullary selector.
|
||||
static inline Selector GetNullarySelector(llvm::StringRef name, ASTContext& Ctx) {
|
||||
static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
|
||||
IdentifierInfo* II = &Ctx.Idents.get(name);
|
||||
return Ctx.Selectors.getSelector(0, &II);
|
||||
}
|
||||
|
||||
/// @brief Utility function for constructing an unary selector.
|
||||
static inline Selector GetUnarySelector(llvm::StringRef name, ASTContext& Ctx) {
|
||||
static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
|
||||
IdentifierInfo* II = &Ctx.Idents.get(name);
|
||||
return Ctx.Selectors.getSelector(1, &II);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.inc"
|
||||
#undef DIAG
|
||||
@ -24,27 +24,27 @@ namespace clang {
|
||||
};
|
||||
} // end namespace diag
|
||||
|
||||
/// \brief Diagnostic argument formatting function for diagnostics that
|
||||
/// \brief DiagnosticsEngine argument formatting function for diagnostics that
|
||||
/// involve AST nodes.
|
||||
///
|
||||
/// This function formats diagnostic arguments for various AST nodes,
|
||||
/// including types, declaration names, nested name specifiers, and
|
||||
/// declaration contexts, into strings that can be printed as part of
|
||||
/// diagnostics. It is meant to be used as the argument to
|
||||
/// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext
|
||||
/// pointer.
|
||||
/// \c DiagnosticsEngine::SetArgToStringFn(), where the cookie is an \c
|
||||
/// ASTContext pointer.
|
||||
void FormatASTNodeDiagnosticArgument(
|
||||
Diagnostic::ArgumentKind Kind,
|
||||
DiagnosticsEngine::ArgumentKind Kind,
|
||||
intptr_t Val,
|
||||
const char *Modifier,
|
||||
unsigned ModLen,
|
||||
const char *Argument,
|
||||
unsigned ArgLen,
|
||||
const Diagnostic::ArgumentValue *PrevArgs,
|
||||
const DiagnosticsEngine::ArgumentValue *PrevArgs,
|
||||
unsigned NumPrevArgs,
|
||||
llvm::SmallVectorImpl<char> &Output,
|
||||
SmallVectorImpl<char> &Output,
|
||||
void *Cookie,
|
||||
llvm::SmallVectorImpl<intptr_t> &QualTypeVals);
|
||||
SmallVectorImpl<intptr_t> &QualTypeVals);
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -25,7 +25,7 @@ namespace clang {
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class Diagnostic;
|
||||
class DiagnosticsEngine;
|
||||
class Expr;
|
||||
class FileManager;
|
||||
class IdentifierInfo;
|
||||
@ -67,7 +67,7 @@ namespace clang {
|
||||
|
||||
/// \brief Imported, anonymous tag declarations that are missing their
|
||||
/// corresponding typedefs.
|
||||
llvm::SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
|
||||
SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
|
||||
|
||||
/// \brief Declaration (from, to) pairs that are known not to be equivalent
|
||||
/// (which we have already complained about).
|
||||
|
@ -22,6 +22,8 @@ namespace clang {
|
||||
class ClassTemplateSpecializationDecl;
|
||||
class FunctionDecl;
|
||||
class FunctionTemplateDecl;
|
||||
class ObjCCategoryDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
|
||||
/// \brief An abstract interface that should be implemented by listeners
|
||||
/// that want to be notified when an AST entity gets modified after its
|
||||
@ -54,6 +56,10 @@ class ASTMutationListener {
|
||||
|
||||
/// \brief A static data member was implicitly instantiated.
|
||||
virtual void StaticDataMemberInstantiated(const VarDecl *D) {}
|
||||
|
||||
/// \brief A new objc category class was added for an interface.
|
||||
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
|
||||
const ObjCInterfaceDecl *IFD) {}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -14,18 +14,18 @@
|
||||
#ifndef LLVM_CLANG_AST_ATTR_H
|
||||
#define LLVM_CLANG_AST_ATTR_H
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
using llvm::dyn_cast;
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
@ -58,7 +58,7 @@ namespace clang {
|
||||
/// Attr - This represents one attribute.
|
||||
class Attr {
|
||||
private:
|
||||
SourceLocation Loc;
|
||||
SourceRange Range;
|
||||
unsigned AttrKind : 16;
|
||||
|
||||
protected:
|
||||
@ -67,11 +67,10 @@ class Attr {
|
||||
virtual ~Attr();
|
||||
|
||||
void* operator new(size_t bytes) throw() {
|
||||
assert(0 && "Attrs cannot be allocated with regular 'new'.");
|
||||
return 0;
|
||||
llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
|
||||
}
|
||||
void operator delete(void* data) throw() {
|
||||
assert(0 && "Attrs cannot be released with regular 'delete'.");
|
||||
llvm_unreachable("Attrs cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
public:
|
||||
@ -86,8 +85,8 @@ class Attr {
|
||||
}
|
||||
|
||||
protected:
|
||||
Attr(attr::Kind AK, SourceLocation L)
|
||||
: Loc(L), AttrKind(AK), Inherited(false) {}
|
||||
Attr(attr::Kind AK, SourceRange R)
|
||||
: Range(R), AttrKind(AK), Inherited(false) {}
|
||||
|
||||
public:
|
||||
|
||||
@ -95,8 +94,9 @@ class Attr {
|
||||
return static_cast<attr::Kind>(AttrKind);
|
||||
}
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
SourceLocation getLocation() const { return Range.getBegin(); }
|
||||
SourceRange getRange() const { return Range; }
|
||||
void setRange(SourceRange R) { Range = R; }
|
||||
|
||||
bool isInherited() const { return Inherited; }
|
||||
|
||||
@ -109,8 +109,8 @@ class Attr {
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
protected:
|
||||
InheritableAttr(attr::Kind AK, SourceLocation L)
|
||||
: Attr(AK, L) {}
|
||||
InheritableAttr(attr::Kind AK, SourceRange R)
|
||||
: Attr(AK, R) {}
|
||||
|
||||
public:
|
||||
void setInherited(bool I) { Inherited = I; }
|
||||
@ -124,8 +124,8 @@ class InheritableAttr : public Attr {
|
||||
|
||||
class InheritableParamAttr : public InheritableAttr {
|
||||
protected:
|
||||
InheritableParamAttr(attr::Kind AK, SourceLocation L)
|
||||
: InheritableAttr(AK, L) {}
|
||||
InheritableParamAttr(attr::Kind AK, SourceRange R)
|
||||
: InheritableAttr(AK, R) {}
|
||||
|
||||
public:
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
@ -138,8 +138,8 @@ class InheritableParamAttr : public InheritableAttr {
|
||||
#include "clang/AST/Attrs.inc"
|
||||
|
||||
/// AttrVec - A vector of Attr, which is how they are stored on the AST.
|
||||
typedef llvm::SmallVector<Attr*, 2> AttrVec;
|
||||
typedef llvm::SmallVector<const Attr*, 2> ConstAttrVec;
|
||||
typedef SmallVector<Attr*, 2> AttrVec;
|
||||
typedef SmallVector<const Attr*, 2> ConstAttrVec;
|
||||
|
||||
/// DestroyAttrs - Destroy the contents of an AttrVec.
|
||||
inline void DestroyAttrs (AttrVec& V, ASTContext &C) {
|
||||
@ -159,12 +159,12 @@ class specific_attr_iterator {
|
||||
mutable AttrVec::const_iterator Current;
|
||||
|
||||
void AdvanceToNext() const {
|
||||
while (!llvm::isa<SpecificAttr>(*Current))
|
||||
while (!isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
void AdvanceToNext(AttrVec::const_iterator I) const {
|
||||
while (Current != I && !llvm::isa<SpecificAttr>(*Current))
|
||||
while (Current != I && !isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
@ -180,11 +180,11 @@ class specific_attr_iterator {
|
||||
|
||||
reference operator*() const {
|
||||
AdvanceToNext();
|
||||
return llvm::cast<SpecificAttr>(*Current);
|
||||
return cast<SpecificAttr>(*Current);
|
||||
}
|
||||
pointer operator->() const {
|
||||
AdvanceToNext();
|
||||
return llvm::cast<SpecificAttr>(*Current);
|
||||
return cast<SpecificAttr>(*Current);
|
||||
}
|
||||
|
||||
specific_attr_iterator& operator++() {
|
||||
|
87
include/clang/AST/BaseSubobject.h
Normal file
87
include/clang/AST/BaseSubobject.h
Normal file
@ -0,0 +1,87 @@
|
||||
//===--- BaseSubobject.h - BaseSubobject class ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides a definition of the BaseSubobject class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_BASESUBOBJECT_H
|
||||
#define LLVM_CLANG_AST_BASESUBOBJECT_H
|
||||
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
|
||||
namespace clang {
|
||||
class CXXRecordDecl;
|
||||
|
||||
// BaseSubobject - Uniquely identifies a direct or indirect base class.
|
||||
// Stores both the base class decl and the offset from the most derived class to
|
||||
// the base class. Used for vtable and VTT generation.
|
||||
class BaseSubobject {
|
||||
/// Base - The base class declaration.
|
||||
const CXXRecordDecl *Base;
|
||||
|
||||
/// BaseOffset - The offset from the most derived class to the base class.
|
||||
CharUnits BaseOffset;
|
||||
|
||||
public:
|
||||
BaseSubobject() { }
|
||||
BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset)
|
||||
: Base(Base), BaseOffset(BaseOffset) { }
|
||||
|
||||
/// getBase - Returns the base class declaration.
|
||||
const CXXRecordDecl *getBase() const { return Base; }
|
||||
|
||||
/// getBaseOffset - Returns the base class offset.
|
||||
CharUnits getBaseOffset() const { return BaseOffset; }
|
||||
|
||||
friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) {
|
||||
return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<> struct DenseMapInfo<clang::BaseSubobject> {
|
||||
static clang::BaseSubobject getEmptyKey() {
|
||||
return clang::BaseSubobject(
|
||||
DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(),
|
||||
clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey()));
|
||||
}
|
||||
|
||||
static clang::BaseSubobject getTombstoneKey() {
|
||||
return clang::BaseSubobject(
|
||||
DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(),
|
||||
clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey()));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::BaseSubobject &Base) {
|
||||
return
|
||||
DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
|
||||
DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity());
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::BaseSubobject &LHS,
|
||||
const clang::BaseSubobject &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// It's OK to treat BaseSubobject as a POD type.
|
||||
template <> struct isPodLike<clang::BaseSubobject> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -66,7 +66,7 @@ struct CXXBasePathElement {
|
||||
/// structure, which captures both the link from a derived class to one of its
|
||||
/// direct bases and identification describing which base class
|
||||
/// subobject is being used.
|
||||
class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
|
||||
class CXXBasePath : public SmallVector<CXXBasePathElement, 4> {
|
||||
public:
|
||||
CXXBasePath() : Access(AS_public) {}
|
||||
|
||||
@ -80,7 +80,7 @@ class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
|
||||
DeclContext::lookup_result Decls;
|
||||
|
||||
void clear() {
|
||||
llvm::SmallVectorImpl<CXXBasePathElement>::clear();
|
||||
SmallVectorImpl<CXXBasePathElement>::clear();
|
||||
Access = AS_public;
|
||||
}
|
||||
};
|
||||
@ -272,14 +272,14 @@ struct UniqueVirtualMethod {
|
||||
/// pair is the virtual method that overrides it (including the
|
||||
/// subobject in which that virtual function occurs).
|
||||
class OverridingMethods {
|
||||
llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
|
||||
llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
Overrides;
|
||||
|
||||
public:
|
||||
// Iterate over the set of subobjects that have overriding methods.
|
||||
typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
|
||||
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
::iterator iterator;
|
||||
typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
|
||||
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
::const_iterator const_iterator;
|
||||
iterator begin() { return Overrides.begin(); }
|
||||
const_iterator begin() const { return Overrides.begin(); }
|
||||
@ -289,9 +289,9 @@ class OverridingMethods {
|
||||
|
||||
// Iterate over the set of overriding virtual methods in a given
|
||||
// subobject.
|
||||
typedef llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
|
||||
typedef SmallVector<UniqueVirtualMethod, 4>::iterator
|
||||
overriding_iterator;
|
||||
typedef llvm::SmallVector<UniqueVirtualMethod, 4>::const_iterator
|
||||
typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator
|
||||
overriding_const_iterator;
|
||||
|
||||
// Add a new overriding method for a particular subobject.
|
||||
|
@ -125,6 +125,12 @@ namespace clang {
|
||||
/// isNegative - Test whether the quantity is less than zero.
|
||||
bool isNegative() const { return Quantity < 0; }
|
||||
|
||||
/// isPowerOfTwo - Test whether the quantity is a power of two.
|
||||
/// Zero is not a power of two.
|
||||
bool isPowerOfTwo() const {
|
||||
return (Quantity & -Quantity) == Quantity;
|
||||
}
|
||||
|
||||
// Arithmetic operators.
|
||||
CharUnits operator* (QuantityType N) const {
|
||||
return CharUnits(Quantity * N);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/ExternalASTSource.h"
|
||||
#include "clang/Basic/Linkage.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
||||
namespace clang {
|
||||
@ -32,6 +33,7 @@ class StringLiteral;
|
||||
class NestedNameSpecifier;
|
||||
class TemplateParameterList;
|
||||
class TemplateArgumentList;
|
||||
struct ASTTemplateArgumentListInfo;
|
||||
class MemberSpecializationInfo;
|
||||
class FunctionTemplateSpecializationInfo;
|
||||
class DependentFunctionTemplateSpecializationInfo;
|
||||
@ -115,7 +117,7 @@ class NamedDecl : public Decl {
|
||||
/// getName - Get the name of identifier for this declaration as a StringRef.
|
||||
/// This requires that the declaration have a name and that it be a simple
|
||||
/// identifier.
|
||||
llvm::StringRef getName() const {
|
||||
StringRef getName() const {
|
||||
assert(Name.isIdentifier() && "Name is not a simple identifier");
|
||||
return getIdentifier() ? getIdentifier()->getName() : "";
|
||||
}
|
||||
@ -132,7 +134,7 @@ class NamedDecl : public Decl {
|
||||
// FIXME: Deprecated, move clients to getName().
|
||||
std::string getNameAsString() const { return Name.getAsString(); }
|
||||
|
||||
void printName(llvm::raw_ostream &os) const { return Name.printName(os); }
|
||||
void printName(raw_ostream &os) const { return Name.printName(os); }
|
||||
|
||||
/// getDeclName - Get the actual, stored name of the declaration,
|
||||
/// which may be a special name.
|
||||
@ -180,6 +182,16 @@ class NamedDecl : public Decl {
|
||||
/// \brief Determine whether this declaration has linkage.
|
||||
bool hasLinkage() const;
|
||||
|
||||
/// \brief Whether this declaration was marked as being private to the
|
||||
/// module in which it was defined.
|
||||
bool isModulePrivate() const { return ModulePrivate; }
|
||||
|
||||
/// \brief Specify whether this declaration was marked as being private
|
||||
/// to the module in which it was defined.
|
||||
void setModulePrivate(bool MP = true) {
|
||||
ModulePrivate = MP;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration is a C++ class member.
|
||||
bool isCXXClassMember() const {
|
||||
const DeclContext *DC = getDeclContext();
|
||||
@ -294,9 +306,8 @@ class NamedDecl : public Decl {
|
||||
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
|
||||
};
|
||||
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
||||
const NamedDecl *ND) {
|
||||
ND->getDeclName().printName(OS);
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) {
|
||||
ND.printName(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
@ -706,13 +717,18 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// \brief Whether this variable is an ARC pseudo-__strong
|
||||
/// variable; see isARCPseudoStrong() for details.
|
||||
unsigned ARCPseudoStrong : 1;
|
||||
|
||||
/// \brief Whether this variable is (C++0x) constexpr.
|
||||
unsigned IsConstexpr : 1;
|
||||
};
|
||||
enum { NumVarDeclBits = 13 }; // one reserved bit
|
||||
enum { NumVarDeclBits = 13 };
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class StmtIteratorBase;
|
||||
|
||||
protected:
|
||||
enum { NumParameterIndexBits = 8 };
|
||||
|
||||
class ParmVarDeclBitfields {
|
||||
friend class ParmVarDecl;
|
||||
friend class ASTDeclReader;
|
||||
@ -737,7 +753,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
|
||||
/// The number of parameters preceding this parameter in the
|
||||
/// function parameter scope in which it was declared.
|
||||
unsigned ParameterIndex : 8;
|
||||
unsigned ParameterIndex : NumParameterIndexBits;
|
||||
};
|
||||
|
||||
union {
|
||||
@ -802,7 +818,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
return !isFileVarDecl();
|
||||
|
||||
// Return true for: Auto, Register.
|
||||
// Return false for: Extern, Static, PrivateExtern.
|
||||
// Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.
|
||||
|
||||
return getStorageClass() >= SC_Auto;
|
||||
}
|
||||
@ -1128,6 +1144,10 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; }
|
||||
void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; }
|
||||
|
||||
/// Whether this variable is (C++0x) constexpr.
|
||||
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
|
||||
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
|
||||
|
||||
/// \brief If this variable is an instantiated static data member of a
|
||||
/// class template specialization, returns the templated static data member
|
||||
/// from which it was instantiated.
|
||||
@ -1198,11 +1218,11 @@ class ParmVarDecl : public VarDecl {
|
||||
StorageClass S, StorageClass SCAsWritten,
|
||||
Expr *DefArg);
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
|
||||
void setObjCMethodScopeInfo(unsigned parameterIndex) {
|
||||
ParmVarDeclBits.IsObjCMethodParam = true;
|
||||
|
||||
ParmVarDeclBits.ParameterIndex = parameterIndex;
|
||||
assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
|
||||
setParameterIndex(parameterIndex);
|
||||
}
|
||||
|
||||
void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) {
|
||||
@ -1211,8 +1231,7 @@ class ParmVarDecl : public VarDecl {
|
||||
ParmVarDeclBits.ScopeDepthOrObjCQuals = scopeDepth;
|
||||
assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth && "truncation!");
|
||||
|
||||
ParmVarDeclBits.ParameterIndex = parameterIndex;
|
||||
assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
|
||||
setParameterIndex(parameterIndex);
|
||||
}
|
||||
|
||||
bool isObjCMethodParameter() const {
|
||||
@ -1226,7 +1245,7 @@ class ParmVarDecl : public VarDecl {
|
||||
|
||||
/// Returns the index of this parameter in its prototype or method scope.
|
||||
unsigned getFunctionScopeIndex() const {
|
||||
return ParmVarDeclBits.ParameterIndex;
|
||||
return getParameterIndex();
|
||||
}
|
||||
|
||||
ObjCDeclQualifier getObjCDeclQualifier() const {
|
||||
@ -1343,6 +1362,26 @@ class ParmVarDecl : public VarDecl {
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ParmVarDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ParmVar; }
|
||||
|
||||
private:
|
||||
enum { ParameterIndexSentinel = (1 << NumParameterIndexBits) - 1 };
|
||||
|
||||
void setParameterIndex(unsigned parameterIndex) {
|
||||
if (parameterIndex >= ParameterIndexSentinel) {
|
||||
setParameterIndexLarge(parameterIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
ParmVarDeclBits.ParameterIndex = parameterIndex;
|
||||
assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
|
||||
}
|
||||
unsigned getParameterIndex() const {
|
||||
unsigned d = ParmVarDeclBits.ParameterIndex;
|
||||
return d == ParameterIndexSentinel ? getParameterIndexLarge() : d;
|
||||
}
|
||||
|
||||
void setParameterIndexLarge(unsigned parameterIndex);
|
||||
unsigned getParameterIndexLarge() const;
|
||||
};
|
||||
|
||||
/// FunctionDecl - An instance of this class is created to represent a
|
||||
@ -1394,6 +1433,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
|
||||
bool HasImplicitReturnZero : 1;
|
||||
bool IsLateTemplateParsed : 1;
|
||||
bool IsConstexpr : 1;
|
||||
|
||||
/// \brief End part of this FunctionDecl's source range.
|
||||
///
|
||||
@ -1460,13 +1500,14 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD,
|
||||
TemplateSpecializationKind TSK);
|
||||
|
||||
void setParams(ASTContext &C, ParmVarDecl **NewParamInfo, unsigned NumParams);
|
||||
void setParams(ASTContext &C, llvm::ArrayRef<ParmVarDecl *> NewParamInfo);
|
||||
|
||||
protected:
|
||||
FunctionDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified)
|
||||
StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified,
|
||||
bool isConstexprSpecified)
|
||||
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
|
||||
StartLoc),
|
||||
DeclContext(DK),
|
||||
@ -1477,7 +1518,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
|
||||
IsDefaulted(false), IsExplicitlyDefaulted(false),
|
||||
HasImplicitReturnZero(false), IsLateTemplateParsed(false),
|
||||
EndRangeLoc(NameInfo.getEndLoc()),
|
||||
IsConstexpr(isConstexprSpecified), EndRangeLoc(NameInfo.getEndLoc()),
|
||||
TemplateOrSpecialization(),
|
||||
DNLoc(NameInfo.getInfo()) {}
|
||||
|
||||
@ -1500,11 +1541,13 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
StorageClass SC = SC_None,
|
||||
StorageClass SCAsWritten = SC_None,
|
||||
bool isInlineSpecified = false,
|
||||
bool hasWrittenPrototype = true) {
|
||||
bool hasWrittenPrototype = true,
|
||||
bool isConstexprSpecified = false) {
|
||||
DeclarationNameInfo NameInfo(N, NLoc);
|
||||
return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo,
|
||||
SC, SCAsWritten,
|
||||
isInlineSpecified, hasWrittenPrototype);
|
||||
isInlineSpecified, hasWrittenPrototype,
|
||||
isConstexprSpecified);
|
||||
}
|
||||
|
||||
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
@ -1514,7 +1557,8 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
StorageClass SC = SC_None,
|
||||
StorageClass SCAsWritten = SC_None,
|
||||
bool isInlineSpecified = false,
|
||||
bool hasWrittenPrototype = true);
|
||||
bool hasWrittenPrototype = true,
|
||||
bool isConstexprSpecified = false);
|
||||
|
||||
DeclarationNameInfo getNameInfo() const {
|
||||
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
|
||||
@ -1600,10 +1644,6 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool isPure() const { return IsPure; }
|
||||
void setPure(bool P = true);
|
||||
|
||||
/// Whether this is a constexpr function or constexpr constructor.
|
||||
// FIXME: C++0x: Implement tracking of the constexpr specifier.
|
||||
bool isConstExpr() const { return false; }
|
||||
|
||||
/// Whether this templated function will be late parsed.
|
||||
bool isLateTemplateParsed() const { return IsLateTemplateParsed; }
|
||||
void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; }
|
||||
@ -1646,6 +1686,10 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool hasInheritedPrototype() const { return HasInheritedPrototype; }
|
||||
void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; }
|
||||
|
||||
/// Whether this is a (C++0x) constexpr function or constexpr constructor.
|
||||
bool isConstexpr() const { return IsConstexpr; }
|
||||
void setConstexpr(bool IC) { IsConstexpr = IC; }
|
||||
|
||||
/// \brief Whether this function has been deleted.
|
||||
///
|
||||
/// A function that is "deleted" (via the C++0x "= delete" syntax)
|
||||
@ -1726,8 +1770,8 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
}
|
||||
void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
|
||||
setParams(getASTContext(), NewParamInfo, NumParams);
|
||||
void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
|
||||
setParams(getASTContext(), NewParamInfo);
|
||||
}
|
||||
|
||||
/// getMinRequiredArguments - Returns the minimum number of arguments
|
||||
@ -1768,11 +1812,13 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
}
|
||||
|
||||
/// \brief Determine whether this function should be inlined, because it is
|
||||
/// either marked "inline" or is a member function of a C++ class that
|
||||
/// was defined in the class body.
|
||||
/// either marked "inline" or "constexpr" or is a member function of a class
|
||||
/// that was defined in the class body.
|
||||
bool isInlined() const;
|
||||
|
||||
bool isInlineDefinitionExternallyVisible() const;
|
||||
|
||||
bool doesDeclarationForceExternallyVisibleDefinition() const;
|
||||
|
||||
/// isOverloadedOperator - Whether this function declaration
|
||||
/// represents an C++ overloaded operator, e.g., "operator+".
|
||||
@ -1847,7 +1893,11 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool isFunctionTemplateSpecialization() const {
|
||||
return getPrimaryTemplate() != 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the class scope template pattern that this function
|
||||
/// template specialization is instantiated from.
|
||||
FunctionDecl *getClassScopeSpecializationPattern() const;
|
||||
|
||||
/// \brief If this function is actually a function template specialization,
|
||||
/// retrieve information about this function template specialization.
|
||||
/// Otherwise, returns NULL.
|
||||
@ -1887,7 +1937,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// or if it had no explicit template argument list, returns NULL.
|
||||
/// Note that it an explicit template argument list may be written empty,
|
||||
/// e.g., template<> void foo<>(char* s);
|
||||
const TemplateArgumentListInfo*
|
||||
const ASTTemplateArgumentListInfo*
|
||||
getTemplateSpecializationArgsAsWritten() const;
|
||||
|
||||
/// \brief Specify that this function declaration is actually a function
|
||||
@ -1945,7 +1995,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// specialization or a member of a class template specialization.
|
||||
///
|
||||
/// \returns the first point of instantiation, if this function was
|
||||
/// instantiated from a template; otherwie, returns an invalid source
|
||||
/// instantiated from a template; otherwise, returns an invalid source
|
||||
/// location.
|
||||
SourceLocation getPointOfInstantiation() const;
|
||||
|
||||
@ -2033,6 +2083,7 @@ class FieldDecl : public DeclaratorDecl {
|
||||
Expr *getBitWidth() const {
|
||||
return isBitField() ? InitializerOrBitWidth.getPointer() : 0;
|
||||
}
|
||||
unsigned getBitWidthValue(const ASTContext &Ctx) const;
|
||||
void setBitWidth(Expr *BW) {
|
||||
assert(!InitializerOrBitWidth.getPointer() &&
|
||||
"bit width or initializer already set");
|
||||
@ -2308,9 +2359,10 @@ class TagDecl
|
||||
/// TagDeclKind - The TagKind enum.
|
||||
unsigned TagDeclKind : 2;
|
||||
|
||||
/// IsDefinition - True if this is a definition ("struct foo {};"), false if
|
||||
/// it is a declaration ("struct foo;").
|
||||
bool IsDefinition : 1;
|
||||
/// IsCompleteDefinition - True if this is a definition ("struct foo
|
||||
/// {};"), false if it is a declaration ("struct foo;"). It is not
|
||||
/// a definition until the definition has been fully processed.
|
||||
bool IsCompleteDefinition : 1;
|
||||
|
||||
/// IsBeingDefined - True if this is currently being defined.
|
||||
bool IsBeingDefined : 1;
|
||||
@ -2320,6 +2372,9 @@ class TagDecl
|
||||
/// in the syntax of a declarator.
|
||||
bool IsEmbeddedInDeclarator : 1;
|
||||
|
||||
/// /brief True if this tag is free standing, e.g. "struct foo;".
|
||||
bool IsFreeStanding : 1;
|
||||
|
||||
protected:
|
||||
// These are used by (and only defined for) EnumDecl.
|
||||
unsigned NumPositiveBits : 8;
|
||||
@ -2367,9 +2422,10 @@ class TagDecl
|
||||
assert((DK != Enum || TK == TTK_Enum) &&
|
||||
"EnumDecl not matched with TTK_Enum");
|
||||
TagDeclKind = TK;
|
||||
IsDefinition = false;
|
||||
IsCompleteDefinition = false;
|
||||
IsBeingDefined = false;
|
||||
IsEmbeddedInDeclarator = false;
|
||||
IsFreeStanding = false;
|
||||
setPreviousDeclaration(PrevDecl);
|
||||
}
|
||||
|
||||
@ -2408,14 +2464,15 @@ class TagDecl
|
||||
}
|
||||
|
||||
/// isThisDeclarationADefinition() - Return true if this declaration
|
||||
/// defines the type. Provided for consistency.
|
||||
/// is a completion definintion of the type. Provided for consistency.
|
||||
bool isThisDeclarationADefinition() const {
|
||||
return isDefinition();
|
||||
return isCompleteDefinition();
|
||||
}
|
||||
|
||||
/// isDefinition - Return true if this decl has its body specified.
|
||||
bool isDefinition() const {
|
||||
return IsDefinition;
|
||||
/// isCompleteDefinition - Return true if this decl has its body
|
||||
/// fully specified.
|
||||
bool isCompleteDefinition() const {
|
||||
return IsCompleteDefinition;
|
||||
}
|
||||
|
||||
/// isBeingDefined - Return true if this decl is currently being defined.
|
||||
@ -2430,6 +2487,11 @@ class TagDecl
|
||||
IsEmbeddedInDeclarator = isInDeclarator;
|
||||
}
|
||||
|
||||
bool isFreeStanding() const { return IsFreeStanding; }
|
||||
void setFreeStanding(bool isFreeStanding = true) {
|
||||
IsFreeStanding = isFreeStanding;
|
||||
}
|
||||
|
||||
/// \brief Whether this declaration declares a type that is
|
||||
/// dependent, i.e., a type that somehow depends on template
|
||||
/// parameters.
|
||||
@ -2444,14 +2506,15 @@ class TagDecl
|
||||
|
||||
/// getDefinition - Returns the TagDecl that actually defines this
|
||||
/// struct/union/class/enum. When determining whether or not a
|
||||
/// struct/union/class/enum is completely defined, one should use this method
|
||||
/// as opposed to 'isDefinition'. 'isDefinition' indicates whether or not a
|
||||
/// specific TagDecl is defining declaration, not whether or not the
|
||||
/// struct/union/class/enum type is defined. This method returns NULL if
|
||||
/// there is no TagDecl that defines the struct/union/class/enum.
|
||||
TagDecl* getDefinition() const;
|
||||
/// struct/union/class/enum has a definition, one should use this
|
||||
/// method as opposed to 'isDefinition'. 'isDefinition' indicates
|
||||
/// whether or not a specific TagDecl is defining declaration, not
|
||||
/// whether or not the struct/union/class/enum type is defined.
|
||||
/// This method returns NULL if there is no TagDecl that defines
|
||||
/// the struct/union/class/enum.
|
||||
TagDecl *getDefinition() const;
|
||||
|
||||
void setDefinition(bool V) { IsDefinition = V; }
|
||||
void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
|
||||
|
||||
const char *getKindName() const {
|
||||
return TypeWithKeyword::getTagTypeKindName(getTagKind());
|
||||
@ -2691,7 +2754,7 @@ class EnumDecl : public TagDecl {
|
||||
|
||||
/// \brief Returns true if this can be considered a complete type.
|
||||
bool isComplete() const {
|
||||
return isDefinition() || isFixed();
|
||||
return isCompleteDefinition() || isFixed();
|
||||
}
|
||||
|
||||
/// \brief Returns the enumeration (declared within the template)
|
||||
@ -2794,14 +2857,15 @@ class RecordDecl : public TagDecl {
|
||||
/// \endcode
|
||||
bool isInjectedClassName() const;
|
||||
|
||||
/// getDefinition - Returns the RecordDecl that actually defines this
|
||||
/// struct/union/class. When determining whether or not a struct/union/class
|
||||
/// is completely defined, one should use this method as opposed to
|
||||
/// 'isDefinition'. 'isDefinition' indicates whether or not a specific
|
||||
/// RecordDecl is defining declaration, not whether or not the record
|
||||
/// type is defined. This method returns NULL if there is no RecordDecl
|
||||
/// that defines the struct/union/tag.
|
||||
RecordDecl* getDefinition() const {
|
||||
/// getDefinition - Returns the RecordDecl that actually defines
|
||||
/// this struct/union/class. When determining whether or not a
|
||||
/// struct/union/class is completely defined, one should use this
|
||||
/// method as opposed to 'isCompleteDefinition'.
|
||||
/// 'isCompleteDefinition' indicates whether or not a specific
|
||||
/// RecordDecl is a completed definition, not whether or not the
|
||||
/// record type is defined. This method returns NULL if there is
|
||||
/// no RecordDecl that defines the struct/union/tag.
|
||||
RecordDecl *getDefinition() const {
|
||||
return cast_or_null<RecordDecl>(TagDecl::getDefinition());
|
||||
}
|
||||
|
||||
@ -2967,7 +3031,7 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
}
|
||||
void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
|
||||
void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo);
|
||||
|
||||
/// hasCaptures - True if this block (or its nested blocks) captures
|
||||
/// anything of local storage from its enclosing scopes.
|
||||
@ -3010,8 +3074,9 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
/// Insertion operator for diagnostics. This allows sending NamedDecl's
|
||||
/// into a diagnostic with <<.
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
NamedDecl* ND) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND), Diagnostic::ak_nameddecl);
|
||||
const NamedDecl* ND) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND),
|
||||
DiagnosticsEngine::ak_nameddecl);
|
||||
return DB;
|
||||
}
|
||||
|
||||
|
@ -243,19 +243,23 @@ class Decl {
|
||||
/// evaluated context or not, e.g. functions used in uninstantiated templates
|
||||
/// are regarded as "referenced" but not "used".
|
||||
unsigned Referenced : 1;
|
||||
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
unsigned Access : 2;
|
||||
friend class CXXClassMemberWrapper;
|
||||
|
||||
/// PCHLevel - the "level" of AST file from which this declaration was built.
|
||||
unsigned PCHLevel : 2;
|
||||
|
||||
/// \brief Whether this declaration was loaded from an AST file.
|
||||
unsigned FromASTFile : 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;
|
||||
|
||||
@ -269,7 +273,9 @@ class Decl {
|
||||
/// This field is only valid for NamedDecls subclasses.
|
||||
mutable unsigned CachedLinkage : 2;
|
||||
|
||||
|
||||
friend class ASTDeclWriter;
|
||||
friend class ASTDeclReader;
|
||||
|
||||
private:
|
||||
void CheckAccessDeclContext() const;
|
||||
|
||||
@ -279,7 +285,8 @@ class Decl {
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
|
||||
Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
|
||||
ModulePrivate(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
@ -289,7 +296,8 @@ class Decl {
|
||||
Decl(Kind DK, EmptyShell Empty)
|
||||
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
|
||||
Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
|
||||
ModulePrivate(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
HasCachedLinkage(0)
|
||||
{
|
||||
@ -493,25 +501,10 @@ class Decl {
|
||||
/// declaration cannot be weak-imported because it has a definition.
|
||||
bool canBeWeakImported(bool &IsDefinition) const;
|
||||
|
||||
/// \brief Retrieve the level of precompiled header from which this
|
||||
/// declaration was generated.
|
||||
///
|
||||
/// The PCH level of a declaration describes where the declaration originated
|
||||
/// from. A PCH level of 0 indicates that the declaration was parsed from
|
||||
/// source. A PCH level of 1 indicates that the declaration was loaded from
|
||||
/// a top-level AST file. A PCH level 2 indicates that the declaration was
|
||||
/// loaded from a PCH file the AST file depends on, and so on.
|
||||
unsigned getPCHLevel() const { return PCHLevel; }
|
||||
|
||||
/// \brief The maximum PCH level that any declaration may have.
|
||||
static const unsigned MaxPCHLevel = 3;
|
||||
|
||||
/// \brief Set the PCH level of this declaration.
|
||||
void setPCHLevel(unsigned Level) {
|
||||
assert(Level <= MaxPCHLevel && "PCH level exceeds the maximum");
|
||||
PCHLevel = Level;
|
||||
}
|
||||
|
||||
/// \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.
|
||||
///
|
||||
@ -574,7 +567,17 @@ class Decl {
|
||||
/// scoped decl is defined outside the current function or method. This is
|
||||
/// roughly global variables and functions, but also handles enums (which
|
||||
/// could be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const;
|
||||
bool isDefinedOutsideFunctionOrMethod() const {
|
||||
return getParentFunctionOrMethod() == 0;
|
||||
}
|
||||
|
||||
/// \brief If this decl is defined inside a function/method/block it returns
|
||||
/// the corresponding DeclContext, otherwise it returns null.
|
||||
const DeclContext *getParentFunctionOrMethod() const;
|
||||
DeclContext *getParentFunctionOrMethod() {
|
||||
return const_cast<DeclContext*>(
|
||||
const_cast<const Decl*>(this)->getParentFunctionOrMethod());
|
||||
}
|
||||
|
||||
/// \brief Retrieves the "canonical" declaration of the given declaration.
|
||||
virtual Decl *getCanonicalDecl() { return this; }
|
||||
@ -671,6 +674,9 @@ class Decl {
|
||||
/// \brief Whether this declaration is a parameter pack.
|
||||
bool isParameterPack() const;
|
||||
|
||||
/// \brief returns true if this declaration is a template
|
||||
bool isTemplateDecl() const;
|
||||
|
||||
/// \brief Whether this declaration is a function or function template.
|
||||
bool isFunctionOrFunctionTemplate() const;
|
||||
|
||||
@ -734,15 +740,16 @@ class Decl {
|
||||
static DeclContext *castToDeclContext(const Decl *);
|
||||
static Decl *castFromDeclContext(const DeclContext *);
|
||||
|
||||
void print(llvm::raw_ostream &Out, unsigned Indentation = 0) const;
|
||||
void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0) const;
|
||||
void print(raw_ostream &Out, unsigned Indentation = 0,
|
||||
bool PrintInstantiation = false) const;
|
||||
void print(raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0, bool PrintInstantiation = false) const;
|
||||
static void printGroup(Decl** Begin, unsigned NumDecls,
|
||||
llvm::raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
void dump() const;
|
||||
void dumpXML() const;
|
||||
void dumpXML(llvm::raw_ostream &OS) const;
|
||||
void dumpXML(raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
const Attr *getAttrsImpl() const;
|
||||
@ -763,7 +770,7 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
|
||||
SourceManager &sm, const char *Msg)
|
||||
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
|
||||
|
||||
virtual void print(llvm::raw_ostream &OS) const;
|
||||
virtual void print(raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
class DeclContextLookupResult
|
||||
@ -839,7 +846,7 @@ class DeclContext {
|
||||
///
|
||||
/// \returns the first/last pair of declarations.
|
||||
static std::pair<Decl *, Decl *>
|
||||
BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls);
|
||||
BuildDeclChain(const SmallVectorImpl<Decl*> &Decls, bool FieldsAlreadyLoaded);
|
||||
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
@ -892,6 +899,18 @@ class DeclContext {
|
||||
return DeclKind == Decl::Block;
|
||||
}
|
||||
|
||||
bool isObjCContainer() const {
|
||||
switch (DeclKind) {
|
||||
case Decl::ObjCCategory:
|
||||
case Decl::ObjCCategoryImpl:
|
||||
case Decl::ObjCImplementation:
|
||||
case Decl::ObjCInterface:
|
||||
case Decl::ObjCProtocol:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isFunctionOrMethod() const {
|
||||
switch (DeclKind) {
|
||||
case Decl::Block:
|
||||
@ -1243,6 +1262,15 @@ class DeclContext {
|
||||
lookup_result lookup(DeclarationName Name);
|
||||
lookup_const_result lookup(DeclarationName Name) const;
|
||||
|
||||
/// \brief A simplistic name lookup mechanism that performs name lookup
|
||||
/// into this declaration context without consulting the external source.
|
||||
///
|
||||
/// This function should almost never be used, because it subverts the
|
||||
/// usual relationship between a DeclContext and the external source.
|
||||
/// See the ASTImporter for the (few, but important) use cases.
|
||||
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
|
||||
@ -1263,14 +1291,6 @@ class DeclContext {
|
||||
/// the declaration chains.
|
||||
void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true);
|
||||
|
||||
/// \brief Deserialize all the visible declarations from external storage.
|
||||
///
|
||||
/// Name lookup deserializes visible declarations lazily, thus a DeclContext
|
||||
/// may not have a complete name lookup table. This function deserializes
|
||||
/// the rest of visible declarations from the external storage and completes
|
||||
/// the name lookup table.
|
||||
void MaterializeVisibleDeclsFromExternalStorage();
|
||||
|
||||
/// udir_iterator - Iterates through the using-directives stored
|
||||
/// within this context.
|
||||
typedef UsingDirectiveDecl * const * udir_iterator;
|
||||
@ -1317,6 +1337,12 @@ class DeclContext {
|
||||
ExternalVisibleStorage = ES;
|
||||
}
|
||||
|
||||
/// \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);
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D);
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
#define DECL(NAME, BASE)
|
||||
|
@ -363,10 +363,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// default constructor.
|
||||
bool HasTrivialDefaultConstructor : 1;
|
||||
|
||||
/// HasConstExprNonCopyMoveConstructor - True when this class has at least
|
||||
/// HasConstexprNonCopyMoveConstructor - True when this class has at least
|
||||
/// one constexpr constructor which is neither the copy nor move
|
||||
/// constructor.
|
||||
bool HasConstExprNonCopyMoveConstructor : 1;
|
||||
bool HasConstexprNonCopyMoveConstructor : 1;
|
||||
|
||||
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
||||
/// constructor.
|
||||
@ -468,6 +468,14 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// \brief Whether we have already declared a destructor within the class.
|
||||
bool DeclaredDestructor : 1;
|
||||
|
||||
/// \brief Whether an implicit move constructor was attempted to be declared
|
||||
/// but would have been deleted.
|
||||
bool FailedImplicitMoveConstructor : 1;
|
||||
|
||||
/// \brief Whether an implicit move assignment operator was attempted to be
|
||||
/// declared but would have been deleted.
|
||||
bool FailedImplicitMoveAssignment : 1;
|
||||
|
||||
/// NumBases - The number of base class specifiers in Bases.
|
||||
unsigned NumBases;
|
||||
|
||||
@ -780,6 +788,33 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return data().DeclaredMoveConstructor;
|
||||
}
|
||||
|
||||
/// \brief Determine whether implicit move constructor generation for this
|
||||
/// class has failed before.
|
||||
bool hasFailedImplicitMoveConstructor() const {
|
||||
return data().FailedImplicitMoveConstructor;
|
||||
}
|
||||
|
||||
/// \brief Set whether implicit move constructor generation for this class
|
||||
/// has failed before.
|
||||
void setFailedImplicitMoveConstructor(bool Failed = true) {
|
||||
data().FailedImplicitMoveConstructor = Failed;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class should get an implicit move
|
||||
/// constructor or if any existing special member function inhibits this.
|
||||
///
|
||||
/// Covers all bullets of C++0x [class.copy]p9 except the last, that the
|
||||
/// constructor wouldn't be deleted, which is only looked up from a cached
|
||||
/// result.
|
||||
bool needsImplicitMoveConstructor() const {
|
||||
return !hasFailedImplicitMoveConstructor() &&
|
||||
!hasDeclaredMoveConstructor() &&
|
||||
!hasUserDeclaredCopyConstructor() &&
|
||||
!hasUserDeclaredCopyAssignment() &&
|
||||
!hasUserDeclaredMoveAssignment() &&
|
||||
!hasUserDeclaredDestructor();
|
||||
}
|
||||
|
||||
/// hasUserDeclaredCopyAssignment - Whether this class has a
|
||||
/// user-declared copy assignment operator. When false, a copy
|
||||
/// assigment operator will be implicitly declared.
|
||||
@ -807,6 +842,33 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return data().DeclaredMoveAssignment;
|
||||
}
|
||||
|
||||
/// \brief Determine whether implicit move assignment generation for this
|
||||
/// class has failed before.
|
||||
bool hasFailedImplicitMoveAssignment() const {
|
||||
return data().FailedImplicitMoveAssignment;
|
||||
}
|
||||
|
||||
/// \brief Set whether implicit move assignment generation for this class
|
||||
/// has failed before.
|
||||
void setFailedImplicitMoveAssignment(bool Failed = true) {
|
||||
data().FailedImplicitMoveAssignment = Failed;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class should get an implicit move
|
||||
/// assignment operator or if any existing special member function inhibits
|
||||
/// this.
|
||||
///
|
||||
/// Covers all bullets of C++0x [class.copy]p20 except the last, that the
|
||||
/// constructor wouldn't be deleted.
|
||||
bool needsImplicitMoveAssignment() const {
|
||||
return !hasFailedImplicitMoveAssignment() &&
|
||||
!hasDeclaredMoveAssignment() &&
|
||||
!hasUserDeclaredCopyConstructor() &&
|
||||
!hasUserDeclaredCopyAssignment() &&
|
||||
!hasUserDeclaredMoveConstructor() &&
|
||||
!hasUserDeclaredDestructor();
|
||||
}
|
||||
|
||||
/// hasUserDeclaredDestructor - Whether this class has a
|
||||
/// user-declared destructor. When false, a destructor will be
|
||||
/// implicitly declared.
|
||||
@ -889,10 +951,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
data().DeclaredDefaultConstructor);
|
||||
}
|
||||
|
||||
// hasConstExprNonCopyMoveConstructor - Whether this class has at least one
|
||||
// constexpr constructor other than the copy or move constructors
|
||||
bool hasConstExprNonCopyMoveConstructor() const {
|
||||
return data().HasConstExprNonCopyMoveConstructor;
|
||||
// hasConstexprNonCopyMoveConstructor - Whether this class has at least one
|
||||
// constexpr constructor other than the copy or move constructors.
|
||||
bool hasConstexprNonCopyMoveConstructor() const {
|
||||
return data().HasConstexprNonCopyMoveConstructor;
|
||||
}
|
||||
|
||||
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
||||
@ -942,6 +1004,25 @@ class CXXRecordDecl : public RecordDecl {
|
||||
return isTriviallyCopyable() && hasTrivialDefaultConstructor();
|
||||
}
|
||||
|
||||
// isLiteral - Whether this class is a literal type.
|
||||
//
|
||||
// C++0x [basic.types]p10
|
||||
// A class type that has all the following properties:
|
||||
// -- a trivial destructor
|
||||
// -- every constructor call and full-expression in the
|
||||
// brace-or-equal-intializers for non-static data members (if any) is
|
||||
// a constant expression.
|
||||
// -- it is an aggregate type or has at least one constexpr constructor or
|
||||
// constructor template that is not a copy or move constructor, and
|
||||
// -- all non-static data members and base classes of literal types
|
||||
//
|
||||
// We resolve DR1361 by ignoring the second bullet.
|
||||
bool isLiteral() const {
|
||||
return hasTrivialDestructor() &&
|
||||
(isAggregate() || hasConstexprNonCopyMoveConstructor()) &&
|
||||
!hasNonLiteralTypeFieldsOrBases();
|
||||
}
|
||||
|
||||
/// \brief If this record is an instantiation of a member class,
|
||||
/// retrieves the member class from which it was instantiated.
|
||||
///
|
||||
@ -1237,10 +1318,10 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isStatic, StorageClass SCAsWritten, bool isInline,
|
||||
SourceLocation EndLocation)
|
||||
bool isConstexpr, SourceLocation EndLocation)
|
||||
: FunctionDecl(DK, RD, StartLoc, NameInfo, T, TInfo,
|
||||
(isStatic ? SC_Static : SC_None),
|
||||
SCAsWritten, isInline) {
|
||||
SCAsWritten, isInline, isConstexpr) {
|
||||
if (EndLocation.isValid())
|
||||
setRangeEnd(EndLocation);
|
||||
}
|
||||
@ -1253,6 +1334,7 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
bool isStatic,
|
||||
StorageClass SCAsWritten,
|
||||
bool isInline,
|
||||
bool isConstexpr,
|
||||
SourceLocation EndLocation);
|
||||
|
||||
bool isStatic() const { return getStorageClass() == SC_Static; }
|
||||
@ -1333,6 +1415,7 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
/// void g() &&;
|
||||
/// void h();
|
||||
/// };
|
||||
/// \endcode
|
||||
RefQualifierKind getRefQualifier() const {
|
||||
return getType()->getAs<FunctionProtoType>()->getRefQualifier();
|
||||
}
|
||||
@ -1630,9 +1713,9 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isExplicitSpecified, bool isInline,
|
||||
bool isImplicitlyDeclared)
|
||||
bool isImplicitlyDeclared, bool isConstexpr)
|
||||
: CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false,
|
||||
SC_None, isInline, SourceLocation()),
|
||||
SC_None, isInline, isConstexpr, SourceLocation()),
|
||||
IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
|
||||
CtorInitializers(0), NumCtorInitializers(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
@ -1645,7 +1728,8 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isExplicit,
|
||||
bool isInline, bool isImplicitlyDeclared);
|
||||
bool isInline, bool isImplicitlyDeclared,
|
||||
bool isConstexpr);
|
||||
|
||||
/// isExplicitSpecified - Whether this constructor declaration has the
|
||||
/// 'explicit' keyword specified.
|
||||
@ -1853,7 +1937,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo, false,
|
||||
SC_None, isInline, SourceLocation()),
|
||||
SC_None, isInline, /*isConstexpr=*/false, SourceLocation()),
|
||||
ImplicitlyDefined(false), OperatorDelete(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
@ -1916,9 +2000,9 @@ class CXXConversionDecl : public CXXMethodDecl {
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isInline, bool isExplicitSpecified,
|
||||
SourceLocation EndLocation)
|
||||
bool isConstexpr, SourceLocation EndLocation)
|
||||
: CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo, false,
|
||||
SC_None, isInline, EndLocation),
|
||||
SC_None, isInline, isConstexpr, EndLocation),
|
||||
IsExplicitSpecified(isExplicitSpecified) { }
|
||||
|
||||
public:
|
||||
@ -1928,6 +2012,7 @@ class CXXConversionDecl : public CXXMethodDecl {
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T, TypeSourceInfo *TInfo,
|
||||
bool isInline, bool isExplicit,
|
||||
bool isConstexpr,
|
||||
SourceLocation EndLocation);
|
||||
|
||||
/// IsExplicitSpecified - Whether this conversion function declaration is
|
||||
|
@ -31,7 +31,7 @@ class DependentDiagnostic;
|
||||
struct StoredDeclsList {
|
||||
|
||||
/// DeclsTy - When in vector form, this is what the Data pointer points to.
|
||||
typedef llvm::SmallVector<NamedDecl *, 4> DeclsTy;
|
||||
typedef SmallVector<NamedDecl *, 4> DeclsTy;
|
||||
|
||||
/// \brief The stored data, which will be either a pointer to a NamedDecl,
|
||||
/// or a pointer to a vector.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_CLANG_AST_DECLOBJC_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/SelectorLocationsKind.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
namespace clang {
|
||||
@ -127,6 +128,12 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
// Method has a definition.
|
||||
unsigned IsDefined : 1;
|
||||
|
||||
/// \brief Method redeclaration in the same interface.
|
||||
unsigned IsRedeclaration : 1;
|
||||
|
||||
/// \brief Is redeclared in the same interface.
|
||||
mutable unsigned HasRedeclaration : 1;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
|
||||
/// @required/@optional
|
||||
unsigned DeclImplementation : 2;
|
||||
@ -138,8 +145,9 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
/// \brief Indicates whether this method has a related result type.
|
||||
unsigned RelatedResultType : 1;
|
||||
|
||||
// Number of args separated by ':' in a method declaration.
|
||||
unsigned NumSelectorArgs;
|
||||
/// \brief Whether the locations of the selector identifiers are in a
|
||||
/// "standard" position, a enum SelectorLocationsKind.
|
||||
unsigned SelLocsKind : 2;
|
||||
|
||||
// Result type of this method.
|
||||
QualType MethodDeclType;
|
||||
@ -147,9 +155,10 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
// Type source information for the result type.
|
||||
TypeSourceInfo *ResultTInfo;
|
||||
|
||||
/// ParamInfo - List of pointers to VarDecls for the formal parameters of this
|
||||
/// Method.
|
||||
ObjCList<ParmVarDecl> ParamInfo;
|
||||
/// \brief Array of ParmVarDecls for the formal parameters of this method
|
||||
/// and optionally followed by selector locations.
|
||||
void *ParamsAndSelLocs;
|
||||
unsigned NumParams;
|
||||
|
||||
/// List of attributes for this method declaration.
|
||||
SourceLocation EndLoc; // the location of the ';' or '}'.
|
||||
@ -165,6 +174,43 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
/// constructed by createImplicitParams.
|
||||
ImplicitParamDecl *CmdDecl;
|
||||
|
||||
SelectorLocationsKind getSelLocsKind() const {
|
||||
return (SelectorLocationsKind)SelLocsKind;
|
||||
}
|
||||
bool hasStandardSelLocs() const {
|
||||
return getSelLocsKind() != SelLoc_NonStandard;
|
||||
}
|
||||
|
||||
/// \brief Get a pointer to the stored selector identifiers locations array.
|
||||
/// No locations will be stored if HasStandardSelLocs is true.
|
||||
SourceLocation *getStoredSelLocs() {
|
||||
return reinterpret_cast<SourceLocation*>(getParams() + NumParams);
|
||||
}
|
||||
const SourceLocation *getStoredSelLocs() const {
|
||||
return reinterpret_cast<const SourceLocation*>(getParams() + NumParams);
|
||||
}
|
||||
|
||||
/// \brief Get a pointer to the stored selector identifiers locations array.
|
||||
/// No locations will be stored if HasStandardSelLocs is true.
|
||||
ParmVarDecl **getParams() {
|
||||
return reinterpret_cast<ParmVarDecl **>(ParamsAndSelLocs);
|
||||
}
|
||||
const ParmVarDecl *const *getParams() const {
|
||||
return reinterpret_cast<const ParmVarDecl *const *>(ParamsAndSelLocs);
|
||||
}
|
||||
|
||||
/// \brief Get the number of stored selector identifiers locations.
|
||||
/// No locations will be stored if HasStandardSelLocs is true.
|
||||
unsigned getNumStoredSelLocs() const {
|
||||
if (hasStandardSelLocs())
|
||||
return 0;
|
||||
return getNumSelectorLocs();
|
||||
}
|
||||
|
||||
void setParamsAndSelLocs(ASTContext &C,
|
||||
ArrayRef<ParmVarDecl*> Params,
|
||||
ArrayRef<SourceLocation> SelLocs);
|
||||
|
||||
ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
|
||||
Selector SelInfo, QualType T,
|
||||
TypeSourceInfo *ResultTInfo,
|
||||
@ -172,19 +218,23 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
bool isInstance = true,
|
||||
bool isVariadic = false,
|
||||
bool isSynthesized = false,
|
||||
bool isImplicitlyDeclared = false,
|
||||
bool isDefined = false,
|
||||
ImplementationControl impControl = None,
|
||||
bool HasRelatedResultType = false,
|
||||
unsigned numSelectorArgs = 0)
|
||||
bool HasRelatedResultType = false)
|
||||
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
|
||||
DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
|
||||
IsInstance(isInstance), IsVariadic(isVariadic),
|
||||
IsSynthesized(isSynthesized),
|
||||
IsDefined(isDefined),
|
||||
IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0),
|
||||
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
|
||||
RelatedResultType(HasRelatedResultType), NumSelectorArgs(numSelectorArgs),
|
||||
RelatedResultType(HasRelatedResultType),
|
||||
SelLocsKind(SelLoc_StandardNoSpace),
|
||||
MethodDeclType(T), ResultTInfo(ResultTInfo),
|
||||
EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {}
|
||||
ParamsAndSelLocs(0), NumParams(0),
|
||||
EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
/// \brief A definition will return its interface declaration.
|
||||
/// An interface declaration will return its definition.
|
||||
@ -194,17 +244,18 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
public:
|
||||
static ObjCMethodDecl *Create(ASTContext &C,
|
||||
SourceLocation beginLoc,
|
||||
SourceLocation endLoc, Selector SelInfo,
|
||||
SourceLocation endLoc,
|
||||
Selector SelInfo,
|
||||
QualType T,
|
||||
TypeSourceInfo *ResultTInfo,
|
||||
DeclContext *contextDecl,
|
||||
bool isInstance = true,
|
||||
bool isVariadic = false,
|
||||
bool isSynthesized = false,
|
||||
bool isImplicitlyDeclared = false,
|
||||
bool isDefined = false,
|
||||
ImplementationControl impControl = None,
|
||||
bool HasRelatedResultType = false,
|
||||
unsigned numSelectorArgs = 0);
|
||||
bool HasRelatedResultType = false);
|
||||
|
||||
virtual ObjCMethodDecl *getCanonicalDecl();
|
||||
const ObjCMethodDecl *getCanonicalDecl() const {
|
||||
@ -222,11 +273,10 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
/// \brief Note whether this method has a related result type.
|
||||
void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; }
|
||||
|
||||
unsigned getNumSelectorArgs() const { return NumSelectorArgs; }
|
||||
void setNumSelectorArgs(unsigned numSelectorArgs) {
|
||||
NumSelectorArgs = numSelectorArgs;
|
||||
}
|
||||
|
||||
/// \brief True if this is a method redeclaration in the same interface.
|
||||
bool isRedeclaration() const { return IsRedeclaration; }
|
||||
void setAsRedeclaration(const ObjCMethodDecl *PrevMethod);
|
||||
|
||||
// Location information, modeled after the Stmt API.
|
||||
SourceLocation getLocStart() const { return getLocation(); }
|
||||
@ -236,6 +286,29 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
return SourceRange(getLocation(), EndLoc);
|
||||
}
|
||||
|
||||
SourceLocation getSelectorStartLoc() const { return getSelectorLoc(0); }
|
||||
SourceLocation getSelectorLoc(unsigned Index) const {
|
||||
assert(Index < getNumSelectorLocs() && "Index out of range!");
|
||||
if (hasStandardSelLocs())
|
||||
return getStandardSelectorLoc(Index, getSelector(),
|
||||
getSelLocsKind() == SelLoc_StandardWithSpace,
|
||||
llvm::makeArrayRef(const_cast<ParmVarDecl**>(getParams()),
|
||||
NumParams),
|
||||
EndLoc);
|
||||
return getStoredSelLocs()[Index];
|
||||
}
|
||||
|
||||
void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const;
|
||||
|
||||
unsigned getNumSelectorLocs() const {
|
||||
if (isImplicit())
|
||||
return 0;
|
||||
Selector Sel = getSelector();
|
||||
if (Sel.isUnarySelector())
|
||||
return 1;
|
||||
return Sel.getNumArgs();
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *getClassInterface();
|
||||
const ObjCInterfaceDecl *getClassInterface() const {
|
||||
return const_cast<ObjCMethodDecl*>(this)->getClassInterface();
|
||||
@ -256,25 +329,31 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
void setResultTypeSourceInfo(TypeSourceInfo *TInfo) { ResultTInfo = TInfo; }
|
||||
|
||||
// Iterator access to formal parameters.
|
||||
unsigned param_size() const { return ParamInfo.size(); }
|
||||
typedef ObjCList<ParmVarDecl>::iterator param_iterator;
|
||||
param_iterator param_begin() const { return ParamInfo.begin(); }
|
||||
param_iterator param_end() const { return ParamInfo.end(); }
|
||||
unsigned param_size() const { return NumParams; }
|
||||
typedef const ParmVarDecl *const *param_const_iterator;
|
||||
typedef ParmVarDecl *const *param_iterator;
|
||||
param_const_iterator param_begin() const { return getParams(); }
|
||||
param_const_iterator param_end() const { return getParams() + NumParams; }
|
||||
param_iterator param_begin() { return getParams(); }
|
||||
param_iterator param_end() { return getParams() + NumParams; }
|
||||
// This method returns and of the parameters which are part of the selector
|
||||
// name mangling requirements.
|
||||
param_iterator sel_param_end() const {
|
||||
return ParamInfo.begin() + NumSelectorArgs;
|
||||
param_const_iterator sel_param_end() const {
|
||||
return param_begin() + getSelector().getNumArgs();
|
||||
}
|
||||
|
||||
void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num,
|
||||
unsigned numSelectorArgs) {
|
||||
ParamInfo.set(List, Num, C);
|
||||
NumSelectorArgs = numSelectorArgs;
|
||||
}
|
||||
/// \brief Sets the method's parameters and selector source locations.
|
||||
/// If the method is implicit (not coming from source) \arg SelLocs is
|
||||
/// ignored.
|
||||
void setMethodParams(ASTContext &C,
|
||||
ArrayRef<ParmVarDecl*> Params,
|
||||
ArrayRef<SourceLocation> SelLocs =
|
||||
ArrayRef<SourceLocation>());
|
||||
|
||||
// Iterator access to parameter types.
|
||||
typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun;
|
||||
typedef llvm::mapped_iterator<param_iterator, deref_fun> arg_type_iterator;
|
||||
typedef llvm::mapped_iterator<param_const_iterator, deref_fun>
|
||||
arg_type_iterator;
|
||||
|
||||
arg_type_iterator arg_type_begin() const {
|
||||
return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType));
|
||||
@ -337,6 +416,9 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC));
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// ObjCContainerDecl - Represents a container for method declarations.
|
||||
@ -344,14 +426,17 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
/// ObjCProtocolDecl, and ObjCImplDecl.
|
||||
///
|
||||
class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
||||
SourceLocation AtStart;
|
||||
|
||||
// These two locations in the range mark the end of the method container.
|
||||
// The first points to the '@' token, and the second to the 'end' token.
|
||||
SourceRange AtEnd;
|
||||
public:
|
||||
|
||||
ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id)
|
||||
: NamedDecl(DK, DC, L, Id), DeclContext(DK) {}
|
||||
ObjCContainerDecl(Kind DK, DeclContext *DC,
|
||||
IdentifierInfo *Id, SourceLocation nameLoc,
|
||||
SourceLocation atStartLoc)
|
||||
: NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {}
|
||||
|
||||
// Iterator access to properties.
|
||||
typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator;
|
||||
@ -403,6 +488,9 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
|
||||
|
||||
SourceLocation getAtStartLoc() const { return AtStart; }
|
||||
void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; }
|
||||
|
||||
// Marks the end of the container.
|
||||
SourceRange getAtEndRange() const {
|
||||
return AtEnd;
|
||||
@ -412,7 +500,7 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getLocation(), getAtEndRange().getEnd());
|
||||
return SourceRange(AtStart, getAtEndRange().getEnd());
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
@ -485,7 +573,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
/// completed by the external AST source when required.
|
||||
mutable bool ExternallyCompleted : 1;
|
||||
|
||||
SourceLocation ClassLoc; // location of the class identifier.
|
||||
SourceLocation SuperClassLoc; // location of the super class identifier.
|
||||
SourceLocation EndLoc; // marks the '>', '}', or identifier.
|
||||
|
||||
@ -576,7 +663,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
|
||||
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
|
||||
|
||||
ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); }
|
||||
ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); }
|
||||
ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); }
|
||||
|
||||
unsigned ivar_size() const {
|
||||
@ -585,7 +672,12 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
|
||||
bool ivar_empty() const { return ivar_begin() == ivar_end(); }
|
||||
|
||||
ObjCIvarDecl *all_declared_ivar_begin();
|
||||
ObjCIvarDecl *all_declared_ivar_begin();
|
||||
const ObjCIvarDecl *all_declared_ivar_begin() const {
|
||||
// Even though this modifies IvarList, it's conceptually const:
|
||||
// the ivar chain is essentially a cached property of ObjCInterfaceDecl.
|
||||
return const_cast<ObjCInterfaceDecl *>(this)->all_declared_ivar_begin();
|
||||
}
|
||||
void setIvarList(ObjCIvarDecl *ivar) { IvarList = ivar; }
|
||||
|
||||
/// setProtocolList - Set the list of protocols that this interface
|
||||
@ -675,12 +767,10 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
|
||||
ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, bool Instance=true);
|
||||
|
||||
// Location information, modeled after the Stmt API.
|
||||
SourceLocation getLocStart() const { return getLocation(); } // '@'interface
|
||||
SourceLocation getLocStart() const { return getAtStartLoc(); } // '@'interface
|
||||
SourceLocation getLocEnd() const { return EndLoc; }
|
||||
void setLocEnd(SourceLocation LE) { EndLoc = LE; }
|
||||
|
||||
void setClassLoc(SourceLocation Loc) { ClassLoc = Loc; }
|
||||
SourceLocation getClassLoc() const { return ClassLoc; }
|
||||
void setSuperClassLoc(SourceLocation Loc) { SuperClassLoc = Loc; }
|
||||
SourceLocation getSuperClassLoc() const { return SuperClassLoc; }
|
||||
|
||||
@ -754,6 +844,7 @@ class ObjCIvarDecl : public FieldDecl {
|
||||
const ObjCInterfaceDecl *getContainingInterface() const;
|
||||
|
||||
ObjCIvarDecl *getNextIvar() { return NextIvar; }
|
||||
const ObjCIvarDecl *getNextIvar() const { return NextIvar; }
|
||||
void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; }
|
||||
|
||||
void setAccessControl(AccessControl ac) { DeclAccess = ac; }
|
||||
@ -837,14 +928,17 @@ class ObjCProtocolDecl : public ObjCContainerDecl {
|
||||
|
||||
SourceLocation EndLoc; // marks the '>' or identifier.
|
||||
|
||||
ObjCProtocolDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
||||
: ObjCContainerDecl(ObjCProtocol, DC, L, Id),
|
||||
ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
|
||||
SourceLocation nameLoc, SourceLocation atStartLoc)
|
||||
: ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc),
|
||||
isForwardProtoDecl(true) {
|
||||
}
|
||||
|
||||
public:
|
||||
static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id);
|
||||
IdentifierInfo *Id,
|
||||
SourceLocation nameLoc,
|
||||
SourceLocation atStartLoc);
|
||||
|
||||
const ObjCProtocolList &getReferencedProtocols() const {
|
||||
return ReferencedProtocols;
|
||||
@ -884,7 +978,7 @@ class ObjCProtocolDecl : public ObjCContainerDecl {
|
||||
void setForwardDecl(bool val) { isForwardProtoDecl = val; }
|
||||
|
||||
// Location information, modeled after the Stmt API.
|
||||
SourceLocation getLocStart() const { return getLocation(); } // '@'protocol
|
||||
SourceLocation getLocStart() const { return getAtStartLoc(); } // '@'protocol
|
||||
SourceLocation getLocEnd() const { return EndLoc; }
|
||||
void setLocEnd(SourceLocation LE) { EndLoc = LE; }
|
||||
|
||||
@ -908,29 +1002,23 @@ class ObjCClassDecl : public Decl {
|
||||
ObjCInterfaceDecl *getInterface() const { return ID; }
|
||||
};
|
||||
private:
|
||||
ObjCClassRef *ForwardDecls;
|
||||
unsigned NumDecls;
|
||||
ObjCClassRef *ForwardDecl;
|
||||
|
||||
ObjCClassDecl(DeclContext *DC, SourceLocation L,
|
||||
ObjCInterfaceDecl *const *Elts, const SourceLocation *Locs,
|
||||
unsigned nElts, ASTContext &C);
|
||||
ObjCInterfaceDecl *const Elt, const SourceLocation Loc,
|
||||
ASTContext &C);
|
||||
public:
|
||||
static ObjCClassDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
ObjCInterfaceDecl *const *Elts = 0,
|
||||
const SourceLocation *Locs = 0,
|
||||
unsigned nElts = 0);
|
||||
ObjCInterfaceDecl *const Elt = 0,
|
||||
const SourceLocation Locs = SourceLocation());
|
||||
|
||||
ObjCInterfaceDecl *getForwardInterfaceDecl() { return ForwardDecl->getInterface(); }
|
||||
ObjCClassRef *getForwardDecl() { return ForwardDecl; }
|
||||
void setClass(ASTContext &C, ObjCInterfaceDecl*const Cls,
|
||||
const SourceLocation Locs);
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
|
||||
typedef const ObjCClassRef* iterator;
|
||||
iterator begin() const { return ForwardDecls; }
|
||||
iterator end() const { return ForwardDecls + NumDecls; }
|
||||
unsigned size() const { return NumDecls; }
|
||||
|
||||
/// setClassList - Set the list of forward classes.
|
||||
void setClassList(ASTContext &C, ObjCInterfaceDecl*const*List,
|
||||
const SourceLocation *Locs, unsigned Num);
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCClassDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCClass; }
|
||||
@ -1013,19 +1101,16 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
|
||||
/// true of class extension has at least one bitfield ivar.
|
||||
bool HasSynthBitfield : 1;
|
||||
|
||||
/// \brief The location of the '@' in '@interface'
|
||||
SourceLocation AtLoc;
|
||||
|
||||
/// \brief The location of the category name in this declaration.
|
||||
SourceLocation CategoryNameLoc;
|
||||
|
||||
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id)
|
||||
: ObjCContainerDecl(ObjCCategory, DC, ClassNameLoc, Id),
|
||||
ClassInterface(0), NextClassCategory(0), HasSynthBitfield(false),
|
||||
AtLoc(AtLoc), CategoryNameLoc(CategoryNameLoc) {
|
||||
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl)
|
||||
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
||||
ClassInterface(IDecl), NextClassCategory(0), HasSynthBitfield(false),
|
||||
CategoryNameLoc(CategoryNameLoc) {
|
||||
}
|
||||
public:
|
||||
|
||||
@ -1033,11 +1118,12 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc,
|
||||
SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id);
|
||||
IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *IDecl);
|
||||
static ObjCCategoryDecl *Create(ASTContext &C, EmptyShell Empty);
|
||||
|
||||
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
|
||||
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
|
||||
void setClassInterface(ObjCInterfaceDecl *IDecl) { ClassInterface = IDecl; }
|
||||
|
||||
ObjCCategoryImplDecl *getImplementation() const;
|
||||
void setImplementation(ObjCCategoryImplDecl *ImplD);
|
||||
@ -1066,14 +1152,6 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
}
|
||||
|
||||
ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; }
|
||||
void setNextClassCategory(ObjCCategoryDecl *Cat) {
|
||||
NextClassCategory = Cat;
|
||||
}
|
||||
void insertNextClassCategory() {
|
||||
NextClassCategory = ClassInterface->getCategoryList();
|
||||
ClassInterface->setCategoryList(this);
|
||||
ClassInterface->setChangedSinceDeserialization(true);
|
||||
}
|
||||
|
||||
bool IsClassExtension() const { return getIdentifier() == 0; }
|
||||
const ObjCCategoryDecl *getNextClassExtension() const;
|
||||
@ -1094,20 +1172,16 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
bool ivar_empty() const {
|
||||
return ivar_begin() == ivar_end();
|
||||
}
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
void setAtLoc(SourceLocation At) { AtLoc = At; }
|
||||
|
||||
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
|
||||
void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, getAtEndRange().getEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCCategoryDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCCategory; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
class ObjCImplDecl : public ObjCContainerDecl {
|
||||
@ -1115,10 +1189,12 @@ class ObjCImplDecl : public ObjCContainerDecl {
|
||||
ObjCInterfaceDecl *ClassInterface;
|
||||
|
||||
protected:
|
||||
ObjCImplDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
ObjCInterfaceDecl *classInterface)
|
||||
: ObjCContainerDecl(DK, DC, L,
|
||||
classInterface? classInterface->getIdentifier() : 0),
|
||||
ObjCImplDecl(Kind DK, DeclContext *DC,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
SourceLocation nameLoc, SourceLocation atStartLoc)
|
||||
: ObjCContainerDecl(DK, DC,
|
||||
classInterface? classInterface->getIdentifier() : 0,
|
||||
nameLoc, atStartLoc),
|
||||
ClassInterface(classInterface) {}
|
||||
|
||||
public:
|
||||
@ -1175,13 +1251,17 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
|
||||
// Category name
|
||||
IdentifierInfo *Id;
|
||||
|
||||
ObjCCategoryImplDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *classInterface)
|
||||
: ObjCImplDecl(ObjCCategoryImpl, DC, L, classInterface), Id(Id) {}
|
||||
ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
SourceLocation nameLoc, SourceLocation atStartLoc)
|
||||
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc),
|
||||
Id(Id) {}
|
||||
public:
|
||||
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *classInterface);
|
||||
IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
SourceLocation nameLoc,
|
||||
SourceLocation atStartLoc);
|
||||
|
||||
/// getIdentifier - Get the identifier that names the category
|
||||
/// interface associated with this implementation.
|
||||
@ -1203,7 +1283,7 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
|
||||
//
|
||||
// FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean
|
||||
// something different.
|
||||
llvm::StringRef getName() const {
|
||||
StringRef getName() const {
|
||||
return Id ? Id->getNameStart() : "";
|
||||
}
|
||||
|
||||
@ -1228,7 +1308,7 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
|
||||
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
|
||||
};
|
||||
|
||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
||||
raw_ostream &operator<<(raw_ostream &OS,
|
||||
const ObjCCategoryImplDecl *CID);
|
||||
|
||||
/// ObjCImplementationDecl - Represents a class definition - this is where
|
||||
@ -1259,17 +1339,19 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
/// true of class extension has at least one bitfield ivar.
|
||||
bool HasSynthBitfield : 1;
|
||||
|
||||
ObjCImplementationDecl(DeclContext *DC, SourceLocation L,
|
||||
ObjCImplementationDecl(DeclContext *DC,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
ObjCInterfaceDecl *superDecl)
|
||||
: ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
|
||||
ObjCInterfaceDecl *superDecl,
|
||||
SourceLocation nameLoc, SourceLocation atStartLoc)
|
||||
: ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc),
|
||||
SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0),
|
||||
HasCXXStructors(false), HasSynthBitfield(false) {}
|
||||
public:
|
||||
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
ObjCInterfaceDecl *superDecl);
|
||||
ObjCInterfaceDecl *superDecl,
|
||||
SourceLocation nameLoc,
|
||||
SourceLocation atStartLoc);
|
||||
|
||||
/// init_iterator - Iterates through the ivar initializer list.
|
||||
typedef CXXCtorInitializer **init_iterator;
|
||||
@ -1320,7 +1402,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
//
|
||||
// FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean
|
||||
// something different.
|
||||
llvm::StringRef getName() const {
|
||||
StringRef getName() const {
|
||||
assert(getIdentifier() && "Name is not a simple identifier");
|
||||
return getIdentifier()->getName();
|
||||
}
|
||||
@ -1368,7 +1450,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
||||
raw_ostream &operator<<(raw_ostream &OS,
|
||||
const ObjCImplementationDecl *ID);
|
||||
|
||||
/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
|
||||
@ -1423,7 +1505,7 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
NumPropertyAttrsBits = 12
|
||||
};
|
||||
|
||||
enum SetterKind { Assign, Retain, Copy };
|
||||
enum SetterKind { Assign, Retain, Copy, Weak };
|
||||
enum PropertyControl { None, Required, Optional };
|
||||
private:
|
||||
SourceLocation AtLoc; // location of @property
|
||||
@ -1495,14 +1577,29 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
return (PropertyAttributes & OBJC_PR_readonly);
|
||||
}
|
||||
|
||||
/// isAtomic - Return true if the property is atomic.
|
||||
bool isAtomic() const {
|
||||
return (PropertyAttributes & OBJC_PR_atomic);
|
||||
}
|
||||
|
||||
/// isRetaining - Return true if the property retains its value.
|
||||
bool isRetaining() const {
|
||||
return (PropertyAttributes &
|
||||
(OBJC_PR_retain | OBJC_PR_strong | OBJC_PR_copy));
|
||||
}
|
||||
|
||||
/// getSetterKind - Return the method used for doing assignment in
|
||||
/// the property setter. This is only valid if the property has been
|
||||
/// defined to have a setter.
|
||||
SetterKind getSetterKind() const {
|
||||
if (PropertyAttributes & (OBJC_PR_retain|OBJC_PR_strong))
|
||||
if (PropertyAttributes & OBJC_PR_strong)
|
||||
return getType()->isBlockPointerType() ? Copy : Retain;
|
||||
if (PropertyAttributes & OBJC_PR_retain)
|
||||
return Retain;
|
||||
if (PropertyAttributes & OBJC_PR_copy)
|
||||
return Copy;
|
||||
if (PropertyAttributes & OBJC_PR_weak)
|
||||
return Weak;
|
||||
return Assign;
|
||||
}
|
||||
|
||||
|
@ -264,7 +264,7 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
FunctionTemplateDecl *Template,
|
||||
TemplateSpecializationKind TSK,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
const TemplateArgumentListInfo *TemplateArgsAsWritten,
|
||||
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
|
||||
SourceLocation POI)
|
||||
: Function(FD),
|
||||
Template(Template, TSK - 1),
|
||||
@ -278,12 +278,7 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
TemplateSpecializationKind TSK,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
const TemplateArgumentListInfo *TemplateArgsAsWritten,
|
||||
SourceLocation POI) {
|
||||
return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK,
|
||||
TemplateArgs,
|
||||
TemplateArgsAsWritten,
|
||||
POI);
|
||||
}
|
||||
SourceLocation POI);
|
||||
|
||||
/// \brief The function template specialization that this structure
|
||||
/// describes.
|
||||
@ -300,7 +295,7 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
const TemplateArgumentList *TemplateArguments;
|
||||
|
||||
/// \brief The template arguments as written in the sources, if provided.
|
||||
const TemplateArgumentListInfo *TemplateArgumentsAsWritten;
|
||||
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
|
||||
|
||||
/// \brief The point at which this function template specialization was
|
||||
/// first instantiated.
|
||||
@ -913,7 +908,7 @@ class TemplateParmPosition {
|
||||
// FIXME: This should probably never be called, but it's here as
|
||||
TemplateParmPosition()
|
||||
: Depth(0), Position(0)
|
||||
{ /* assert(0 && "Cannot create positionless template parameter"); */ }
|
||||
{ /* llvm_unreachable("Cannot create positionless template parameter"); */ }
|
||||
|
||||
TemplateParmPosition(unsigned D, unsigned P)
|
||||
: Depth(D), Position(P)
|
||||
@ -1864,7 +1859,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl,
|
||||
|
||||
/// \brief Retrieve the partial specializations as an ordered list.
|
||||
void getPartialSpecializations(
|
||||
llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
|
||||
SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
|
||||
|
||||
/// \brief Find a class template partial specialization with the given
|
||||
/// type T.
|
||||
@ -2097,6 +2092,58 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl,
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Declaration of a function specialization at template class scope.
|
||||
/// This is a non standard extension needed to support MSVC.
|
||||
/// For example:
|
||||
/// template <class T>
|
||||
/// class A {
|
||||
/// template <class U> void foo(U a) { }
|
||||
/// template<> void foo(int a) { }
|
||||
/// }
|
||||
///
|
||||
/// "template<> foo(int a)" will be saved in Specialization as a normal
|
||||
/// CXXMethodDecl. Then during an instantiation of class A, it will be
|
||||
/// transformed into an actual function specialization.
|
||||
class ClassScopeFunctionSpecializationDecl : public Decl {
|
||||
private:
|
||||
ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc,
|
||||
CXXMethodDecl *FD)
|
||||
: Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
|
||||
Specialization(FD) {}
|
||||
|
||||
ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
|
||||
: Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
|
||||
|
||||
CXXMethodDecl *Specialization;
|
||||
|
||||
public:
|
||||
CXXMethodDecl *getSpecialization() const { return Specialization; }
|
||||
|
||||
static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C,
|
||||
DeclContext *DC,
|
||||
SourceLocation Loc,
|
||||
CXXMethodDecl *FD) {
|
||||
return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD);
|
||||
}
|
||||
|
||||
static ClassScopeFunctionSpecializationDecl *Create(ASTContext &Context,
|
||||
EmptyShell Empty) {
|
||||
return new (Context)ClassScopeFunctionSpecializationDecl(0,
|
||||
SourceLocation(), 0);
|
||||
}
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) {
|
||||
return K == Decl::ClassScopeFunctionSpecialization;
|
||||
}
|
||||
static bool classof(const ClassScopeFunctionSpecializationDecl *D) {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Implementation of inline functions that require the template declarations
|
||||
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
|
||||
: Function(FTD) { }
|
||||
|
@ -30,7 +30,7 @@ class DeclVisitor {
|
||||
public:
|
||||
RetTy Visit(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
default: assert(false && "Decl that isn't part of DeclNodes.inc!");
|
||||
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)
|
||||
|
@ -203,7 +203,7 @@ class DeclarationName {
|
||||
std::string getAsString() const;
|
||||
|
||||
/// printName - Print the human-readable name to a stream.
|
||||
void printName(llvm::raw_ostream &OS) const;
|
||||
void printName(raw_ostream &OS) const;
|
||||
|
||||
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
||||
/// this declaration name, or NULL if this declaration name isn't a
|
||||
@ -503,7 +503,7 @@ struct DeclarationNameInfo {
|
||||
std::string getAsString() const;
|
||||
|
||||
/// printName - Print the human-readable name to a stream.
|
||||
void printName(llvm::raw_ostream &OS) const;
|
||||
void printName(raw_ostream &OS) const;
|
||||
|
||||
/// getBeginLoc - Retrieve the location of the first token.
|
||||
SourceLocation getBeginLoc() const { return NameLoc; }
|
||||
@ -520,7 +520,7 @@ struct DeclarationNameInfo {
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
DeclarationName N) {
|
||||
DB.AddTaggedVal(N.getAsOpaqueInteger(),
|
||||
Diagnostic::ak_declarationname);
|
||||
DiagnosticsEngine::ak_declarationname);
|
||||
return DB;
|
||||
}
|
||||
|
||||
@ -529,11 +529,11 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
DeclarationName N) {
|
||||
PD.AddTaggedVal(N.getAsOpaqueInteger(),
|
||||
Diagnostic::ak_declarationname);
|
||||
DiagnosticsEngine::ak_declarationname);
|
||||
return PD;
|
||||
}
|
||||
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
||||
inline raw_ostream &operator<<(raw_ostream &OS,
|
||||
DeclarationNameInfo DNInfo) {
|
||||
DNInfo.printName(OS);
|
||||
return OS;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/DeclAccessPair.h"
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/ASTVector.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/UsuallyTinyPtrVector.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
@ -41,12 +42,10 @@ namespace clang {
|
||||
class CXXOperatorCallExpr;
|
||||
class CXXMemberCallExpr;
|
||||
class ObjCPropertyRefExpr;
|
||||
class TemplateArgumentLoc;
|
||||
class TemplateArgumentListInfo;
|
||||
class OpaqueValueExpr;
|
||||
|
||||
/// \brief A simple array of base specifiers.
|
||||
typedef llvm::SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
|
||||
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
|
||||
|
||||
/// Expr - This represents one expression. Note that Expr's are subclasses of
|
||||
/// Stmt. This allows an expression to be transparently used any place a Stmt
|
||||
@ -454,9 +453,14 @@ class Expr : public Stmt {
|
||||
|
||||
/// EvaluateAsBooleanCondition - Return true if this is a constant
|
||||
/// which we we can fold and convert to a boolean condition using
|
||||
/// any crazy technique that we want to.
|
||||
/// any crazy technique that we want to, even if the expression has
|
||||
/// side-effects.
|
||||
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const;
|
||||
|
||||
/// EvaluateAsInt - Return true if this is a constant which we can fold and
|
||||
/// convert to an integer using any crazy technique that we want to.
|
||||
bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx) const;
|
||||
|
||||
/// isEvaluatable - Call Evaluate to see if this expression can be constant
|
||||
/// folded, but discard the result.
|
||||
bool isEvaluatable(const ASTContext &Ctx) const;
|
||||
@ -467,9 +471,9 @@ class Expr : public Stmt {
|
||||
/// variable read.
|
||||
bool HasSideEffects(const ASTContext &Ctx) const;
|
||||
|
||||
/// EvaluateAsInt - Call Evaluate and return the folded integer. This
|
||||
/// EvaluateKnownConstInt - Call Evaluate and return the folded integer. This
|
||||
/// must be called on an expression that constant folds to an integer.
|
||||
llvm::APSInt EvaluateAsInt(const ASTContext &Ctx) const;
|
||||
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const;
|
||||
|
||||
/// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue
|
||||
/// with link time known address.
|
||||
@ -688,39 +692,6 @@ class OpaqueValueExpr : public Expr {
|
||||
static bool classof(const OpaqueValueExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents an explicit template argument list in C++, e.g.,
|
||||
/// the "<int>" in "sort<int>".
|
||||
struct ExplicitTemplateArgumentList {
|
||||
/// \brief The source location of the left angle bracket ('<');
|
||||
SourceLocation LAngleLoc;
|
||||
|
||||
/// \brief The source location of the right angle bracket ('>');
|
||||
SourceLocation RAngleLoc;
|
||||
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
/// The actual template arguments (if any) are stored after the
|
||||
/// ExplicitTemplateArgumentList structure.
|
||||
unsigned NumTemplateArgs;
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
TemplateArgumentLoc *getTemplateArgs() {
|
||||
return reinterpret_cast<TemplateArgumentLoc *> (this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
return reinterpret_cast<const TemplateArgumentLoc *> (this + 1);
|
||||
}
|
||||
|
||||
void initializeFrom(const TemplateArgumentListInfo &List);
|
||||
void initializeFrom(const TemplateArgumentListInfo &List,
|
||||
bool &Dependent, bool &InstantiationDependent,
|
||||
bool &ContainsUnexpandedParameterPack);
|
||||
void copyInto(TemplateArgumentListInfo &List) const;
|
||||
static std::size_t sizeFor(unsigned NumTemplateArgs);
|
||||
static std::size_t sizeFor(const TemplateArgumentListInfo &List);
|
||||
};
|
||||
|
||||
/// \brief A reference to a declared variable, function, enum, etc.
|
||||
/// [C99 6.5.1p2]
|
||||
///
|
||||
@ -804,6 +775,7 @@ class DeclRefExpr : public Expr {
|
||||
DeclRefExprBits.HasQualifier = 0;
|
||||
DeclRefExprBits.HasExplicitTemplateArgs = 0;
|
||||
DeclRefExprBits.HasFoundDecl = 0;
|
||||
DeclRefExprBits.HadMultipleCandidates = 0;
|
||||
computeDependence();
|
||||
}
|
||||
|
||||
@ -887,29 +859,29 @@ class DeclRefExpr : public Expr {
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name.
|
||||
ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
|
||||
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
|
||||
assert(hasExplicitTemplateArgs());
|
||||
if (hasFoundDecl())
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList *>(
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
|
||||
&getInternalFoundDecl() + 1);
|
||||
|
||||
if (hasQualifier())
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList *>(
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
|
||||
&getInternalQualifierLoc() + 1);
|
||||
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name.
|
||||
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
|
||||
return const_cast<DeclRefExpr *>(this)->getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ExplicitTemplateArgumentList *getExplicitTemplateArgsOpt() const {
|
||||
const ASTTemplateArgumentListInfo *getExplicitTemplateArgsOpt() const {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
@ -957,6 +929,18 @@ class DeclRefExpr : public Expr {
|
||||
return getExplicitTemplateArgs().RAngleLoc;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this expression refers to a function that
|
||||
/// was resolved from an overloaded set having size greater than 1.
|
||||
bool hadMultipleCandidates() const {
|
||||
return DeclRefExprBits.HadMultipleCandidates;
|
||||
}
|
||||
/// \brief Sets the flag telling whether this expression refers to
|
||||
/// a function that was resolved from an overloaded set having size
|
||||
/// greater than 1.
|
||||
void setHadMultipleCandidates(bool V = true) {
|
||||
DeclRefExprBits.HadMultipleCandidates = V;
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DeclRefExprClass;
|
||||
}
|
||||
@ -1112,29 +1096,39 @@ class IntegerLiteral : public Expr {
|
||||
};
|
||||
|
||||
class CharacterLiteral : public Expr {
|
||||
public:
|
||||
enum CharacterKind {
|
||||
Ascii,
|
||||
Wide,
|
||||
UTF16,
|
||||
UTF32
|
||||
};
|
||||
|
||||
private:
|
||||
unsigned Value;
|
||||
SourceLocation Loc;
|
||||
bool IsWide;
|
||||
unsigned Kind : 2;
|
||||
public:
|
||||
// type should be IntTy
|
||||
CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l)
|
||||
CharacterLiteral(unsigned value, CharacterKind kind, QualType type,
|
||||
SourceLocation l)
|
||||
: Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
|
||||
false, false),
|
||||
Value(value), Loc(l), IsWide(iswide) {
|
||||
Value(value), Loc(l), Kind(kind) {
|
||||
}
|
||||
|
||||
/// \brief Construct an empty character literal.
|
||||
CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
bool isWide() const { return IsWide; }
|
||||
CharacterKind getKind() const { return static_cast<CharacterKind>(Kind); }
|
||||
|
||||
SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
unsigned getValue() const { return Value; }
|
||||
|
||||
void setLocation(SourceLocation Location) { Loc = Location; }
|
||||
void setWide(bool W) { IsWide = W; }
|
||||
void setKind(CharacterKind kind) { Kind = kind; }
|
||||
void setValue(unsigned Val) { Value = Val; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
@ -1243,13 +1237,23 @@ class ImaginaryLiteral : public Expr {
|
||||
/// In this case, getByteLength() will return 6, but the string literal will
|
||||
/// have type "char[2]".
|
||||
class StringLiteral : public Expr {
|
||||
public:
|
||||
enum StringKind {
|
||||
Ascii,
|
||||
Wide,
|
||||
UTF8,
|
||||
UTF16,
|
||||
UTF32
|
||||
};
|
||||
|
||||
private:
|
||||
friend class ASTStmtReader;
|
||||
|
||||
const char *StrData;
|
||||
unsigned ByteLength;
|
||||
bool IsWide;
|
||||
bool IsPascal;
|
||||
unsigned NumConcatenated;
|
||||
unsigned Kind : 3;
|
||||
bool IsPascal : 1;
|
||||
SourceLocation TokLocs[1];
|
||||
|
||||
StringLiteral(QualType Ty) :
|
||||
@ -1259,33 +1263,39 @@ class StringLiteral : public Expr {
|
||||
public:
|
||||
/// This is the "fully general" constructor that allows representation of
|
||||
/// strings formed from multiple concatenated tokens.
|
||||
static StringLiteral *Create(ASTContext &C, llvm::StringRef Str, bool Wide,
|
||||
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
|
||||
bool Pascal, QualType Ty,
|
||||
const SourceLocation *Loc, unsigned NumStrs);
|
||||
|
||||
/// Simple constructor for string literals made from one token.
|
||||
static StringLiteral *Create(ASTContext &C, llvm::StringRef Str, bool Wide,
|
||||
bool Pascal, QualType Ty, SourceLocation Loc) {
|
||||
return Create(C, Str, Wide, Pascal, Ty, &Loc, 1);
|
||||
static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind,
|
||||
bool Pascal, QualType Ty,
|
||||
SourceLocation Loc) {
|
||||
return Create(C, Str, Kind, Pascal, Ty, &Loc, 1);
|
||||
}
|
||||
|
||||
/// \brief Construct an empty string literal.
|
||||
static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
|
||||
|
||||
llvm::StringRef getString() const {
|
||||
return llvm::StringRef(StrData, ByteLength);
|
||||
StringRef getString() const {
|
||||
return StringRef(StrData, ByteLength);
|
||||
}
|
||||
|
||||
unsigned getByteLength() const { return ByteLength; }
|
||||
|
||||
/// \brief Sets the string data to the given string data.
|
||||
void setString(ASTContext &C, llvm::StringRef Str);
|
||||
void setString(ASTContext &C, StringRef Str);
|
||||
|
||||
bool isWide() const { return IsWide; }
|
||||
StringKind getKind() const { return static_cast<StringKind>(Kind); }
|
||||
bool isAscii() const { return Kind == Ascii; }
|
||||
bool isWide() const { return Kind == Wide; }
|
||||
bool isUTF8() const { return Kind == UTF8; }
|
||||
bool isUTF16() const { return Kind == UTF16; }
|
||||
bool isUTF32() const { return Kind == UTF32; }
|
||||
bool isPascal() const { return IsPascal; }
|
||||
|
||||
|
||||
bool containsNonAsciiOrNull() const {
|
||||
llvm::StringRef Str = getString();
|
||||
StringRef Str = getString();
|
||||
for (unsigned i = 0, e = Str.size(); i != e; ++i)
|
||||
if (!isascii(Str[i]) || !Str[i])
|
||||
return true;
|
||||
@ -2029,6 +2039,10 @@ class MemberExpr : public Expr {
|
||||
/// the MemberNameQualifier structure.
|
||||
bool HasExplicitTemplateArgumentList : 1;
|
||||
|
||||
/// \brief True if this member expression refers to a method that
|
||||
/// was resolved from an overloaded set having size greater than 1.
|
||||
bool HadMultipleCandidates : 1;
|
||||
|
||||
/// \brief Retrieve the qualifier that preceded the member name, if any.
|
||||
MemberNameQualifier *getMemberQualifier() {
|
||||
assert(HasQualifierOrFoundDecl);
|
||||
@ -2051,7 +2065,8 @@ class MemberExpr : public Expr {
|
||||
base->containsUnexpandedParameterPack()),
|
||||
Base(base), MemberDecl(memberdecl), MemberLoc(NameInfo.getLoc()),
|
||||
MemberDNLoc(NameInfo.getInfo()), IsArrow(isarrow),
|
||||
HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {
|
||||
HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false),
|
||||
HadMultipleCandidates(false) {
|
||||
assert(memberdecl->getDeclName() == NameInfo.getName());
|
||||
}
|
||||
|
||||
@ -2068,7 +2083,8 @@ class MemberExpr : public Expr {
|
||||
base->containsUnexpandedParameterPack()),
|
||||
Base(base), MemberDecl(memberdecl), MemberLoc(l), MemberDNLoc(),
|
||||
IsArrow(isarrow),
|
||||
HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {}
|
||||
HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false),
|
||||
HadMultipleCandidates(false) {}
|
||||
|
||||
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
@ -2136,26 +2152,26 @@ class MemberExpr : public Expr {
|
||||
/// \brief Retrieve the explicit template argument list that
|
||||
/// follow the member template name. This must only be called on an
|
||||
/// expression with explicit template arguments.
|
||||
ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
|
||||
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
|
||||
assert(HasExplicitTemplateArgumentList);
|
||||
if (!HasQualifierOrFoundDecl)
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
|
||||
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList *>(
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
|
||||
getMemberQualifier() + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that
|
||||
/// followed the member template name. This must only be called on
|
||||
/// an expression with explicit template arguments.
|
||||
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
|
||||
return const_cast<MemberExpr *>(this)->getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
@ -2218,7 +2234,19 @@ class MemberExpr : public Expr {
|
||||
bool isImplicitAccess() const {
|
||||
return getBase() && getBase()->isImplicitCXXThis();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Returns true if this member expression refers to a method that
|
||||
/// was resolved from an overloaded set having size greater than 1.
|
||||
bool hadMultipleCandidates() const {
|
||||
return HadMultipleCandidates;
|
||||
}
|
||||
/// \brief Sets the flag telling whether this expression refers to
|
||||
/// a method that was resolved from an overloaded set having size
|
||||
/// greater than 1.
|
||||
void setHadMultipleCandidates(bool V = true) {
|
||||
HadMultipleCandidates = V;
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == MemberExprClass;
|
||||
}
|
||||
@ -2301,68 +2329,7 @@ class CastExpr : public Expr {
|
||||
private:
|
||||
Stmt *Op;
|
||||
|
||||
void CheckCastConsistency() const {
|
||||
#ifndef NDEBUG
|
||||
switch (getCastKind()) {
|
||||
case CK_DerivedToBase:
|
||||
case CK_UncheckedDerivedToBase:
|
||||
case CK_DerivedToBaseMemberPointer:
|
||||
case CK_BaseToDerived:
|
||||
case CK_BaseToDerivedMemberPointer:
|
||||
assert(!path_empty() && "Cast kind should have a base path!");
|
||||
break;
|
||||
|
||||
// These should not have an inheritance path.
|
||||
case CK_BitCast:
|
||||
case CK_Dynamic:
|
||||
case CK_ToUnion:
|
||||
case CK_ArrayToPointerDecay:
|
||||
case CK_FunctionToPointerDecay:
|
||||
case CK_NullToMemberPointer:
|
||||
case CK_NullToPointer:
|
||||
case CK_ConstructorConversion:
|
||||
case CK_IntegralToPointer:
|
||||
case CK_PointerToIntegral:
|
||||
case CK_ToVoid:
|
||||
case CK_VectorSplat:
|
||||
case CK_IntegralCast:
|
||||
case CK_IntegralToFloating:
|
||||
case CK_FloatingToIntegral:
|
||||
case CK_FloatingCast:
|
||||
case CK_AnyPointerToObjCPointerCast:
|
||||
case CK_AnyPointerToBlockPointerCast:
|
||||
case CK_ObjCObjectLValueCast:
|
||||
case CK_FloatingRealToComplex:
|
||||
case CK_FloatingComplexToReal:
|
||||
case CK_FloatingComplexCast:
|
||||
case CK_FloatingComplexToIntegralComplex:
|
||||
case CK_IntegralRealToComplex:
|
||||
case CK_IntegralComplexToReal:
|
||||
case CK_IntegralComplexCast:
|
||||
case CK_IntegralComplexToFloatingComplex:
|
||||
case CK_ObjCProduceObject:
|
||||
case CK_ObjCConsumeObject:
|
||||
case CK_ObjCReclaimReturnedObject:
|
||||
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
|
||||
// fallthrough to check for null base path
|
||||
|
||||
case CK_Dependent:
|
||||
case CK_LValueToRValue:
|
||||
case CK_GetObjCProperty:
|
||||
case CK_NoOp:
|
||||
case CK_PointerToBoolean:
|
||||
case CK_IntegralToBoolean:
|
||||
case CK_FloatingToBoolean:
|
||||
case CK_MemberPointerToBoolean:
|
||||
case CK_FloatingComplexToBoolean:
|
||||
case CK_IntegralComplexToBoolean:
|
||||
case CK_LValueBitCast: // -> bool&
|
||||
case CK_UserDefinedConversion: // operator bool()
|
||||
assert(path_empty() && "Cast kind should not have a base path!");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void CheckCastConsistency() const;
|
||||
|
||||
const CXXBaseSpecifier * const *path_buffer() const {
|
||||
return const_cast<CastExpr*>(this)->path_buffer();
|
||||
@ -2393,7 +2360,9 @@ class CastExpr : public Expr {
|
||||
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
|
||||
CastExprBits.Kind = kind;
|
||||
setBasePathSize(BasePathSize);
|
||||
#ifndef NDEBUG
|
||||
CheckCastConsistency();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \brief Construct an empty cast.
|
||||
@ -2746,7 +2715,7 @@ class BinaryOperator : public Expr {
|
||||
|
||||
/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep
|
||||
/// track of the type the operation is performed in. Due to the semantics of
|
||||
/// these operators, the operands are promoted, the aritmetic performed, an
|
||||
/// these operators, the operands are promoted, the arithmetic performed, an
|
||||
/// implicit conversion back to the result type done, then the assignment takes
|
||||
/// place. This captures the intermediate type which the computation is done
|
||||
/// in.
|
||||
@ -3134,7 +3103,7 @@ class ShuffleVectorExpr : public Expr {
|
||||
|
||||
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) {
|
||||
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
|
||||
return getExpr(N+2)->EvaluateAsInt(Ctx).getZExtValue();
|
||||
return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
|
||||
}
|
||||
|
||||
// Iterators
|
||||
@ -4045,7 +4014,7 @@ class ExtVectorElementExpr : public Expr {
|
||||
|
||||
/// getEncodedElementAccess - Encode the elements accessed into an llvm
|
||||
/// aggregate Constant of ConstantInt(s).
|
||||
void getEncodedElementAccess(llvm::SmallVectorImpl<unsigned> &Elts) const;
|
||||
void getEncodedElementAccess(SmallVectorImpl<unsigned> &Elts) const;
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), AccessorLoc);
|
||||
@ -4193,6 +4162,101 @@ class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr?
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
|
||||
};
|
||||
|
||||
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
|
||||
/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
|
||||
/// similarly-named C++0x instructions. All of these instructions take one
|
||||
/// primary pointer and at least one memory order.
|
||||
class AtomicExpr : public Expr {
|
||||
public:
|
||||
enum AtomicOp { Load, Store, CmpXchgStrong, CmpXchgWeak, Xchg,
|
||||
Add, Sub, And, Or, Xor };
|
||||
private:
|
||||
enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
unsigned NumSubExprs;
|
||||
SourceLocation BuiltinLoc, RParenLoc;
|
||||
AtomicOp Op;
|
||||
|
||||
public:
|
||||
AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, QualType t,
|
||||
AtomicOp op, SourceLocation RP);
|
||||
|
||||
/// \brief Build an empty AtomicExpr.
|
||||
explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { }
|
||||
|
||||
Expr *getPtr() const {
|
||||
return cast<Expr>(SubExprs[PTR]);
|
||||
}
|
||||
void setPtr(Expr *E) {
|
||||
SubExprs[PTR] = E;
|
||||
}
|
||||
Expr *getOrder() const {
|
||||
return cast<Expr>(SubExprs[ORDER]);
|
||||
}
|
||||
void setOrder(Expr *E) {
|
||||
SubExprs[ORDER] = E;
|
||||
}
|
||||
Expr *getVal1() const {
|
||||
assert(NumSubExprs >= 3);
|
||||
return cast<Expr>(SubExprs[VAL1]);
|
||||
}
|
||||
void setVal1(Expr *E) {
|
||||
assert(NumSubExprs >= 3);
|
||||
SubExprs[VAL1] = E;
|
||||
}
|
||||
Expr *getOrderFail() const {
|
||||
assert(NumSubExprs == 5);
|
||||
return cast<Expr>(SubExprs[ORDER_FAIL]);
|
||||
}
|
||||
void setOrderFail(Expr *E) {
|
||||
assert(NumSubExprs == 5);
|
||||
SubExprs[ORDER_FAIL] = E;
|
||||
}
|
||||
Expr *getVal2() const {
|
||||
assert(NumSubExprs == 5);
|
||||
return cast<Expr>(SubExprs[VAL2]);
|
||||
}
|
||||
void setVal2(Expr *E) {
|
||||
assert(NumSubExprs == 5);
|
||||
SubExprs[VAL2] = E;
|
||||
}
|
||||
|
||||
AtomicOp getOp() const { return Op; }
|
||||
void setOp(AtomicOp op) { Op = op; }
|
||||
unsigned getNumSubExprs() { return NumSubExprs; }
|
||||
void setNumSubExprs(unsigned num) { NumSubExprs = num; }
|
||||
|
||||
Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); }
|
||||
|
||||
bool isVolatile() const {
|
||||
return getPtr()->getType()->getPointeeType().isVolatileQualified();
|
||||
}
|
||||
|
||||
bool isCmpXChg() const {
|
||||
return getOp() == AtomicExpr::CmpXchgStrong ||
|
||||
getOp() == AtomicExpr::CmpXchgWeak;
|
||||
}
|
||||
|
||||
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
|
||||
void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
|
||||
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(BuiltinLoc, RParenLoc);
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == AtomicExprClass;
|
||||
}
|
||||
static bool classof(const AtomicExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
return child_range(SubExprs, SubExprs+NumSubExprs);
|
||||
}
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -807,37 +807,41 @@ class CXXConstructExpr : public Expr {
|
||||
|
||||
SourceLocation Loc;
|
||||
SourceRange ParenRange;
|
||||
unsigned NumArgs : 16;
|
||||
bool Elidable : 1;
|
||||
bool HadMultipleCandidates : 1;
|
||||
bool ZeroInitialization : 1;
|
||||
unsigned ConstructKind : 2;
|
||||
Stmt **Args;
|
||||
unsigned NumArgs;
|
||||
|
||||
protected:
|
||||
CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
|
||||
SourceLocation Loc,
|
||||
CXXConstructorDecl *d, bool elidable,
|
||||
Expr **args, unsigned numargs,
|
||||
bool HadMultipleCandidates,
|
||||
bool ZeroInitialization = false,
|
||||
ConstructionKind ConstructKind = CK_Complete,
|
||||
SourceRange ParenRange = SourceRange());
|
||||
|
||||
/// \brief Construct an empty C++ construction expression.
|
||||
CXXConstructExpr(StmtClass SC, EmptyShell Empty)
|
||||
: Expr(SC, Empty), Constructor(0), Elidable(0), ZeroInitialization(0),
|
||||
ConstructKind(0), Args(0), NumArgs(0) { }
|
||||
: Expr(SC, Empty), Constructor(0), NumArgs(0), Elidable(0),
|
||||
HadMultipleCandidates(false), ZeroInitialization(0),
|
||||
ConstructKind(0), Args(0) { }
|
||||
|
||||
public:
|
||||
/// \brief Construct an empty C++ construction expression.
|
||||
explicit CXXConstructExpr(EmptyShell Empty)
|
||||
: Expr(CXXConstructExprClass, Empty), Constructor(0),
|
||||
Elidable(0), ZeroInitialization(0),
|
||||
ConstructKind(0), Args(0), NumArgs(0) { }
|
||||
NumArgs(0), Elidable(0), HadMultipleCandidates(false),
|
||||
ZeroInitialization(0), ConstructKind(0), Args(0) { }
|
||||
|
||||
static CXXConstructExpr *Create(ASTContext &C, QualType T,
|
||||
SourceLocation Loc,
|
||||
CXXConstructorDecl *D, bool Elidable,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
bool HadMultipleCandidates,
|
||||
bool ZeroInitialization = false,
|
||||
ConstructionKind ConstructKind = CK_Complete,
|
||||
SourceRange ParenRange = SourceRange());
|
||||
@ -852,7 +856,12 @@ class CXXConstructExpr : public Expr {
|
||||
/// \brief Whether this construction is elidable.
|
||||
bool isElidable() const { return Elidable; }
|
||||
void setElidable(bool E) { Elidable = E; }
|
||||
|
||||
|
||||
/// \brief Whether the referred constructor was resolved from
|
||||
/// an overloaded set having size greater than 1.
|
||||
bool hadMultipleCandidates() const { return HadMultipleCandidates; }
|
||||
void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; }
|
||||
|
||||
/// \brief Whether this construction first requires
|
||||
/// zero-initialization before the initializer is called.
|
||||
bool requiresZeroInitialization() const { return ZeroInitialization; }
|
||||
@ -980,6 +989,7 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
|
||||
TypeSourceInfo *Type,
|
||||
Expr **Args,unsigned NumArgs,
|
||||
SourceRange parenRange,
|
||||
bool HadMultipleCandidates,
|
||||
bool ZeroInitialization = false);
|
||||
explicit CXXTemporaryObjectExpr(EmptyShell Empty)
|
||||
: CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { }
|
||||
@ -1049,8 +1059,11 @@ class CXXNewExpr : public Expr {
|
||||
// If this is an array allocation, does the usual deallocation
|
||||
// function for the allocated type want to know the allocated size?
|
||||
bool UsualArrayDeleteWantsSize : 1;
|
||||
// Whether the referred constructor (if any) was resolved from an
|
||||
// overload set having size greater than 1.
|
||||
bool HadMultipleCandidates : 1;
|
||||
// The number of placement new arguments.
|
||||
unsigned NumPlacementArgs : 14;
|
||||
unsigned NumPlacementArgs : 13;
|
||||
// The number of constructor arguments. This may be 1 even for non-class
|
||||
// types; use the pseudo copy constructor.
|
||||
unsigned NumConstructorArgs : 14;
|
||||
@ -1086,6 +1099,7 @@ class CXXNewExpr : public Expr {
|
||||
SourceRange TypeIdParens,
|
||||
Expr *arraySize, CXXConstructorDecl *constructor, bool initializer,
|
||||
Expr **constructorArgs, unsigned numConsArgs,
|
||||
bool HadMultipleCandidates,
|
||||
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
|
||||
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
|
||||
SourceLocation startLoc, SourceLocation endLoc,
|
||||
@ -1174,6 +1188,11 @@ class CXXNewExpr : public Expr {
|
||||
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
|
||||
}
|
||||
|
||||
/// \brief Whether the new expression refers a constructor that was
|
||||
/// resolved from an overloaded set having size greater than 1.
|
||||
bool hadMultipleCandidates() const { return HadMultipleCandidates; }
|
||||
void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; }
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
@ -1842,16 +1861,16 @@ class OverloadExpr : public Expr {
|
||||
/// template argument list, e.g. f<int>.
|
||||
bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
|
||||
|
||||
ExplicitTemplateArgumentList &getExplicitTemplateArgs(); // defined far below
|
||||
ASTTemplateArgumentListInfo &getExplicitTemplateArgs(); // defined far below
|
||||
|
||||
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
|
||||
return const_cast<OverloadExpr*>(this)->getExplicitTemplateArgs();
|
||||
}
|
||||
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
@ -1969,21 +1988,21 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
// nodes, users are *forbidden* from calling these methods on objects
|
||||
// without explicit template arguments.
|
||||
|
||||
ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
|
||||
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
|
||||
assert(hasExplicitTemplateArgs());
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList*>(this + 1);
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo*>(this + 1);
|
||||
}
|
||||
|
||||
/// Gets a reference to the explicit template argument list.
|
||||
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
|
||||
assert(hasExplicitTemplateArgs());
|
||||
return *reinterpret_cast<const ExplicitTemplateArgumentList*>(this + 1);
|
||||
return *reinterpret_cast<const ASTTemplateArgumentListInfo*>(this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
@ -2094,21 +2113,21 @@ class DependentScopeDeclRefExpr : public Expr {
|
||||
// nodes, users are *forbidden* from calling these methods on objects
|
||||
// without explicit template arguments.
|
||||
|
||||
ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
|
||||
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
|
||||
assert(hasExplicitTemplateArgs());
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList*>(this + 1);
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo*>(this + 1);
|
||||
}
|
||||
|
||||
/// Gets a reference to the explicit template argument list.
|
||||
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
|
||||
assert(hasExplicitTemplateArgs());
|
||||
return *reinterpret_cast<const ExplicitTemplateArgumentList*>(this + 1);
|
||||
return *reinterpret_cast<const ASTTemplateArgumentListInfo*>(this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
@ -2470,14 +2489,14 @@ class CXXDependentScopeMemberExpr : public Expr {
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name, if any.
|
||||
ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
|
||||
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
|
||||
assert(HasExplicitTemplateArgs);
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name, if any.
|
||||
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
|
||||
return const_cast<CXXDependentScopeMemberExpr *>(this)
|
||||
->getExplicitTemplateArgs();
|
||||
}
|
||||
@ -2485,7 +2504,7 @@ class CXXDependentScopeMemberExpr : public Expr {
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
@ -2663,22 +2682,22 @@ class UnresolvedMemberExpr : public OverloadExpr {
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name.
|
||||
ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
|
||||
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
|
||||
assert(hasExplicitTemplateArgs());
|
||||
return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
|
||||
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the explicit template argument list that followed the
|
||||
/// member template name, if any.
|
||||
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
|
||||
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
|
||||
assert(hasExplicitTemplateArgs());
|
||||
return *reinterpret_cast<const ExplicitTemplateArgumentList *>(this + 1);
|
||||
return *reinterpret_cast<const ASTTemplateArgumentListInfo *>(this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
|
||||
if (!hasExplicitTemplateArgs()) return 0;
|
||||
return &getExplicitTemplateArgs();
|
||||
}
|
||||
@ -2856,7 +2875,7 @@ class PackExpansionExpr : public Expr {
|
||||
}
|
||||
};
|
||||
|
||||
inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() {
|
||||
inline ASTTemplateArgumentListInfo &OverloadExpr::getExplicitTemplateArgs() {
|
||||
if (isa<UnresolvedLookupExpr>(this))
|
||||
return cast<UnresolvedLookupExpr>(this)->getExplicitTemplateArgs();
|
||||
else
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/SelectorLocationsKind.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
|
||||
namespace clang {
|
||||
@ -359,12 +360,12 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
QualType ArgType;
|
||||
if (isImplicitProperty()) {
|
||||
const ObjCMethodDecl *Setter = getImplicitPropertySetter();
|
||||
ObjCMethodDecl::param_iterator P = Setter->param_begin();
|
||||
ObjCMethodDecl::param_const_iterator P = Setter->param_begin();
|
||||
ArgType = (*P)->getType();
|
||||
} else {
|
||||
if (ObjCPropertyDecl *PDecl = getExplicitProperty())
|
||||
if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) {
|
||||
ObjCMethodDecl::param_iterator P = Setter->param_begin();
|
||||
ObjCMethodDecl::param_const_iterator P = Setter->param_begin();
|
||||
ArgType = (*P)->getType();
|
||||
}
|
||||
if (ArgType.isNull())
|
||||
@ -444,9 +445,21 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
/// class, and can be distinguished via \c getReceiverKind(). Example:
|
||||
///
|
||||
class ObjCMessageExpr : public Expr {
|
||||
/// \brief Stores either the selector that this message is sending
|
||||
/// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer
|
||||
/// referring to the method that we type-checked against.
|
||||
uintptr_t SelectorOrMethod;
|
||||
|
||||
enum { NumArgsBitWidth = 16 };
|
||||
|
||||
/// \brief The number of arguments in the message send, not
|
||||
/// including the receiver.
|
||||
unsigned NumArgs : 16;
|
||||
unsigned NumArgs : NumArgsBitWidth;
|
||||
|
||||
void setNumArgs(unsigned Num) {
|
||||
assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!");
|
||||
NumArgs = Num;
|
||||
}
|
||||
|
||||
/// \brief The kind of message send this is, which is one of the
|
||||
/// ReceiverKind values.
|
||||
@ -464,26 +477,24 @@ 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 the locations of the selector identifiers are in a
|
||||
/// "standard" position, a enum SelectorLocationsKind.
|
||||
unsigned SelLocsKind : 2;
|
||||
|
||||
/// \brief When the message expression is a send to 'super', this is
|
||||
/// the location of the 'super' keyword.
|
||||
SourceLocation SuperLoc;
|
||||
|
||||
/// \brief Stores either the selector that this message is sending
|
||||
/// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer
|
||||
/// referring to the method that we type-checked against.
|
||||
uintptr_t SelectorOrMethod;
|
||||
|
||||
/// \brief Location of the selector.
|
||||
SourceLocation SelectorLoc;
|
||||
|
||||
/// \brief The source locations of the open and close square
|
||||
/// brackets ('[' and ']', respectively).
|
||||
SourceLocation LBracLoc, RBracLoc;
|
||||
|
||||
ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
|
||||
: Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0),
|
||||
HasMethod(0), IsDelegateInitCall(0), SelectorOrMethod(0) { }
|
||||
: Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0),
|
||||
HasMethod(0), IsDelegateInitCall(0) {
|
||||
setNumArgs(NumArgs);
|
||||
}
|
||||
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
@ -491,27 +502,34 @@ class ObjCMessageExpr : public Expr {
|
||||
bool IsInstanceSuper,
|
||||
QualType SuperType,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
SelectorLocationsKind SelLocsK,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
TypeSourceInfo *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
SelectorLocationsKind SelLocsK,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
ObjCMessageExpr(QualType T, ExprValueKind VK,
|
||||
SourceLocation LBracLoc,
|
||||
Expr *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
SelectorLocationsKind SelLocsK,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
|
||||
void initArgsAndSelLocs(ArrayRef<Expr *> Args,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
SelectorLocationsKind SelLocsK);
|
||||
|
||||
/// \brief Retrieve the pointer value of the message receiver.
|
||||
void *getReceiverPointer() const {
|
||||
return *const_cast<void **>(
|
||||
@ -523,6 +541,40 @@ class ObjCMessageExpr : public Expr {
|
||||
*reinterpret_cast<void **>(this + 1) = Value;
|
||||
}
|
||||
|
||||
SelectorLocationsKind getSelLocsKind() const {
|
||||
return (SelectorLocationsKind)SelLocsKind;
|
||||
}
|
||||
bool hasStandardSelLocs() const {
|
||||
return getSelLocsKind() != SelLoc_NonStandard;
|
||||
}
|
||||
|
||||
/// \brief Get a pointer to the stored selector identifiers locations array.
|
||||
/// No locations will be stored if HasStandardSelLocs is true.
|
||||
SourceLocation *getStoredSelLocs() {
|
||||
return reinterpret_cast<SourceLocation*>(getArgs() + getNumArgs());
|
||||
}
|
||||
const SourceLocation *getStoredSelLocs() const {
|
||||
return reinterpret_cast<const SourceLocation*>(getArgs() + getNumArgs());
|
||||
}
|
||||
|
||||
/// \brief Get the number of stored selector identifiers locations.
|
||||
/// No locations will be stored if HasStandardSelLocs is true.
|
||||
unsigned getNumStoredSelLocs() const {
|
||||
if (hasStandardSelLocs())
|
||||
return 0;
|
||||
return getNumSelectorLocs();
|
||||
}
|
||||
|
||||
static ObjCMessageExpr *alloc(ASTContext &C,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBraceLoc,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
Selector Sel,
|
||||
SelectorLocationsKind &SelLocsK);
|
||||
static ObjCMessageExpr *alloc(ASTContext &C,
|
||||
unsigned NumArgs,
|
||||
unsigned NumStoredSelLocs);
|
||||
|
||||
public:
|
||||
/// \brief The kind of receiver this message is sending to.
|
||||
enum ReceiverKind {
|
||||
@ -570,9 +622,9 @@ class ObjCMessageExpr : public Expr {
|
||||
bool IsInstanceSuper,
|
||||
QualType SuperType,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
|
||||
/// \brief Create a class message send.
|
||||
@ -605,9 +657,9 @@ class ObjCMessageExpr : public Expr {
|
||||
SourceLocation LBracLoc,
|
||||
TypeSourceInfo *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
|
||||
/// \brief Create an instance message send.
|
||||
@ -640,9 +692,9 @@ class ObjCMessageExpr : public Expr {
|
||||
SourceLocation LBracLoc,
|
||||
Expr *Receiver,
|
||||
Selector Sel,
|
||||
SourceLocation SelLoc,
|
||||
ArrayRef<SourceLocation> SeLocs,
|
||||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RBracLoc);
|
||||
|
||||
/// \brief Create an empty Objective-C message expression, to be
|
||||
@ -652,7 +704,9 @@ class ObjCMessageExpr : public Expr {
|
||||
///
|
||||
/// \param NumArgs The number of message arguments, not including
|
||||
/// the receiver.
|
||||
static ObjCMessageExpr *CreateEmpty(ASTContext &Context, unsigned NumArgs);
|
||||
static ObjCMessageExpr *CreateEmpty(ASTContext &Context,
|
||||
unsigned NumArgs,
|
||||
unsigned NumStoredSelLocs);
|
||||
|
||||
/// \brief Determine the kind of receiver that this message is being
|
||||
/// sent to.
|
||||
@ -822,7 +876,27 @@ class ObjCMessageExpr : public Expr {
|
||||
|
||||
SourceLocation getLeftLoc() const { return LBracLoc; }
|
||||
SourceLocation getRightLoc() const { return RBracLoc; }
|
||||
SourceLocation getSelectorLoc() const { return SelectorLoc; }
|
||||
|
||||
SourceLocation getSelectorStartLoc() const { return getSelectorLoc(0); }
|
||||
SourceLocation getSelectorLoc(unsigned Index) const {
|
||||
assert(Index < getNumSelectorLocs() && "Index out of range!");
|
||||
if (hasStandardSelLocs())
|
||||
return getStandardSelectorLoc(Index, getSelector(),
|
||||
getSelLocsKind() == SelLoc_StandardWithSpace,
|
||||
llvm::makeArrayRef(const_cast<Expr**>(getArgs()),
|
||||
getNumArgs()),
|
||||
RBracLoc);
|
||||
return getStoredSelLocs()[Index];
|
||||
}
|
||||
|
||||
void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const;
|
||||
|
||||
unsigned getNumSelectorLocs() const {
|
||||
Selector Sel = getSelector();
|
||||
if (Sel.isUnarySelector())
|
||||
return 1;
|
||||
return Sel.getNumArgs();
|
||||
}
|
||||
|
||||
void setSourceRange(SourceRange R) {
|
||||
LBracLoc = R.getBegin();
|
||||
@ -989,10 +1063,10 @@ class ObjCBridgedCastExpr : public ExplicitCastExpr {
|
||||
|
||||
public:
|
||||
ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind,
|
||||
SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo,
|
||||
Expr *Operand)
|
||||
CastKind CK, SourceLocation BridgeKeywordLoc,
|
||||
TypeSourceInfo *TSInfo, Expr *Operand)
|
||||
: ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue,
|
||||
CK_BitCast, Operand, 0, TSInfo),
|
||||
CK, Operand, 0, TSInfo),
|
||||
LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { }
|
||||
|
||||
/// \brief Construct an empty Objective-C bridged cast.
|
||||
@ -1007,7 +1081,7 @@ class ObjCBridgedCastExpr : public ExplicitCastExpr {
|
||||
}
|
||||
|
||||
/// \brief Retrieve the kind of bridge being performed as a string.
|
||||
llvm::StringRef getBridgeKindName() const;
|
||||
StringRef getBridgeKindName() const;
|
||||
|
||||
/// \brief The location of the bridge keyword.
|
||||
SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; }
|
||||
|
@ -15,11 +15,6 @@
|
||||
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
template <class T> class SmallVectorImpl;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -129,16 +124,6 @@ class ExternalASTSource {
|
||||
virtual DeclContextLookupResult
|
||||
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
|
||||
|
||||
/// \brief Deserialize all the visible declarations from external storage.
|
||||
///
|
||||
/// Name lookup deserializes visible declarations lazily, thus a DeclContext
|
||||
/// may not have a complete name lookup table. This function deserializes
|
||||
/// the rest of visible declarations from the external storage and completes
|
||||
/// the name lookup table of the DeclContext.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual void MaterializeVisibleDecls(const DeclContext *DC);
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext, after applying an optional filter predicate.
|
||||
///
|
||||
@ -151,20 +136,20 @@ class ExternalASTSource {
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
|
||||
bool (*isKindWeWant)(Decl::Kind),
|
||||
llvm::SmallVectorImpl<Decl*> &Result);
|
||||
SmallVectorImpl<Decl*> &Result);
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext.
|
||||
///
|
||||
/// \return true if an error occurred
|
||||
ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
|
||||
llvm::SmallVectorImpl<Decl*> &Result) {
|
||||
SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, 0, Result);
|
||||
}
|
||||
|
||||
template <typename DeclTy>
|
||||
ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC,
|
||||
llvm::SmallVectorImpl<Decl*> &Result) {
|
||||
SmallVectorImpl<Decl*> &Result) {
|
||||
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
|
||||
}
|
||||
|
||||
@ -231,15 +216,11 @@ class ExternalASTSource {
|
||||
static DeclContextLookupResult
|
||||
SetExternalVisibleDeclsForName(const DeclContext *DC,
|
||||
DeclarationName Name,
|
||||
llvm::SmallVectorImpl<NamedDecl*> &Decls);
|
||||
ArrayRef<NamedDecl*> Decls);
|
||||
|
||||
static DeclContextLookupResult
|
||||
SetNoExternalVisibleDeclsForName(const DeclContext *DC,
|
||||
DeclarationName Name);
|
||||
|
||||
void MaterializeVisibleDeclsForName(const DeclContext *DC,
|
||||
DeclarationName Name,
|
||||
llvm::SmallVectorImpl<NamedDecl*> &Decls);
|
||||
};
|
||||
|
||||
/// \brief A lazy pointer to an AST node (of base type T) that resides
|
||||
@ -305,6 +286,178 @@ struct LazyOffsetPtr {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a lazily-loaded vector of data.
|
||||
///
|
||||
/// The lazily-loaded vector of data contains data that is partially loaded
|
||||
/// from an external source and partially added by local translation. The
|
||||
/// items loaded from the external source are loaded lazily, when needed for
|
||||
/// iteration over the complete vector.
|
||||
template<typename T, typename Source,
|
||||
void (Source::*Loader)(SmallVectorImpl<T>&),
|
||||
unsigned LoadedStorage = 2, unsigned LocalStorage = 4>
|
||||
class LazyVector {
|
||||
SmallVector<T, LoadedStorage> Loaded;
|
||||
SmallVector<T, LocalStorage> Local;
|
||||
|
||||
public:
|
||||
// Iteration over the elements in the vector.
|
||||
class iterator {
|
||||
LazyVector *Self;
|
||||
|
||||
/// \brief Position within the vector..
|
||||
///
|
||||
/// In a complete iteration, the Position field walks the range [-M, N),
|
||||
/// where negative values are used to indicate elements
|
||||
/// loaded from the external source while non-negative values are used to
|
||||
/// indicate elements added via \c push_back().
|
||||
/// However, to provide iteration in source order (for, e.g., chained
|
||||
/// precompiled headers), dereferencing the iterator flips the negative
|
||||
/// values (corresponding to loaded entities), so that position -M
|
||||
/// corresponds to element 0 in the loaded entities vector, position -M+1
|
||||
/// corresponds to element 1 in the loaded entities vector, etc. This
|
||||
/// gives us a reasonably efficient, source-order walk.
|
||||
int Position;
|
||||
|
||||
friend class LazyVector;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef int difference_type;
|
||||
|
||||
iterator() : Self(0), Position(0) { }
|
||||
|
||||
iterator(LazyVector *Self, int Position)
|
||||
: Self(Self), Position(Position) { }
|
||||
|
||||
reference operator*() const {
|
||||
if (Position < 0)
|
||||
return Self->Loaded.end()[Position];
|
||||
return Self->Local[Position];
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
if (Position < 0)
|
||||
return &Self->Loaded.end()[Position];
|
||||
|
||||
return &Self->Local[Position];
|
||||
}
|
||||
|
||||
reference operator[](difference_type D) {
|
||||
return *(*this + D);
|
||||
}
|
||||
|
||||
iterator &operator++() {
|
||||
++Position;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) {
|
||||
iterator Prev(*this);
|
||||
++Position;
|
||||
return Prev;
|
||||
}
|
||||
|
||||
iterator &operator--() {
|
||||
--Position;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator--(int) {
|
||||
iterator Prev(*this);
|
||||
--Position;
|
||||
return Prev;
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator &X, const iterator &Y) {
|
||||
return X.Position == Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator!=(const iterator &X, const iterator &Y) {
|
||||
return X.Position != Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator<(const iterator &X, const iterator &Y) {
|
||||
return X.Position < Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator>(const iterator &X, const iterator &Y) {
|
||||
return X.Position > Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator<=(const iterator &X, const iterator &Y) {
|
||||
return X.Position < Y.Position;
|
||||
}
|
||||
|
||||
friend bool operator>=(const iterator &X, const iterator &Y) {
|
||||
return X.Position > Y.Position;
|
||||
}
|
||||
|
||||
friend iterator& operator+=(iterator &X, difference_type D) {
|
||||
X.Position += D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend iterator& operator-=(iterator &X, difference_type D) {
|
||||
X.Position -= D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend iterator operator+(iterator X, difference_type D) {
|
||||
X.Position += D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend iterator operator+(difference_type D, iterator X) {
|
||||
X.Position += D;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend difference_type operator-(const iterator &X, const iterator &Y) {
|
||||
return X.Position - Y.Position;
|
||||
}
|
||||
|
||||
friend iterator operator-(iterator X, difference_type D) {
|
||||
X.Position -= D;
|
||||
return X;
|
||||
}
|
||||
};
|
||||
friend class iterator;
|
||||
|
||||
iterator begin(Source *source, bool LocalOnly = false) {
|
||||
if (LocalOnly)
|
||||
return iterator(this, 0);
|
||||
|
||||
if (source)
|
||||
(source->*Loader)(Loaded);
|
||||
return iterator(this, -(int)Loaded.size());
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return iterator(this, Local.size());
|
||||
}
|
||||
|
||||
void push_back(const T& LocalValue) {
|
||||
Local.push_back(LocalValue);
|
||||
}
|
||||
|
||||
void erase(iterator From, iterator To) {
|
||||
if (From.Position < 0 && To.Position < 0) {
|
||||
Loaded.erase(Loaded.end() + From.Position, Loaded.end() + To.Position);
|
||||
return;
|
||||
}
|
||||
|
||||
if (From.Position < 0) {
|
||||
Loaded.erase(Loaded.end() + From.Position, Loaded.end());
|
||||
From = begin(0, true);
|
||||
}
|
||||
|
||||
Local.erase(Local.begin() + From.Position, Local.begin() + To.Position);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A lazy pointer to a statement.
|
||||
typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
|
||||
LazyDeclStmtPtr;
|
||||
|
@ -6,24 +6,24 @@ TABLEGEN_INC_FILES_COMMON = 1
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
$(ObjDir)/Attrs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
|
||||
$(ObjDir)/Attrs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang attribute classes with tblgen"
|
||||
$(Verb) $(TableGen) -gen-clang-attr-classes -o $(call SYSPATH, $@) \
|
||||
$(Verb) $(ClangTableGen) -gen-clang-attr-classes -o $(call SYSPATH, $@) \
|
||||
-I $(PROJ_SRC_DIR)/../../ $<
|
||||
|
||||
$(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
|
||||
$(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang attribute implementations with tblgen"
|
||||
$(Verb) $(TableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \
|
||||
$(Verb) $(ClangTableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \
|
||||
-I $(PROJ_SRC_DIR)/../../ $<
|
||||
|
||||
$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(TBLGEN) \
|
||||
$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang statement node tables with tblgen"
|
||||
$(Verb) $(TableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $<
|
||||
$(Verb) $(ClangTableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(ObjDir)/DeclNodes.inc.tmp : $(TD_SRC_DIR)/DeclNodes.td $(TBLGEN) \
|
||||
$(ObjDir)/DeclNodes.inc.tmp : $(TD_SRC_DIR)/DeclNodes.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang declaration node tables with tblgen"
|
||||
$(Verb) $(TableGen) -gen-clang-decl-nodes -o $(call SYSPATH, $@) $<
|
||||
$(Verb) $(ClangTableGen) -gen-clang-decl-nodes -o $(call SYSPATH, $@) $<
|
||||
|
@ -39,25 +39,25 @@ namespace clang {
|
||||
/// external memory ownership.
|
||||
class MangleBuffer {
|
||||
public:
|
||||
void setString(llvm::StringRef Ref) {
|
||||
void setString(StringRef Ref) {
|
||||
String = Ref;
|
||||
}
|
||||
|
||||
llvm::SmallVectorImpl<char> &getBuffer() {
|
||||
SmallVectorImpl<char> &getBuffer() {
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
llvm::StringRef getString() const {
|
||||
StringRef getString() const {
|
||||
if (!String.empty()) return String;
|
||||
return Buffer.str();
|
||||
}
|
||||
|
||||
operator llvm::StringRef() const {
|
||||
operator StringRef() const {
|
||||
return getString();
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::StringRef String;
|
||||
StringRef String;
|
||||
llvm::SmallString<256> Buffer;
|
||||
};
|
||||
|
||||
@ -65,21 +65,21 @@ class MangleBuffer {
|
||||
/// calls to the C++ name mangler.
|
||||
class MangleContext {
|
||||
ASTContext &Context;
|
||||
Diagnostic &Diags;
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
|
||||
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
|
||||
|
||||
public:
|
||||
explicit MangleContext(ASTContext &Context,
|
||||
Diagnostic &Diags)
|
||||
DiagnosticsEngine &Diags)
|
||||
: Context(Context), Diags(Diags) { }
|
||||
|
||||
virtual ~MangleContext() { }
|
||||
|
||||
ASTContext &getASTContext() const { return Context; }
|
||||
|
||||
Diagnostic &getDiags() const { return Diags; }
|
||||
DiagnosticsEngine &getDiags() const { return Diags; }
|
||||
|
||||
virtual void startNewFunction() { LocalBlockIds.clear(); }
|
||||
|
||||
@ -95,55 +95,55 @@ class MangleContext {
|
||||
/// @{
|
||||
|
||||
virtual bool shouldMangleDeclName(const NamedDecl *D) = 0;
|
||||
virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &)=0;
|
||||
virtual void mangleName(const NamedDecl *D, raw_ostream &)=0;
|
||||
virtual void mangleThunk(const CXXMethodDecl *MD,
|
||||
const ThunkInfo &Thunk,
|
||||
llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
|
||||
const ThisAdjustment &ThisAdjustment,
|
||||
llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleReferenceTemporary(const VarDecl *D,
|
||||
llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
|
||||
llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
|
||||
llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
|
||||
const CXXRecordDecl *Type,
|
||||
llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
|
||||
llvm::raw_ostream &) = 0;
|
||||
raw_ostream &) = 0;
|
||||
|
||||
void mangleGlobalBlock(const BlockDecl *BD,
|
||||
llvm::raw_ostream &Out);
|
||||
raw_ostream &Out);
|
||||
void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT,
|
||||
const BlockDecl *BD, llvm::raw_ostream &Out);
|
||||
const BlockDecl *BD, raw_ostream &Out);
|
||||
void mangleDtorBlock(const CXXDestructorDecl *CD, CXXDtorType DT,
|
||||
const BlockDecl *BD, llvm::raw_ostream &Out);
|
||||
const BlockDecl *BD, raw_ostream &Out);
|
||||
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
||||
llvm::raw_ostream &Out);
|
||||
raw_ostream &Out);
|
||||
// Do the right thing.
|
||||
void mangleBlock(const BlockDecl *BD, llvm::raw_ostream &Out);
|
||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out);
|
||||
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD,
|
||||
llvm::raw_ostream &);
|
||||
raw_ostream &);
|
||||
|
||||
// This is pretty lame.
|
||||
virtual void mangleItaniumGuardVariable(const VarDecl *D,
|
||||
llvm::raw_ostream &) {
|
||||
assert(0 && "Target does not support mangling guard variables");
|
||||
raw_ostream &) {
|
||||
llvm_unreachable("Target does not support mangling guard variables");
|
||||
}
|
||||
/// @}
|
||||
};
|
||||
|
||||
MangleContext *createItaniumMangleContext(ASTContext &Context,
|
||||
Diagnostic &Diags);
|
||||
DiagnosticsEngine &Diags);
|
||||
MangleContext *createMicrosoftMangleContext(ASTContext &Context,
|
||||
Diagnostic &Diags);
|
||||
DiagnosticsEngine &Diags);
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,6 @@
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
@ -196,7 +192,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
|
||||
/// \brief Print this nested name specifier to the given output
|
||||
/// stream.
|
||||
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddPointer(Prefix.getOpaqueValue());
|
||||
@ -469,7 +465,7 @@ class NestedNameSpecifierLocBuilder {
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
NestedNameSpecifier *NNS) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
|
||||
Diagnostic::ak_nestednamespec);
|
||||
DiagnosticsEngine::ak_nestednamespec);
|
||||
return DB;
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,12 @@ enum CastKind {
|
||||
/// to be reinterpreted as a bit pattern of another type. Generally
|
||||
/// the operands must have equivalent size and unrelated types.
|
||||
///
|
||||
/// The pointer conversion char* -> int* is a bitcast. Many other
|
||||
/// pointer conversions which are "physically" bitcasts are given
|
||||
/// special cast kinds.
|
||||
/// The pointer conversion char* -> int* is a bitcast. A conversion
|
||||
/// from any pointer type to a C pointer type is a bitcast unless
|
||||
/// it's actually BaseToDerived or DerivedToBase. A conversion to a
|
||||
/// block pointer or ObjC pointer type is a bitcast only if the
|
||||
/// operand has the same type kind; otherwise, it's one of the
|
||||
/// specialized casts below.
|
||||
///
|
||||
/// Vector coercions are bitcasts.
|
||||
CK_BitCast,
|
||||
@ -186,12 +189,16 @@ enum CastKind {
|
||||
/// (float) ld
|
||||
CK_FloatingCast,
|
||||
|
||||
/// CK_AnyPointerToObjCPointerCast - Casting any other pointer kind
|
||||
/// to an Objective-C pointer.
|
||||
CK_AnyPointerToObjCPointerCast,
|
||||
/// CK_CPointerToObjCPointerCast - Casting a C pointer kind to an
|
||||
/// Objective-C pointer.
|
||||
CK_CPointerToObjCPointerCast,
|
||||
|
||||
/// CK_AnyPointerToBlockPointerCast - Casting any other pointer kind
|
||||
/// to a block pointer.
|
||||
/// CK_BlockPointerToObjCPointerCast - Casting a block pointer to an
|
||||
/// ObjC pointer.
|
||||
CK_BlockPointerToObjCPointerCast,
|
||||
|
||||
/// CK_AnyPointerToBlockPointerCast - Casting any non-block pointer
|
||||
/// to a block pointer. Block-to-block casts are bitcasts.
|
||||
CK_AnyPointerToBlockPointerCast,
|
||||
|
||||
/// \brief Converting between two Objective-C object types, which
|
||||
@ -247,20 +254,27 @@ enum CastKind {
|
||||
/// _Complex unsigned -> _Complex float
|
||||
CK_IntegralComplexToFloatingComplex,
|
||||
|
||||
/// \brief Produces a retainable object pointer so that it may be
|
||||
/// consumed, e.g. by being passed to a consuming parameter. Calls
|
||||
/// objc_retain.
|
||||
CK_ObjCProduceObject,
|
||||
/// \brief [ARC] Produces a retainable object pointer so that it may
|
||||
/// be consumed, e.g. by being passed to a consuming parameter.
|
||||
/// Calls objc_retain.
|
||||
CK_ARCProduceObject,
|
||||
|
||||
/// \brief Consumes a retainable object pointer that has just been
|
||||
/// produced, e.g. as the return value of a retaining call. Enters
|
||||
/// a cleanup to call objc_release at some indefinite time.
|
||||
CK_ObjCConsumeObject,
|
||||
/// \brief [ARC] Consumes a retainable object pointer that has just
|
||||
/// been produced, e.g. as the return value of a retaining call.
|
||||
/// Enters a cleanup to call objc_release at some indefinite time.
|
||||
CK_ARCConsumeObject,
|
||||
|
||||
/// \brief Reclaim a retainable object pointer object that may have
|
||||
/// been produced and autoreleased as part of a function return
|
||||
/// \brief [ARC] Reclaim a retainable object pointer object that may
|
||||
/// have been produced and autoreleased as part of a function return
|
||||
/// sequence.
|
||||
CK_ObjCReclaimReturnedObject
|
||||
CK_ARCReclaimReturnedObject,
|
||||
|
||||
/// \brief [ARC] Causes a value of block type to be copied to the
|
||||
/// heap, if it is not already there. A number of other operations
|
||||
/// 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
|
||||
};
|
||||
|
||||
#define CK_Invalid ((CastKind) -1)
|
||||
|
@ -32,6 +32,7 @@ class ParentMap {
|
||||
Stmt *getParent(Stmt*) const;
|
||||
Stmt *getParentIgnoreParens(Stmt *) const;
|
||||
Stmt *getParentIgnoreParenCasts(Stmt *) const;
|
||||
Stmt *getParentIgnoreParenImpCasts(Stmt *) const;
|
||||
Stmt *getOuterParenParent(Stmt *) const;
|
||||
|
||||
const Stmt *getParent(const Stmt* S) const {
|
||||
|
@ -15,10 +15,7 @@
|
||||
#define LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -29,7 +26,7 @@ class LangOptions;
|
||||
class PrinterHelper {
|
||||
public:
|
||||
virtual ~PrinterHelper();
|
||||
virtual bool handledStmt(Stmt* E, llvm::raw_ostream& OS) = 0;
|
||||
virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0;
|
||||
};
|
||||
|
||||
/// \brief Describes how types, statements, expressions, and
|
||||
@ -41,13 +38,14 @@ struct PrintingPolicy {
|
||||
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
|
||||
SuppressInitializers(false),
|
||||
Dump(false), ConstantArraySizeAsWritten(false),
|
||||
AnonymousTagLocations(true), SuppressStrongLifetime(false) { }
|
||||
AnonymousTagLocations(true), SuppressStrongLifetime(false),
|
||||
Bool(LO.Bool) { }
|
||||
|
||||
/// \brief The number of spaces to use to indent each line.
|
||||
unsigned Indentation : 8;
|
||||
|
||||
/// \brief What language we're printing.
|
||||
const LangOptions LangOpts;
|
||||
LangOptions LangOpts;
|
||||
|
||||
/// \brief Whether we should suppress printing of the actual specifiers for
|
||||
/// the given type or declaration.
|
||||
@ -133,6 +131,10 @@ struct PrintingPolicy {
|
||||
/// \brief When true, suppress printing of the __strong lifetime qualifier in
|
||||
/// ARC.
|
||||
unsigned SuppressStrongLifetime : 1;
|
||||
|
||||
/// \brief Whether we can use 'bool' rather than '_Bool', even if the language
|
||||
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
|
||||
unsigned Bool : 1;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -63,6 +63,9 @@ class ASTRecordLayout {
|
||||
/// any empty subobjects.
|
||||
CharUnits SizeOfLargestEmptySubobject;
|
||||
|
||||
/// VBPtrOffset - Virtual base table offset.
|
||||
CharUnits VBPtrOffset;
|
||||
|
||||
/// PrimaryBase - The primary base info for this record.
|
||||
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
|
||||
|
||||
@ -89,7 +92,8 @@ class ASTRecordLayout {
|
||||
// Constructor for C++ records.
|
||||
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
|
||||
ASTRecordLayout(const ASTContext &Ctx,
|
||||
CharUnits size, CharUnits alignment, CharUnits datasize,
|
||||
CharUnits size, CharUnits alignment, CharUnits vbptroffset,
|
||||
CharUnits datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
|
||||
CharUnits SizeOfLargestEmptySubobject,
|
||||
@ -199,6 +203,10 @@ class ASTRecordLayout {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->SizeOfLargestEmptySubobject;
|
||||
}
|
||||
|
||||
CharUnits getVBPtrOffset() const {
|
||||
return CXXInfo->VBPtrOffset;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -813,6 +813,10 @@ DEF_TRAVERSE_TYPE(ObjCObjectPointerType, {
|
||||
TRY_TO(TraverseType(T->getPointeeType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AtomicType, {
|
||||
TRY_TO(TraverseType(T->getValueType()));
|
||||
})
|
||||
|
||||
#undef DEF_TRAVERSE_TYPE
|
||||
|
||||
// ----------------- TypeLoc traversal -----------------
|
||||
@ -1041,6 +1045,10 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(AtomicType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getValueLoc()));
|
||||
})
|
||||
|
||||
#undef DEF_TRAVERSE_TYPELOC
|
||||
|
||||
// ----------------- Decl traversal -----------------
|
||||
@ -1114,6 +1122,10 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
|
||||
TRY_TO(TraverseDecl(D->getSpecialization()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCClassDecl, {
|
||||
@ -1252,7 +1264,7 @@ bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
|
||||
= (U.get<ClassTemplatePartialSpecializationDecl*>() == Pattern);
|
||||
|
||||
if (ShouldVisit)
|
||||
TRY_TO(TraverseClassTemplateSpecializationDecl(SD));
|
||||
TRY_TO(TraverseDecl(SD));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1280,7 +1292,7 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
|
||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
|
||||
// By default, we do not traverse the instantiations of
|
||||
// class templates since they do not apprear in the user code. The
|
||||
// class templates since they do not appear in the user code. The
|
||||
// following code optionally traverses them.
|
||||
if (getDerived().shouldVisitTemplateInstantiations()) {
|
||||
// If this is the definition of the primary template, visit
|
||||
@ -1318,7 +1330,7 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
||||
case TSK_ExplicitSpecialization:
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unknown specialization kind.");
|
||||
llvm_unreachable("Unknown specialization kind.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1548,10 +1560,10 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
|
||||
FTSI->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
|
||||
// A specialization might not have explicit template arguments if it has
|
||||
// a templated return type and concrete arguments.
|
||||
if (const TemplateArgumentListInfo *TALI =
|
||||
if (const ASTTemplateArgumentListInfo *TALI =
|
||||
FTSI->TemplateArgumentsAsWritten) {
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getArgumentArray(),
|
||||
TALI->size()));
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(),
|
||||
TALI->NumTemplateArgs));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1980,6 +1992,7 @@ DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
|
||||
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
|
||||
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
|
||||
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
|
||||
DEF_TRAVERSE_STMT(AtomicExpr, { })
|
||||
|
||||
// These literals (all of them) do not need any action.
|
||||
DEF_TRAVERSE_STMT(IntegerLiteral, { })
|
||||
|
83
include/clang/AST/SelectorLocationsKind.h
Normal file
83
include/clang/AST/SelectorLocationsKind.h
Normal file
@ -0,0 +1,83 @@
|
||||
//===--- SelectorLocationsKind.h - Kind of selector locations ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Describes whether the identifier locations for a selector are "standard"
|
||||
// or not.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H
|
||||
#define LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
namespace clang {
|
||||
class Selector;
|
||||
class SourceLocation;
|
||||
class Expr;
|
||||
class ParmVarDecl;
|
||||
|
||||
/// \brief Whether all locations of the selector identifiers are in a
|
||||
/// "standard" position.
|
||||
enum SelectorLocationsKind {
|
||||
/// \brief Non-standard.
|
||||
SelLoc_NonStandard = 0,
|
||||
|
||||
/// \brief For nullary selectors, immediately before the end:
|
||||
/// "[foo release]" / "-(void)release;"
|
||||
/// Or immediately before the arguments:
|
||||
/// "[foo first:1 second:2]" / "-(id)first:(int)x second:(int)y;
|
||||
SelLoc_StandardNoSpace = 1,
|
||||
|
||||
/// \brief For nullary selectors, immediately before the end:
|
||||
/// "[foo release]" / "-(void)release;"
|
||||
/// Or with a space between the arguments:
|
||||
/// "[foo first: 1 second: 2]" / "-(id)first: (int)x second: (int)y;
|
||||
SelLoc_StandardWithSpace = 2
|
||||
};
|
||||
|
||||
/// \brief Returns true if all \arg SelLocs are in a "standard" location.
|
||||
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// \brief Get the "standard" location of a selector identifier, e.g:
|
||||
/// For nullary selectors, immediately before ']': "[foo release]"
|
||||
///
|
||||
/// \param WithArgSpace if true the standard location is with a space apart
|
||||
/// before arguments: "[foo first: 1 second: 2]"
|
||||
/// If false: "[foo first:1 second:2]"
|
||||
SourceLocation getStandardSelectorLoc(unsigned Index,
|
||||
Selector Sel,
|
||||
bool WithArgSpace,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// \brief Returns true if all \arg SelLocs are in a "standard" location.
|
||||
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
ArrayRef<ParmVarDecl *> Args,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// \brief Get the "standard" location of a selector identifier, e.g:
|
||||
/// For nullary selectors, immediately before ']': "[foo release]"
|
||||
///
|
||||
/// \param WithArgSpace if true the standard location is with a space apart
|
||||
/// before arguments: "-(id)first: (int)x second: (int)y;"
|
||||
/// If false: "-(id)first:(int)x second:(int)y;"
|
||||
SourceLocation getStandardSelectorLoc(unsigned Index,
|
||||
Selector Sel,
|
||||
bool WithArgSpace,
|
||||
ArrayRef<ParmVarDecl *> Args,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -14,16 +14,15 @@
|
||||
#ifndef LLVM_CLANG_AST_STMT_H
|
||||
#define LLVM_CLANG_AST_STMT_H
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <string>
|
||||
using llvm::dyn_cast_or_null;
|
||||
|
||||
namespace llvm {
|
||||
class FoldingSetNodeID;
|
||||
@ -108,11 +107,10 @@ class Stmt {
|
||||
// Make vanilla 'new' and 'delete' illegal for Stmts.
|
||||
protected:
|
||||
void* operator new(size_t bytes) throw() {
|
||||
assert(0 && "Stmts cannot be allocated with regular 'new'.");
|
||||
return 0;
|
||||
llvm_unreachable("Stmts cannot be allocated with regular 'new'.");
|
||||
}
|
||||
void operator delete(void* data) throw() {
|
||||
assert(0 && "Stmts cannot be released with regular 'delete'.");
|
||||
llvm_unreachable("Stmts cannot be released with regular 'delete'.");
|
||||
}
|
||||
|
||||
class StmtBitfields {
|
||||
@ -148,6 +146,7 @@ class Stmt {
|
||||
friend class CXXUnresolvedConstructExpr; // ctor
|
||||
friend class CXXDependentScopeMemberExpr; // ctor
|
||||
friend class OverloadExpr; // ctor
|
||||
friend class AtomicExpr; // ctor
|
||||
unsigned : NumStmtBits;
|
||||
|
||||
unsigned ValueKind : 2;
|
||||
@ -167,6 +166,7 @@ class Stmt {
|
||||
unsigned HasQualifier : 1;
|
||||
unsigned HasExplicitTemplateArgs : 1;
|
||||
unsigned HasFoundDecl : 1;
|
||||
unsigned HadMultipleCandidates : 1;
|
||||
};
|
||||
|
||||
class CastExprBitfields {
|
||||
@ -270,7 +270,7 @@ class Stmt {
|
||||
/// This is useful in a debugger.
|
||||
void dump() const;
|
||||
void dump(SourceManager &SM) const;
|
||||
void dump(llvm::raw_ostream &OS, SourceManager &SM) const;
|
||||
void dump(raw_ostream &OS, SourceManager &SM) const;
|
||||
|
||||
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
|
||||
void dumpAll() const;
|
||||
@ -279,12 +279,12 @@ class Stmt {
|
||||
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
|
||||
/// back to its original source language syntax.
|
||||
void dumpPretty(ASTContext& Context) const;
|
||||
void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper,
|
||||
void printPretty(raw_ostream &OS, PrinterHelper *Helper,
|
||||
const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0) const {
|
||||
printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation);
|
||||
}
|
||||
void printPretty(llvm::raw_ostream &OS, ASTContext &Context,
|
||||
void printPretty(raw_ostream &OS, ASTContext &Context,
|
||||
PrinterHelper *Helper,
|
||||
const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0) const;
|
||||
@ -297,6 +297,12 @@ class Stmt {
|
||||
/// statement, such as ExprWithCleanups or ImplicitCastExpr nodes.
|
||||
Stmt *IgnoreImplicit();
|
||||
|
||||
const Stmt *stripLabelLikeStatements() const;
|
||||
Stmt *stripLabelLikeStatements() {
|
||||
return const_cast<Stmt*>(
|
||||
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static bool classof(const Stmt *) { return true; }
|
||||
|
||||
@ -407,25 +413,25 @@ class DeclStmt : public Stmt {
|
||||
class NullStmt : public Stmt {
|
||||
SourceLocation SemiLoc;
|
||||
|
||||
/// \brief If the null statement was preceded by an empty macro this is
|
||||
/// its instantiation source location, e.g:
|
||||
/// \brief True if the null statement was preceded by an empty macro, e.g:
|
||||
/// @code
|
||||
/// #define CALL(x)
|
||||
/// CALL(0);
|
||||
/// @endcode
|
||||
SourceLocation LeadingEmptyMacro;
|
||||
bool HasLeadingEmptyMacro;
|
||||
public:
|
||||
NullStmt(SourceLocation L, SourceLocation LeadingEmptyMacro =SourceLocation())
|
||||
: Stmt(NullStmtClass), SemiLoc(L), LeadingEmptyMacro(LeadingEmptyMacro) {}
|
||||
NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false)
|
||||
: Stmt(NullStmtClass), SemiLoc(L),
|
||||
HasLeadingEmptyMacro(hasLeadingEmptyMacro) {}
|
||||
|
||||
/// \brief Build an empty null statement.
|
||||
explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { }
|
||||
explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty),
|
||||
HasLeadingEmptyMacro(false) { }
|
||||
|
||||
SourceLocation getSemiLoc() const { return SemiLoc; }
|
||||
void setSemiLoc(SourceLocation L) { SemiLoc = L; }
|
||||
|
||||
bool hasLeadingEmptyMacro() const { return LeadingEmptyMacro.isValid(); }
|
||||
SourceLocation getLeadingEmptyMacroLoc() const { return LeadingEmptyMacro; }
|
||||
bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; }
|
||||
|
||||
SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
|
||||
|
||||
@ -525,6 +531,10 @@ class CompoundStmt : public Stmt {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// SwitchCase is the base class for CaseStmt and DefaultStmt,
|
||||
@ -1308,7 +1318,7 @@ class AsmStmt : public Stmt {
|
||||
/// true, otherwise return false. This handles canonicalization and
|
||||
/// translation of strings from GCC syntax to LLVM IR syntax, and handles
|
||||
//// flattening of named references like %[foo] to Operand AsmStringPiece's.
|
||||
unsigned AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece> &Pieces,
|
||||
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
|
||||
ASTContext &C, unsigned &DiagOffs) const;
|
||||
|
||||
|
||||
@ -1320,17 +1330,17 @@ class AsmStmt : public Stmt {
|
||||
return Names[i];
|
||||
}
|
||||
|
||||
llvm::StringRef getOutputName(unsigned i) const {
|
||||
StringRef getOutputName(unsigned i) const {
|
||||
if (IdentifierInfo *II = getOutputIdentifier(i))
|
||||
return II->getName();
|
||||
|
||||
return llvm::StringRef();
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
/// getOutputConstraint - Return the constraint string for the specified
|
||||
/// output operand. All output constraints are known to be non-empty (either
|
||||
/// '=' or '+').
|
||||
llvm::StringRef getOutputConstraint(unsigned i) const;
|
||||
StringRef getOutputConstraint(unsigned i) const;
|
||||
|
||||
const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
|
||||
return Constraints[i];
|
||||
@ -1364,16 +1374,16 @@ class AsmStmt : public Stmt {
|
||||
return Names[i + NumOutputs];
|
||||
}
|
||||
|
||||
llvm::StringRef getInputName(unsigned i) const {
|
||||
StringRef getInputName(unsigned i) const {
|
||||
if (IdentifierInfo *II = getInputIdentifier(i))
|
||||
return II->getName();
|
||||
|
||||
return llvm::StringRef();
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
/// getInputConstraint - Return the specified input constraint. Unlike output
|
||||
/// constraints, these can be empty.
|
||||
llvm::StringRef getInputConstraint(unsigned i) const;
|
||||
StringRef getInputConstraint(unsigned i) const;
|
||||
|
||||
const StringLiteral *getInputConstraintLiteral(unsigned i) const {
|
||||
return Constraints[i + NumOutputs];
|
||||
@ -1403,7 +1413,7 @@ class AsmStmt : public Stmt {
|
||||
/// getNamedOperand - Given a symbolic operand reference like %[foo],
|
||||
/// translate this into a numeric value needed to reference the same operand.
|
||||
/// This returns -1 if the operand name is invalid.
|
||||
int getNamedOperand(llvm::StringRef SymbolicName) const;
|
||||
int getNamedOperand(StringRef SymbolicName) const;
|
||||
|
||||
unsigned getNumClobbers() const { return NumClobbers; }
|
||||
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
|
||||
|
@ -42,7 +42,7 @@ class StmtVisitorBase {
|
||||
// below.
|
||||
if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
default: assert(0 && "Unknown binary operator!");
|
||||
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 +80,7 @@ class StmtVisitorBase {
|
||||
}
|
||||
} else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) {
|
||||
switch (UnOp->getOpcode()) {
|
||||
default: assert(0 && "Unknown unary operator!");
|
||||
default: llvm_unreachable("Unknown unary operator!");
|
||||
case UO_PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
|
||||
case UO_PostDec: DISPATCH(UnaryPostDec, UnaryOperator);
|
||||
case UO_PreInc: DISPATCH(UnaryPreInc, UnaryOperator);
|
||||
@ -99,7 +99,7 @@ class StmtVisitorBase {
|
||||
|
||||
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
|
||||
switch (S->getStmtClass()) {
|
||||
default: assert(0 && "Unknown stmt kind!");
|
||||
default: llvm_unreachable("Unknown stmt kind!");
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#define STMT(CLASS, PARENT) \
|
||||
case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
namespace llvm {
|
||||
class FoldingSetNodeID;
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -354,7 +353,7 @@ class TemplateArgument {
|
||||
TemplateArgument getPackExpansionPattern() const;
|
||||
|
||||
/// \brief Print this template argument to the given output stream.
|
||||
void print(const PrintingPolicy &Policy, llvm::raw_ostream &Out) const;
|
||||
void print(const PrintingPolicy &Policy, raw_ostream &Out) const;
|
||||
|
||||
/// \brief Used to insert TemplateArguments into FoldingSets.
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
|
||||
@ -515,10 +514,14 @@ class TemplateArgumentLoc {
|
||||
/// A convenient class for passing around template argument
|
||||
/// information. Designed to be passed by reference.
|
||||
class TemplateArgumentListInfo {
|
||||
llvm::SmallVector<TemplateArgumentLoc, 8> Arguments;
|
||||
SmallVector<TemplateArgumentLoc, 8> Arguments;
|
||||
SourceLocation LAngleLoc;
|
||||
SourceLocation RAngleLoc;
|
||||
|
||||
// This can leak if used in an AST node, use ASTTemplateArgumentListInfo
|
||||
// instead.
|
||||
void* operator new(size_t bytes, ASTContext& C);
|
||||
|
||||
public:
|
||||
TemplateArgumentListInfo() {}
|
||||
|
||||
@ -547,6 +550,48 @@ class TemplateArgumentListInfo {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents an explicit template argument list in C++, e.g.,
|
||||
/// the "<int>" in "sort<int>".
|
||||
/// This is safe to be used inside an AST node, in contrast with
|
||||
/// TemplateArgumentListInfo.
|
||||
struct ASTTemplateArgumentListInfo {
|
||||
/// \brief The source location of the left angle bracket ('<');
|
||||
SourceLocation LAngleLoc;
|
||||
|
||||
/// \brief The source location of the right angle bracket ('>');
|
||||
SourceLocation RAngleLoc;
|
||||
|
||||
/// \brief The number of template arguments in TemplateArgs.
|
||||
/// The actual template arguments (if any) are stored after the
|
||||
/// ExplicitTemplateArgumentList structure.
|
||||
unsigned NumTemplateArgs;
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
TemplateArgumentLoc *getTemplateArgs() {
|
||||
return reinterpret_cast<TemplateArgumentLoc *> (this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template arguments
|
||||
const TemplateArgumentLoc *getTemplateArgs() const {
|
||||
return reinterpret_cast<const TemplateArgumentLoc *> (this + 1);
|
||||
}
|
||||
|
||||
const TemplateArgumentLoc &operator[](unsigned I) const {
|
||||
return getTemplateArgs()[I];
|
||||
}
|
||||
|
||||
static const ASTTemplateArgumentListInfo *Create(ASTContext &C,
|
||||
const TemplateArgumentListInfo &List);
|
||||
|
||||
void initializeFrom(const TemplateArgumentListInfo &List);
|
||||
void initializeFrom(const TemplateArgumentListInfo &List,
|
||||
bool &Dependent, bool &InstantiationDependent,
|
||||
bool &ContainsUnexpandedParameterPack);
|
||||
void copyInto(TemplateArgumentListInfo &List) const;
|
||||
static std::size_t sizeFor(unsigned NumTemplateArgs);
|
||||
static std::size_t sizeFor(const TemplateArgumentListInfo &List);
|
||||
};
|
||||
|
||||
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const TemplateArgument &Arg);
|
||||
|
||||
|
@ -14,14 +14,11 @@
|
||||
#ifndef LLVM_CLANG_AST_TEMPLATENAME_H
|
||||
#define LLVM_CLANG_AST_TEMPLATENAME_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
@ -308,7 +305,7 @@ class TemplateName {
|
||||
/// \param SuppressNNS if true, don't print the
|
||||
/// nested-name-specifier that precedes the template name (if it has
|
||||
/// one).
|
||||
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
bool SuppressNNS = false) const;
|
||||
|
||||
/// \brief Debugging aid that dumps the template name to standard
|
||||
|
@ -22,19 +22,15 @@
|
||||
#include "clang/Basic/Visibility.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
using llvm::isa;
|
||||
using llvm::cast;
|
||||
using llvm::cast_or_null;
|
||||
using llvm::dyn_cast;
|
||||
using llvm::dyn_cast_or_null;
|
||||
namespace clang {
|
||||
enum {
|
||||
TypeAlignmentInBits = 4,
|
||||
@ -508,6 +504,9 @@ class QualType {
|
||||
|
||||
const Type *getTypePtrOrNull() const;
|
||||
|
||||
/// Retrieves a pointer to the name of the base type.
|
||||
const IdentifierInfo *getBaseTypeIdentifier() const;
|
||||
|
||||
/// Divides a QualType into its unqualified type and a set of local
|
||||
/// qualifiers.
|
||||
SplitQualType split() const;
|
||||
@ -868,8 +867,9 @@ class QualType {
|
||||
/// type other than void.
|
||||
bool isCForbiddenLValueType() const;
|
||||
|
||||
/// \brief Determine whether this type has trivial copy-assignment semantics.
|
||||
bool hasTrivialCopyAssignment(ASTContext &Context) const;
|
||||
/// \brief Determine whether this type has trivial copy/move-assignment
|
||||
/// semantics.
|
||||
bool hasTrivialAssignment(ASTContext &Context, bool Copying) const;
|
||||
|
||||
private:
|
||||
// These methods are implemented in a separate translation unit;
|
||||
@ -1362,6 +1362,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
/// various convenient purposes within Clang. All such types are
|
||||
/// BuiltinTypes.
|
||||
bool isPlaceholderType() const;
|
||||
const BuiltinType *getAsPlaceholderType() const;
|
||||
|
||||
/// isSpecificPlaceholderType - Test for a specific placeholder type.
|
||||
bool isSpecificPlaceholderType(unsigned K) const;
|
||||
@ -1373,6 +1374,8 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
bool isBooleanType() const;
|
||||
bool isCharType() const;
|
||||
bool isWideCharType() const;
|
||||
bool isChar16Type() const;
|
||||
bool isChar32Type() const;
|
||||
bool isAnyCharacterType() const;
|
||||
bool isIntegralType(ASTContext &Ctx) const;
|
||||
|
||||
@ -1389,6 +1392,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
bool isComplexType() const; // C99 6.2.5p11 (complex)
|
||||
bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
|
||||
bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
|
||||
bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
|
||||
bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
|
||||
bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
|
||||
bool isVoidType() const; // C99 6.2.5p19
|
||||
@ -1447,6 +1451,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
bool isCARCBridgableType() const;
|
||||
bool isTemplateTypeParmType() const; // C++ template type parameter
|
||||
bool isNullPtrType() const; // C++0x nullptr_t
|
||||
bool isAtomicType() const; // C1X _Atomic()
|
||||
|
||||
/// Determines if this type, which must satisfy
|
||||
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
|
||||
@ -1457,7 +1462,9 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
|
||||
|
||||
enum ScalarTypeKind {
|
||||
STK_Pointer,
|
||||
STK_CPointer,
|
||||
STK_BlockPointer,
|
||||
STK_ObjCObjectPointer,
|
||||
STK_MemberPointer,
|
||||
STK_Bool,
|
||||
STK_Integral,
|
||||
@ -1693,6 +1700,8 @@ class BuiltinType : public Type {
|
||||
LongLong,
|
||||
Int128, // __int128_t
|
||||
|
||||
Half, // This is the 'half' type in OpenCL,
|
||||
// __fp16 in case of ARM NEON.
|
||||
Float, Double, LongDouble,
|
||||
|
||||
NullPtr, // This is the type of C++0x 'nullptr'.
|
||||
@ -1755,7 +1764,7 @@ class BuiltinType : public Type {
|
||||
}
|
||||
|
||||
Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); }
|
||||
const char *getName(const LangOptions &LO) const;
|
||||
const char *getName(const PrintingPolicy &Policy) const;
|
||||
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
@ -1773,7 +1782,7 @@ class BuiltinType : public Type {
|
||||
}
|
||||
|
||||
bool isFloatingPoint() const {
|
||||
return getKind() >= Float && getKind() <= LongDouble;
|
||||
return getKind() >= Half && getKind() <= LongDouble;
|
||||
}
|
||||
|
||||
/// Determines whether this type is a placeholder type, i.e. a type
|
||||
@ -2249,7 +2258,7 @@ class VariableArrayType : public ArrayType {
|
||||
friend class StmtIteratorBase;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
assert(0 && "Cannot unique VariableArrayTypes.");
|
||||
llvm_unreachable("Cannot unique VariableArrayTypes.");
|
||||
}
|
||||
};
|
||||
|
||||
@ -2635,7 +2644,7 @@ class FunctionType : public Type {
|
||||
return getResultType().getNonLValueExprType(Context);
|
||||
}
|
||||
|
||||
static llvm::StringRef getNameForCallConv(CallingConv CC);
|
||||
static StringRef getNameForCallConv(CallingConv CC);
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == FunctionNoProto ||
|
||||
@ -2696,8 +2705,17 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
unsigned char TypeQuals;
|
||||
RefQualifierKind RefQualifier;
|
||||
unsigned NumExceptions;
|
||||
|
||||
/// Exceptions - A variable size array after that holds the exception types.
|
||||
const QualType *Exceptions;
|
||||
|
||||
/// NoexceptExpr - Instead of Exceptions, there may be a single Expr*
|
||||
/// pointing to the expression in the noexcept() specifier.
|
||||
Expr *NoexceptExpr;
|
||||
|
||||
/// ConsumedArgs - A variable size array, following Exceptions
|
||||
/// and of length NumArgs, holding flags indicating which arguments
|
||||
/// are consumed. This only appears if HasAnyConsumedArgs is true.
|
||||
const bool *ConsumedArguments;
|
||||
};
|
||||
|
||||
@ -2728,19 +2746,6 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
/// HasAnyConsumedArgs - Whether this function has any consumed arguments.
|
||||
unsigned HasAnyConsumedArgs : 1;
|
||||
|
||||
/// ArgInfo - There is an variable size array after the class in memory that
|
||||
/// holds the argument types.
|
||||
|
||||
/// Exceptions - There is another variable size array after ArgInfo that
|
||||
/// holds the exception types.
|
||||
|
||||
/// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
|
||||
/// to the expression in the noexcept() specifier.
|
||||
|
||||
/// ConsumedArgs - A variable size array, following Exceptions
|
||||
/// and of length NumArgs, holding flags indicating which arguments
|
||||
/// are consumed. This only appears if HasAnyConsumedArgs is true.
|
||||
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
|
||||
const bool *getConsumedArgsBuffer() const {
|
||||
@ -4348,6 +4353,37 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const ObjCObjectPointerType *) { return true; }
|
||||
};
|
||||
|
||||
class AtomicType : public Type, public llvm::FoldingSetNode {
|
||||
QualType ValueType;
|
||||
|
||||
AtomicType(QualType ValTy, QualType Canonical)
|
||||
: Type(Atomic, Canonical, ValTy->isDependentType(),
|
||||
ValTy->isInstantiationDependentType(),
|
||||
ValTy->isVariablyModifiedType(),
|
||||
ValTy->containsUnexpandedParameterPack()),
|
||||
ValueType(ValTy) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
|
||||
public:
|
||||
/// getValueType - Gets the type contained by this atomic type, i.e.
|
||||
/// the type returned by performing an atomic load of this atomic type.
|
||||
QualType getValueType() const { return ValueType; }
|
||||
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getValueType());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
|
||||
ID.AddPointer(T.getAsOpaquePtr());
|
||||
}
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Atomic;
|
||||
}
|
||||
static bool classof(const AtomicType *) { return true; }
|
||||
};
|
||||
|
||||
/// A qualifier set is used to build a set of qualifiers.
|
||||
class QualifierCollector : public Qualifiers {
|
||||
public:
|
||||
@ -4673,6 +4709,9 @@ inline bool Type::isObjCObjectOrInterfaceType() const {
|
||||
return isa<ObjCInterfaceType>(CanonicalType) ||
|
||||
isa<ObjCObjectType>(CanonicalType);
|
||||
}
|
||||
inline bool Type::isAtomicType() const {
|
||||
return isa<AtomicType>(CanonicalType);
|
||||
}
|
||||
|
||||
inline bool Type::isObjCQualifiedIdType() const {
|
||||
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
|
||||
@ -4714,11 +4753,18 @@ inline bool Type::isSpecificBuiltinType(unsigned K) const {
|
||||
}
|
||||
|
||||
inline bool Type::isPlaceholderType() const {
|
||||
if (const BuiltinType *BT = getAs<BuiltinType>())
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
|
||||
return BT->isPlaceholderType();
|
||||
return false;
|
||||
}
|
||||
|
||||
inline const BuiltinType *Type::getAsPlaceholderType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
|
||||
if (BT->isPlaceholderType())
|
||||
return BT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool Type::isSpecificPlaceholderType(unsigned K) const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
|
||||
return (BT->getKind() == (BuiltinType::Kind) K);
|
||||
@ -4757,7 +4803,7 @@ inline const Type *Type::getBaseElementTypeUnsafe() const {
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
QualType T) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
|
||||
Diagnostic::ak_qualtype);
|
||||
DiagnosticsEngine::ak_qualtype);
|
||||
return DB;
|
||||
}
|
||||
|
||||
@ -4766,7 +4812,7 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
QualType T) {
|
||||
PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
|
||||
Diagnostic::ak_qualtype);
|
||||
DiagnosticsEngine::ak_qualtype);
|
||||
return PD;
|
||||
}
|
||||
|
||||
|
@ -538,6 +538,10 @@ class InjectedClassNameTypeLoc :
|
||||
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
InjectedClassNameTypeLoc,
|
||||
InjectedClassNameType> {
|
||||
public:
|
||||
CXXRecordDecl *getDecl() const {
|
||||
return getTypePtr()->getDecl();
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for unresolved typename using decls.
|
||||
@ -561,6 +565,12 @@ class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TagType> {
|
||||
public:
|
||||
TagDecl *getDecl() const { return getTypePtr()->getDecl(); }
|
||||
|
||||
/// \brief True if the tag was defined in this type specifier.
|
||||
bool isDefinition() const {
|
||||
return getDecl()->isCompleteDefinition() &&
|
||||
(getNameLoc().isInvalid() || getNameLoc() == getDecl()->getLocation());
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for record types.
|
||||
@ -1408,6 +1418,8 @@ class TypeOfTypeLoc
|
||||
class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
DecltypeTypeLoc,
|
||||
DecltypeType> {
|
||||
public:
|
||||
Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); }
|
||||
};
|
||||
|
||||
struct UnaryTransformTypeLocInfo {
|
||||
@ -1718,6 +1730,62 @@ class PackExpansionTypeLoc
|
||||
}
|
||||
};
|
||||
|
||||
struct AtomicTypeLocInfo {
|
||||
SourceLocation KWLoc, LParenLoc, RParenLoc;
|
||||
};
|
||||
|
||||
class AtomicTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AtomicTypeLoc,
|
||||
AtomicType, AtomicTypeLocInfo> {
|
||||
public:
|
||||
TypeLoc getValueLoc() const {
|
||||
return this->getInnerTypeLoc();
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return SourceRange(getKWLoc(), getRParenLoc());
|
||||
}
|
||||
|
||||
SourceLocation getKWLoc() const {
|
||||
return this->getLocalData()->KWLoc;
|
||||
}
|
||||
void setKWLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->KWLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getLParenLoc() const {
|
||||
return this->getLocalData()->LParenLoc;
|
||||
}
|
||||
void setLParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->LParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRParenLoc() const {
|
||||
return this->getLocalData()->RParenLoc;
|
||||
}
|
||||
void setRParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->RParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceRange getParensRange() const {
|
||||
return SourceRange(getLParenLoc(), getRParenLoc());
|
||||
}
|
||||
void setParensRange(SourceRange Range) {
|
||||
setLParenLoc(Range.getBegin());
|
||||
setRParenLoc(Range.getEnd());
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setKWLoc(Loc);
|
||||
setLParenLoc(Loc);
|
||||
setRParenLoc(Loc);
|
||||
}
|
||||
|
||||
QualType getInnerType() const {
|
||||
return this->getTypePtr()->getValueType();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -102,9 +102,10 @@ DEPENDENT_TYPE(PackExpansion, Type)
|
||||
TYPE(ObjCObject, Type)
|
||||
TYPE(ObjCInterface, ObjCObjectType)
|
||||
TYPE(ObjCObjectPointer, Type)
|
||||
TYPE(Atomic, Type)
|
||||
|
||||
#ifdef LAST_TYPE
|
||||
LAST_TYPE(ObjCObjectPointer)
|
||||
LAST_TYPE(Atomic)
|
||||
#undef LAST_TYPE
|
||||
#endif
|
||||
|
||||
|
@ -28,7 +28,7 @@ class TypeVisitor {
|
||||
RetTy Visit(const Type *T) {
|
||||
// Top switch stmt: dispatch to VisitFooType for each FooType.
|
||||
switch (T->getTypeClass()) {
|
||||
default: assert(0 && "Unknown type class!");
|
||||
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"
|
||||
|
@ -25,7 +25,7 @@ namespace clang {
|
||||
/// non-const iterator.
|
||||
class UnresolvedSetIterator {
|
||||
private:
|
||||
typedef llvm::SmallVectorImpl<DeclAccessPair> DeclsTy;
|
||||
typedef SmallVectorImpl<DeclAccessPair> DeclsTy;
|
||||
typedef DeclsTy::iterator IteratorTy;
|
||||
|
||||
IteratorTy ir;
|
||||
@ -177,7 +177,7 @@ class UnresolvedSetImpl {
|
||||
/// A set of unresolved declarations
|
||||
template <unsigned InlineCapacity> class UnresolvedSet :
|
||||
public UnresolvedSetImpl {
|
||||
llvm::SmallVector<DeclAccessPair, InlineCapacity> Decls;
|
||||
SmallVector<DeclAccessPair, InlineCapacity> Decls;
|
||||
};
|
||||
|
||||
|
||||
|
176
include/clang/AST/VTTBuilder.h
Normal file
176
include/clang/AST/VTTBuilder.h
Normal file
@ -0,0 +1,176 @@
|
||||
//===--- VTTBuilder.h - C++ VTT layout builder --------------------*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code dealing with generation of the layout of virtual table
|
||||
// tables (VTT).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_VTTBUILDER_H
|
||||
#define LLVM_CLANG_AST_VTTBUILDER_H
|
||||
|
||||
#include "clang/AST/BaseSubobject.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/GlobalDecl.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/Basic/ABI.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class VTTVTable {
|
||||
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> BaseAndIsVirtual;
|
||||
CharUnits BaseOffset;
|
||||
|
||||
public:
|
||||
VTTVTable() {}
|
||||
VTTVTable(const CXXRecordDecl *Base, CharUnits BaseOffset, bool BaseIsVirtual)
|
||||
: BaseAndIsVirtual(Base, BaseIsVirtual), BaseOffset(BaseOffset) {}
|
||||
VTTVTable(BaseSubobject Base, bool BaseIsVirtual)
|
||||
: BaseAndIsVirtual(Base.getBase(), BaseIsVirtual),
|
||||
BaseOffset(Base.getBaseOffset()) {}
|
||||
|
||||
const CXXRecordDecl *getBase() const {
|
||||
return BaseAndIsVirtual.getPointer();
|
||||
}
|
||||
|
||||
CharUnits getBaseOffset() const {
|
||||
return BaseOffset;
|
||||
}
|
||||
|
||||
bool isVirtual() const {
|
||||
return BaseAndIsVirtual.getInt();
|
||||
}
|
||||
|
||||
BaseSubobject getBaseSubobject() const {
|
||||
return BaseSubobject(getBase(), getBaseOffset());
|
||||
}
|
||||
};
|
||||
|
||||
struct VTTComponent {
|
||||
uint64_t VTableIndex;
|
||||
BaseSubobject VTableBase;
|
||||
|
||||
VTTComponent() {}
|
||||
VTTComponent(uint64_t VTableIndex, BaseSubobject VTableBase)
|
||||
: VTableIndex(VTableIndex), VTableBase(VTableBase) {}
|
||||
};
|
||||
|
||||
/// VTT builder - Class for building VTT layout information.
|
||||
class VTTBuilder {
|
||||
|
||||
ASTContext &Ctx;
|
||||
|
||||
/// MostDerivedClass - The most derived class for which we're building this
|
||||
/// vtable.
|
||||
const CXXRecordDecl *MostDerivedClass;
|
||||
|
||||
typedef SmallVector<VTTVTable, 64> VTTVTablesVectorTy;
|
||||
|
||||
/// VTTVTables - The VTT vtables.
|
||||
VTTVTablesVectorTy VTTVTables;
|
||||
|
||||
typedef SmallVector<VTTComponent, 64> VTTComponentsVectorTy;
|
||||
|
||||
/// VTTComponents - The VTT components.
|
||||
VTTComponentsVectorTy VTTComponents;
|
||||
|
||||
/// MostDerivedClassLayout - the AST record layout of the most derived class.
|
||||
const ASTRecordLayout &MostDerivedClassLayout;
|
||||
|
||||
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
|
||||
|
||||
typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
|
||||
|
||||
/// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
|
||||
/// class.
|
||||
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
|
||||
|
||||
/// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
|
||||
/// all subobjects of the most derived class.
|
||||
llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices;
|
||||
|
||||
/// GenerateDefinition - Whether the VTT builder should generate LLVM IR for
|
||||
/// the VTT.
|
||||
bool GenerateDefinition;
|
||||
|
||||
/// AddVTablePointer - Add a vtable pointer to the VTT currently being built.
|
||||
///
|
||||
/// \param AddressPoints - If the vtable is a construction vtable, this has
|
||||
/// the address points for it.
|
||||
void AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
|
||||
const CXXRecordDecl *VTableClass);
|
||||
|
||||
/// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base
|
||||
/// subobject.
|
||||
void LayoutSecondaryVTTs(BaseSubobject Base);
|
||||
|
||||
/// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
|
||||
/// for the given base subobject.
|
||||
///
|
||||
/// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
|
||||
/// or a direct or indirect base of a virtual base.
|
||||
///
|
||||
/// \param AddressPoints - If the vtable is a construction vtable, this has
|
||||
/// the address points for it.
|
||||
void LayoutSecondaryVirtualPointers(BaseSubobject Base,
|
||||
bool BaseIsMorallyVirtual,
|
||||
uint64_t VTableIndex,
|
||||
const CXXRecordDecl *VTableClass,
|
||||
VisitedVirtualBasesSetTy &VBases);
|
||||
|
||||
/// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
|
||||
/// for the given base subobject.
|
||||
///
|
||||
/// \param AddressPoints - If the vtable is a construction vtable, this has
|
||||
/// the address points for it.
|
||||
void LayoutSecondaryVirtualPointers(BaseSubobject Base,
|
||||
uint64_t VTableIndex);
|
||||
|
||||
/// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the
|
||||
/// given record decl.
|
||||
void LayoutVirtualVTTs(const CXXRecordDecl *RD,
|
||||
VisitedVirtualBasesSetTy &VBases);
|
||||
|
||||
/// LayoutVTT - Will lay out the VTT for the given subobject, including any
|
||||
/// secondary VTTs, secondary virtual pointers and virtual VTTs.
|
||||
void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual);
|
||||
|
||||
public:
|
||||
VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass,
|
||||
bool GenerateDefinition);
|
||||
|
||||
// getVTTComponents - Returns a reference to the VTT components.
|
||||
const VTTComponentsVectorTy &getVTTComponents() const {
|
||||
return VTTComponents;
|
||||
}
|
||||
|
||||
// getVTTVTables - Returns a reference to the VTT vtables.
|
||||
const VTTVTablesVectorTy &getVTTVTables() const {
|
||||
return VTTVTables;
|
||||
}
|
||||
|
||||
/// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
|
||||
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
|
||||
return SubVTTIndicies;
|
||||
}
|
||||
|
||||
/// getSecondaryVirtualPointerIndices - Returns a reference to the secondary
|
||||
/// virtual pointer indices.
|
||||
const llvm::DenseMap<BaseSubobject, uint64_t> &
|
||||
getSecondaryVirtualPointerIndices() const {
|
||||
return SecondaryVirtualPointerIndices;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
357
include/clang/AST/VTableBuilder.h
Normal file
357
include/clang/AST/VTableBuilder.h
Normal file
@ -0,0 +1,357 @@
|
||||
//===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This contains code dealing with generation of the layout of virtual tables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_VTABLEBUILDER_H
|
||||
#define LLVM_CLANG_AST_VTABLEBUILDER_H
|
||||
|
||||
#include "clang/AST/BaseSubobject.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/GlobalDecl.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/Basic/ABI.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
class CXXRecordDecl;
|
||||
|
||||
/// VTableComponent - Represents a single component in a vtable.
|
||||
class VTableComponent {
|
||||
public:
|
||||
enum Kind {
|
||||
CK_VCallOffset,
|
||||
CK_VBaseOffset,
|
||||
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.
|
||||
CK_UnusedFunctionPointer
|
||||
};
|
||||
|
||||
VTableComponent() { }
|
||||
|
||||
static VTableComponent MakeVCallOffset(CharUnits Offset) {
|
||||
return VTableComponent(CK_VCallOffset, Offset);
|
||||
}
|
||||
|
||||
static VTableComponent MakeVBaseOffset(CharUnits Offset) {
|
||||
return VTableComponent(CK_VBaseOffset, Offset);
|
||||
}
|
||||
|
||||
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) &&
|
||||
"Don't use MakeFunction with destructors!");
|
||||
|
||||
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,
|
||||
reinterpret_cast<uintptr_t>(DD));
|
||||
}
|
||||
|
||||
static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
|
||||
assert(!isa<CXXDestructorDecl>(MD) &&
|
||||
"Don't use MakeUnusedFunction with destructors!");
|
||||
return VTableComponent(CK_UnusedFunctionPointer,
|
||||
reinterpret_cast<uintptr_t>(MD));
|
||||
}
|
||||
|
||||
static VTableComponent getFromOpaqueInteger(uint64_t I) {
|
||||
return VTableComponent(I);
|
||||
}
|
||||
|
||||
/// getKind - Get the kind of this vtable component.
|
||||
Kind getKind() const {
|
||||
return (Kind)(Value & 0x7);
|
||||
}
|
||||
|
||||
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 ||
|
||||
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 ||
|
||||
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 ||
|
||||
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) { }
|
||||
|
||||
/// The kind is stored in the lower 3 bits of the value. For offsets, we
|
||||
/// make use of the facts that classes can't be larger than 2^55 bytes,
|
||||
/// so we store the offset in the lower part of the 61 bytes that remain.
|
||||
/// (The reason that we're not simply using a PointerIntPair here is that we
|
||||
/// need the offsets to be 64-bit, even when on a 32-bit machine).
|
||||
int64_t Value;
|
||||
};
|
||||
|
||||
class VTableLayout {
|
||||
public:
|
||||
typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
|
||||
typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
|
||||
|
||||
typedef const VTableComponent *vtable_component_iterator;
|
||||
typedef const VTableThunkTy *vtable_thunk_iterator;
|
||||
|
||||
typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
|
||||
private:
|
||||
uint64_t NumVTableComponents;
|
||||
VTableComponent *VTableComponents;
|
||||
|
||||
/// VTableThunks - Contains thunks needed by vtables.
|
||||
uint64_t NumVTableThunks;
|
||||
VTableThunkTy *VTableThunks;
|
||||
|
||||
/// Address points - Address points for all vtables.
|
||||
AddressPointsMapTy AddressPoints;
|
||||
|
||||
public:
|
||||
VTableLayout(uint64_t NumVTableComponents,
|
||||
const VTableComponent *VTableComponents,
|
||||
uint64_t NumVTableThunks,
|
||||
const VTableThunkTy *VTableThunks,
|
||||
const AddressPointsMapTy &AddressPoints);
|
||||
~VTableLayout();
|
||||
|
||||
uint64_t getNumVTableComponents() const {
|
||||
return NumVTableComponents;
|
||||
}
|
||||
|
||||
vtable_component_iterator vtable_component_begin() const {
|
||||
return VTableComponents;
|
||||
}
|
||||
|
||||
vtable_component_iterator vtable_component_end() const {
|
||||
return VTableComponents+NumVTableComponents;
|
||||
}
|
||||
|
||||
uint64_t getNumVTableThunks() const {
|
||||
return NumVTableThunks;
|
||||
}
|
||||
|
||||
vtable_thunk_iterator vtable_thunk_begin() const {
|
||||
return VTableThunks;
|
||||
}
|
||||
|
||||
vtable_thunk_iterator vtable_thunk_end() const {
|
||||
return VTableThunks+NumVTableThunks;
|
||||
}
|
||||
|
||||
uint64_t getAddressPoint(BaseSubobject Base) const {
|
||||
assert(AddressPoints.count(Base) &&
|
||||
"Did not find address point!");
|
||||
|
||||
uint64_t AddressPoint = AddressPoints.lookup(Base);
|
||||
assert(AddressPoint && "Address point must not be zero!");
|
||||
|
||||
return AddressPoint;
|
||||
}
|
||||
|
||||
const AddressPointsMapTy &getAddressPoints() const {
|
||||
return AddressPoints;
|
||||
}
|
||||
};
|
||||
|
||||
class VTableContext {
|
||||
ASTContext &Context;
|
||||
|
||||
public:
|
||||
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.
|
||||
typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
|
||||
MethodVTableIndicesTy MethodVTableIndices;
|
||||
|
||||
typedef llvm::DenseMap<const CXXRecordDecl *, const VTableLayout *>
|
||||
VTableLayoutMapTy;
|
||||
VTableLayoutMapTy VTableLayouts;
|
||||
|
||||
/// 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
|
||||
/// the address point) in chars where the offsets for virtual bases of a class
|
||||
/// are stored.
|
||||
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;
|
||||
|
||||
void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
|
||||
|
||||
/// ComputeVTableRelatedInformation - Compute and store all vtable related
|
||||
/// information (vtable layout, vbase offset offsets, thunks etc) for the
|
||||
/// given record decl.
|
||||
void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
|
||||
|
||||
public:
|
||||
VTableContext(ASTContext &Context) : Context(Context) {}
|
||||
~VTableContext();
|
||||
|
||||
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
|
||||
ComputeVTableRelatedInformation(RD);
|
||||
assert(VTableLayouts.count(RD) && "No layout for this record decl!");
|
||||
|
||||
return *VTableLayouts[RD];
|
||||
}
|
||||
|
||||
VTableLayout *
|
||||
createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass,
|
||||
CharUnits MostDerivedClassOffset,
|
||||
bool MostDerivedClassIsVirtual,
|
||||
const CXXRecordDecl *LayoutClass);
|
||||
|
||||
const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) {
|
||||
ComputeVTableRelatedInformation(MD->getParent());
|
||||
|
||||
ThunksMapTy::const_iterator I = Thunks.find(MD);
|
||||
if (I == Thunks.end()) {
|
||||
// We did not find a thunk for this method.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &I->second;
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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.
|
||||
CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
|
||||
const CXXRecordDecl *VBase);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -164,8 +164,8 @@ class ConversionSpecifier {
|
||||
return Position;
|
||||
}
|
||||
|
||||
llvm::StringRef getCharacters() const {
|
||||
return llvm::StringRef(getStart(), getLength());
|
||||
StringRef getCharacters() const {
|
||||
return StringRef(getStart(), getLength());
|
||||
}
|
||||
|
||||
bool consumesDataArgument() const {
|
||||
@ -271,7 +271,7 @@ class OptionalAmount {
|
||||
|
||||
ArgTypeResult getArgType(ASTContext &Ctx) const;
|
||||
|
||||
void toString(llvm::raw_ostream &os) const;
|
||||
void toString(raw_ostream &os) const;
|
||||
|
||||
bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
|
||||
unsigned getPositionalArgIndex() const {
|
||||
@ -465,7 +465,7 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
/// was not successful.
|
||||
bool fixType(QualType QT);
|
||||
|
||||
void toString(llvm::raw_ostream &os) const;
|
||||
void toString(raw_ostream &os) const;
|
||||
|
||||
// Validation methods - to check if any element results in undefined behavior
|
||||
bool hasValidPlusPrefix() const;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-===//
|
||||
//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -14,110 +14,105 @@
|
||||
#ifndef LLVM_CLANG_LIVEVARIABLES_H
|
||||
#define LLVM_CLANG_LIVEVARIABLES_H
|
||||
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/ImmutableSet.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CFG;
|
||||
class CFGBlock;
|
||||
class Stmt;
|
||||
class DeclRefExpr;
|
||||
class SourceManager;
|
||||
class AnalysisContext;
|
||||
|
||||
struct LiveVariables_ValueTypes {
|
||||
|
||||
struct ObserverTy;
|
||||
|
||||
// We keep dataflow state for declarations and block-level expressions;
|
||||
typedef StmtDeclBitVector_Types::ValTy ValTy;
|
||||
|
||||
// We need to keep track of both declarations and CFGBlock-level expressions,
|
||||
// (so that we don't explore such expressions twice). We also want
|
||||
// to compute liveness information for block-level expressions, since these
|
||||
// act as "temporary" values.
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
ObserverTy* Observer;
|
||||
ValTy AlwaysLive;
|
||||
AnalysisContext *AC;
|
||||
bool killAtAssign;
|
||||
|
||||
AnalysisDataTy() : Observer(NULL), AC(NULL), killAtAssign(true) {}
|
||||
};
|
||||
|
||||
//===-----------------------------------------------------===//
|
||||
// ObserverTy - Observer for uninitialized values queries.
|
||||
//===-----------------------------------------------------===//
|
||||
|
||||
struct ObserverTy {
|
||||
virtual ~ObserverTy() {}
|
||||
|
||||
/// ObserveStmt - A callback invoked right before invoking the
|
||||
/// liveness transfer function on the given statement.
|
||||
virtual void ObserveStmt(Stmt* S, const CFGBlock *currentBlock,
|
||||
const AnalysisDataTy& AD,
|
||||
const ValTy& V) {}
|
||||
|
||||
virtual void ObserverKill(DeclRefExpr* DR) {}
|
||||
};
|
||||
};
|
||||
|
||||
class LiveVariables : public DataflowValues<LiveVariables_ValueTypes,
|
||||
dataflow::backward_analysis_tag> {
|
||||
|
||||
|
||||
|
||||
class LiveVariables : public ManagedAnalysis {
|
||||
public:
|
||||
typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
|
||||
class LivenessValues {
|
||||
public:
|
||||
|
||||
LiveVariables(AnalysisContext &AC, bool killAtAssign = true);
|
||||
llvm::ImmutableSet<const Stmt *> liveStmts;
|
||||
llvm::ImmutableSet<const VarDecl *> liveDecls;
|
||||
|
||||
bool equals(const LivenessValues &V) const;
|
||||
|
||||
/// IsLive - Return true if a variable is live at the end of a
|
||||
LivenessValues()
|
||||
: liveStmts(0), liveDecls(0) {}
|
||||
|
||||
LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts,
|
||||
llvm::ImmutableSet<const VarDecl *> LiveDecls)
|
||||
: liveStmts(LiveStmts), liveDecls(LiveDecls) {}
|
||||
|
||||
~LivenessValues() {}
|
||||
|
||||
bool isLive(const Stmt *S) const;
|
||||
bool isLive(const VarDecl *D) const;
|
||||
|
||||
friend class LiveVariables;
|
||||
};
|
||||
|
||||
struct Observer {
|
||||
virtual ~Observer() {}
|
||||
|
||||
/// A callback invoked right before invoking the
|
||||
/// liveness transfer function on the given statement.
|
||||
virtual void observeStmt(const Stmt *S,
|
||||
const CFGBlock *currentBlock,
|
||||
const LivenessValues& V) {}
|
||||
|
||||
/// Called when the live variables analysis registers
|
||||
/// that a variable is killed.
|
||||
virtual void observerKill(const DeclRefExpr *DR) {}
|
||||
};
|
||||
|
||||
|
||||
virtual ~LiveVariables();
|
||||
|
||||
/// Compute the liveness information for a given CFG.
|
||||
static LiveVariables *computeLiveness(AnalysisContext &analysisContext,
|
||||
bool killAtAssign);
|
||||
|
||||
/// Return true if a variable is live at the end of a
|
||||
/// specified block.
|
||||
bool isLive(const CFGBlock* B, const VarDecl* D) const;
|
||||
|
||||
/// IsLive - Returns true if a variable is live at the beginning of the
|
||||
bool isLive(const CFGBlock *B, const VarDecl *D);
|
||||
|
||||
/// Returns true if a variable is live at the beginning of the
|
||||
/// the statement. This query only works if liveness information
|
||||
/// has been recorded at the statement level (see runOnAllBlocks), and
|
||||
/// only returns liveness information for block-level expressions.
|
||||
bool isLive(const Stmt* S, const VarDecl* D) const;
|
||||
|
||||
/// IsLive - Returns true the block-level expression "value" is live
|
||||
bool isLive(const Stmt *S, const VarDecl *D);
|
||||
|
||||
/// Returns true the block-level expression "value" is live
|
||||
/// before the given block-level expression (see runOnAllBlocks).
|
||||
bool isLive(const Stmt* Loc, const Stmt* StmtVal) const;
|
||||
bool isLive(const Stmt *Loc, const Stmt *StmtVal);
|
||||
|
||||
/// Print to stderr the liveness information associated with
|
||||
/// each basic block.
|
||||
void dumpBlockLiveness(const SourceManager& M);
|
||||
|
||||
/// IsLive - Return true if a variable is live according to the
|
||||
/// provided livness bitvector.
|
||||
bool isLive(const ValTy& V, const VarDecl* D) const;
|
||||
|
||||
/// dumpLiveness - Print to stderr the liveness information encoded
|
||||
/// by a specified bitvector.
|
||||
void dumpLiveness(const ValTy& V, const SourceManager& M) const;
|
||||
|
||||
/// dumpBlockLiveness - Print to stderr the liveness information
|
||||
/// associated with each basic block.
|
||||
void dumpBlockLiveness(const SourceManager& M) const;
|
||||
|
||||
/// getNumDecls - Return the number of variables (declarations) that
|
||||
/// whose liveness status is being tracked by the dataflow
|
||||
/// analysis.
|
||||
unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); }
|
||||
|
||||
/// IntializeValues - This routine can perform extra initialization, but
|
||||
/// for LiveVariables this does nothing since all that logic is in
|
||||
/// the constructor.
|
||||
void InitializeValues(const CFG& cfg) {}
|
||||
|
||||
void runOnCFG(CFG& cfg);
|
||||
|
||||
/// runOnAllBlocks - Propagate the dataflow values once for each block,
|
||||
/// starting from the current dataflow values. 'recordStmtValues' indicates
|
||||
/// whether the method should store dataflow values per each individual
|
||||
/// block-level expression.
|
||||
void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs,
|
||||
bool recordStmtValues=false);
|
||||
void runOnAllBlocks(Observer &obs);
|
||||
|
||||
static LiveVariables *create(AnalysisContext &analysisContext) {
|
||||
return computeLiveness(analysisContext, true);
|
||||
}
|
||||
|
||||
static const void *getTag();
|
||||
|
||||
private:
|
||||
LiveVariables(void *impl);
|
||||
void *impl;
|
||||
};
|
||||
|
||||
|
||||
class RelaxedLiveVariables : public LiveVariables {
|
||||
public:
|
||||
static LiveVariables *create(AnalysisContext &analysisContext) {
|
||||
return computeLiveness(analysisContext, false);
|
||||
}
|
||||
|
||||
static const void *getTag();
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -45,7 +45,7 @@ class Callback {
|
||||
|
||||
/// ScanReachableFromBlock - Mark all blocks reachable from Start.
|
||||
/// Returns the total number of blocks that were marked reachable.
|
||||
unsigned ScanReachableFromBlock(const CFGBlock &Start,
|
||||
unsigned ScanReachableFromBlock(const CFGBlock *Start,
|
||||
llvm::BitVector &Reachable);
|
||||
|
||||
void FindUnreachableCode(AnalysisContext &AC, Callback &CB);
|
||||
|
153
include/clang/Analysis/Analyses/ThreadSafety.h
Normal file
153
include/clang/Analysis/Analyses/ThreadSafety.h
Normal file
@ -0,0 +1,153 @@
|
||||
//===- ThreadSafety.h ------------------------------------------*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//
|
||||
// A intra-procedural analysis for thread safety (e.g. deadlocks and race
|
||||
// conditions), based off of an annotation system.
|
||||
//
|
||||
// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more
|
||||
// information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_THREADSAFETY_H
|
||||
#define LLVM_CLANG_THREADSAFETY_H
|
||||
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
namespace thread_safety {
|
||||
|
||||
/// This enum distinguishes between different kinds of operations that may
|
||||
/// need to be protected by locks. We use this enum in error handling.
|
||||
enum ProtectedOperationKind {
|
||||
POK_VarDereference, /// Dereferencing a variable (e.g. p in *p = 5;)
|
||||
POK_VarAccess, /// Reading or writing a variable (e.g. x in x = 5;)
|
||||
POK_FunctionCall /// Making a function call (e.g. fool())
|
||||
};
|
||||
|
||||
/// This enum distinguishes between different kinds of lock actions. For
|
||||
/// example, it is an error to write a variable protected by shared version of a
|
||||
/// mutex.
|
||||
enum LockKind {
|
||||
LK_Shared, /// Shared/reader lock of a mutex
|
||||
LK_Exclusive /// Exclusive/writer lock of a mutex
|
||||
};
|
||||
|
||||
/// This enum distinguishes between different ways to access (read or write) a
|
||||
/// variable.
|
||||
enum AccessKind {
|
||||
AK_Read, /// Reading a variable
|
||||
AK_Written /// Writing a variable
|
||||
};
|
||||
|
||||
/// This enum distinguishes between different situations where we warn due to
|
||||
/// inconsistent locking.
|
||||
/// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all
|
||||
/// loop iterations.
|
||||
/// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all
|
||||
/// predecessors of a CFGBlock.
|
||||
/// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a
|
||||
/// function.
|
||||
enum LockErrorKind {
|
||||
LEK_LockedSomeLoopIterations,
|
||||
LEK_LockedSomePredecessors,
|
||||
LEK_LockedAtEndOfFunction
|
||||
};
|
||||
|
||||
/// Handler class for thread safety warnings.
|
||||
class ThreadSafetyHandler {
|
||||
public:
|
||||
typedef llvm::StringRef Name;
|
||||
virtual ~ThreadSafetyHandler() = 0;
|
||||
|
||||
/// Warn about lock expressions which fail to resolve to lockable objects.
|
||||
/// \param Loc -- the SourceLocation of the unresolved expression.
|
||||
virtual void handleInvalidLockExp(SourceLocation Loc) {}
|
||||
|
||||
/// Warn about unlock function calls that do not have a prior matching lock
|
||||
/// expression.
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param Loc -- The SourceLocation of the Unlock
|
||||
virtual void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {}
|
||||
|
||||
/// Warn about lock function calls for locks which are already held.
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param Loc -- The location of the second lock expression.
|
||||
virtual void handleDoubleLock(Name LockName, SourceLocation Loc) {}
|
||||
|
||||
/// Warn about situations where a mutex is sometimes held and sometimes not.
|
||||
/// The three situations are:
|
||||
/// 1. a mutex is locked on an "if" branch but not the "else" branch,
|
||||
/// 2, or a mutex is only held at the start of some loop iterations,
|
||||
/// 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 LEK -- which of the three above cases we should warn for
|
||||
virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
|
||||
LockErrorKind LEK){}
|
||||
|
||||
/// Warn when a mutex is held exclusively and shared at the same point. For
|
||||
/// example, if a mutex is locked exclusively during an if branch and shared
|
||||
/// during the else branch.
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param Loc1 -- The location of the first lock expression.
|
||||
/// \param Loc2 -- The location of the second lock expression.
|
||||
virtual void handleExclusiveAndShared(Name LockName, SourceLocation Loc1,
|
||||
SourceLocation Loc2) {}
|
||||
|
||||
/// Warn when a protected operation occurs while no locks are held.
|
||||
/// \param D -- The decl for the protected variable or function
|
||||
/// \param POK -- The kind of protected operation (e.g. variable access)
|
||||
/// \param AK -- The kind of access (i.e. read or write) that occurred
|
||||
/// \param Loc -- The location of the protected operation.
|
||||
virtual void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
|
||||
AccessKind AK, SourceLocation Loc) {}
|
||||
|
||||
/// Warn when a protected operation occurs while the specific mutex protecting
|
||||
/// the operation is not locked.
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param D -- The decl for the protected variable or function
|
||||
/// \param POK -- The kind of protected operation (e.g. variable access)
|
||||
/// \param AK -- The kind of access (i.e. read or write) that occurred
|
||||
/// \param Loc -- The location of the protected operation.
|
||||
virtual void handleMutexNotHeld(const NamedDecl *D,
|
||||
ProtectedOperationKind POK, Name LockName,
|
||||
LockKind LK, SourceLocation Loc) {}
|
||||
|
||||
/// Warn when a function is called while an excluded mutex is locked. For
|
||||
/// example, the mutex may be locked inside the function.
|
||||
/// \param FunName -- The name of the function
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param Loc -- The location of the function call.
|
||||
virtual void handleFunExcludesLock(Name FunName, Name LockName,
|
||||
SourceLocation Loc) {}
|
||||
};
|
||||
|
||||
/// \brief Check a function's CFG for thread-safety violations.
|
||||
///
|
||||
/// 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);
|
||||
|
||||
/// \brief Helper function that returns a LockKind required for the given level
|
||||
/// of access.
|
||||
LockKind getLockKindFromAccessKind(AccessKind AK);
|
||||
|
||||
}} // end namespace clang::thread_safety
|
||||
#endif
|
@ -27,10 +27,16 @@ class UninitVariablesHandler {
|
||||
public:
|
||||
UninitVariablesHandler() {}
|
||||
virtual ~UninitVariablesHandler();
|
||||
|
||||
|
||||
/// Called when the uninitialized variable is used at the given expression.
|
||||
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.
|
||||
virtual void handleSelfInit(const VarDecl *vd) {}
|
||||
};
|
||||
|
||||
struct UninitVariablesAnalysisStats {
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
@ -31,14 +32,35 @@ class Stmt;
|
||||
class CFGReverseBlockReachabilityAnalysis;
|
||||
class CFGStmtMap;
|
||||
class LiveVariables;
|
||||
class ManagedAnalysis;
|
||||
class ParentMap;
|
||||
class PseudoConstantAnalysis;
|
||||
class ImplicitParamDecl;
|
||||
class LocationContextManager;
|
||||
class StackFrameContext;
|
||||
|
||||
|
||||
namespace idx { class TranslationUnit; }
|
||||
|
||||
/// The base class of a hierarchy of objects representing analyses tied
|
||||
/// to AnalysisContext.
|
||||
class ManagedAnalysis {
|
||||
protected:
|
||||
ManagedAnalysis() {}
|
||||
public:
|
||||
virtual ~ManagedAnalysis();
|
||||
|
||||
// Subclasses need to implement:
|
||||
//
|
||||
// static const void *getTag();
|
||||
//
|
||||
// Which returns a fixed pointer address to distinguish classes of
|
||||
// analysis objects. They also need to implement:
|
||||
//
|
||||
// static [Derived*] create(AnalysisContext &Ctx);
|
||||
//
|
||||
// which creates the analysis object given an AnalysisContext.
|
||||
};
|
||||
|
||||
/// AnalysisContext contains the context data for the function or method under
|
||||
/// analysis.
|
||||
class AnalysisContext {
|
||||
@ -54,7 +76,6 @@ class AnalysisContext {
|
||||
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
|
||||
|
||||
bool builtCFG, builtCompleteCFG;
|
||||
const bool useUnoptimizedCFG;
|
||||
|
||||
llvm::OwningPtr<LiveVariables> liveness;
|
||||
llvm::OwningPtr<LiveVariables> relaxedLiveness;
|
||||
@ -67,12 +88,13 @@ class AnalysisContext {
|
||||
// FIXME: remove.
|
||||
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
|
||||
|
||||
void *ManagedAnalyses;
|
||||
|
||||
public:
|
||||
AnalysisContext(const Decl *d, idx::TranslationUnit *tu);
|
||||
|
||||
AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
|
||||
bool useUnoptimizedCFG = false,
|
||||
bool addehedges = false,
|
||||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false);
|
||||
const CFG::BuildOptions &buildOptions);
|
||||
|
||||
~AnalysisContext();
|
||||
|
||||
@ -81,13 +103,22 @@ class AnalysisContext {
|
||||
|
||||
idx::TranslationUnit *getTranslationUnit() const { return TU; }
|
||||
|
||||
/// Return the build options used to construct the CFG.
|
||||
CFG::BuildOptions &getCFGBuildOptions() {
|
||||
return cfgBuildOptions;
|
||||
}
|
||||
|
||||
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 getUseUnoptimizedCFG() const {
|
||||
return cfgBuildOptions.PruneTriviallyFalseEdges;
|
||||
return !cfgBuildOptions.PruneTriviallyFalseEdges;
|
||||
}
|
||||
bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; }
|
||||
bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; }
|
||||
@ -95,7 +126,7 @@ class AnalysisContext {
|
||||
void registerForcedBlockExpression(const Stmt *stmt);
|
||||
const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
|
||||
|
||||
Stmt *getBody();
|
||||
Stmt *getBody() const;
|
||||
CFG *getCFG();
|
||||
|
||||
CFGStmtMap *getCFGStmtMap();
|
||||
@ -114,8 +145,6 @@ class AnalysisContext {
|
||||
|
||||
ParentMap &getParentMap();
|
||||
PseudoConstantAnalysis *getPseudoConstantAnalysis();
|
||||
LiveVariables *getLiveVariables();
|
||||
LiveVariables *getRelaxedLiveVariables();
|
||||
|
||||
typedef const VarDecl * const * referenced_decls_iterator;
|
||||
|
||||
@ -125,29 +154,44 @@ class AnalysisContext {
|
||||
/// Return the ImplicitParamDecl* associated with 'self' if this
|
||||
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
|
||||
const ImplicitParamDecl *getSelfDecl() const;
|
||||
|
||||
/// Return the specified analysis object, lazily running the analysis if
|
||||
/// necessary. Return NULL if the analysis could not run.
|
||||
template <typename T>
|
||||
T *getAnalysis() {
|
||||
const void *tag = T::getTag();
|
||||
ManagedAnalysis *&data = getAnalysisImpl(tag);
|
||||
if (!data) {
|
||||
data = T::create(*this);
|
||||
}
|
||||
return static_cast<T*>(data);
|
||||
}
|
||||
private:
|
||||
ManagedAnalysis *&getAnalysisImpl(const void* tag);
|
||||
};
|
||||
|
||||
class AnalysisContextManager {
|
||||
typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
|
||||
ContextMap Contexts;
|
||||
bool UseUnoptimizedCFG;
|
||||
bool AddImplicitDtors;
|
||||
bool AddInitializers;
|
||||
CFG::BuildOptions cfgBuildOptions;
|
||||
public:
|
||||
AnalysisContextManager(bool useUnoptimizedCFG = false,
|
||||
bool addImplicitDtors = false, bool addInitializers = false)
|
||||
: UseUnoptimizedCFG(useUnoptimizedCFG), AddImplicitDtors(addImplicitDtors),
|
||||
AddInitializers(addInitializers) {}
|
||||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false);
|
||||
|
||||
~AnalysisContextManager();
|
||||
|
||||
AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
|
||||
|
||||
bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
|
||||
bool getAddImplicitDtors() const { return AddImplicitDtors; }
|
||||
bool getAddInitializers() const { return AddInitializers; }
|
||||
bool getUseUnoptimizedCFG() const {
|
||||
return !cfgBuildOptions.PruneTriviallyFalseEdges;
|
||||
}
|
||||
|
||||
CFG::BuildOptions &getCFGBuildOptions() {
|
||||
return cfgBuildOptions;
|
||||
}
|
||||
|
||||
// Discard all previously created AnalysisContexts.
|
||||
/// Discard all previously created AnalysisContexts.
|
||||
void clear();
|
||||
};
|
||||
|
||||
@ -187,8 +231,9 @@ class LocationContext : public llvm::FoldingSetNode {
|
||||
|
||||
CFG *getCFG() const { return getAnalysisContext()->getCFG(); }
|
||||
|
||||
LiveVariables *getLiveVariables() const {
|
||||
return getAnalysisContext()->getLiveVariables();
|
||||
template <typename T>
|
||||
T *getAnalysis() const {
|
||||
return getAnalysisContext()->getAnalysis<T>();
|
||||
}
|
||||
|
||||
ParentMap &getParentMap() const {
|
||||
@ -212,7 +257,7 @@ class LocationContext : public llvm::FoldingSetNode {
|
||||
ContextKind ck,
|
||||
AnalysisContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const void* data);
|
||||
const void *data);
|
||||
};
|
||||
|
||||
class StackFrameContext : public LocationContext {
|
||||
@ -251,7 +296,7 @@ class StackFrameContext : public LocationContext {
|
||||
ID.AddInteger(idx);
|
||||
}
|
||||
|
||||
static bool classof(const LocationContext* Ctx) {
|
||||
static bool classof(const LocationContext *Ctx) {
|
||||
return Ctx->getKind() == StackFrame;
|
||||
}
|
||||
};
|
||||
@ -274,7 +319,7 @@ class ScopeContext : public LocationContext {
|
||||
ProfileCommon(ID, Scope, ctx, parent, s);
|
||||
}
|
||||
|
||||
static bool classof(const LocationContext* Ctx) {
|
||||
static bool classof(const LocationContext *Ctx) {
|
||||
return Ctx->getKind() == Scope;
|
||||
}
|
||||
};
|
||||
@ -302,7 +347,7 @@ class BlockInvocationContext : public LocationContext {
|
||||
ProfileCommon(ID, Block, ctx, parent, bd);
|
||||
}
|
||||
|
||||
static bool classof(const LocationContext* Ctx) {
|
||||
static bool classof(const LocationContext *Ctx) {
|
||||
return Ctx->getKind() == Block;
|
||||
}
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
|
||||
#define ANALYSISSTART
|
||||
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
|
||||
#undef DIAG
|
||||
|
@ -21,15 +21,13 @@
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class CXXDestructorDecl;
|
||||
class Decl;
|
||||
@ -98,7 +96,9 @@ class CFGStmt : public CFGElement {
|
||||
public:
|
||||
CFGStmt(Stmt *S) : CFGElement(Statement, S) {}
|
||||
|
||||
Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); }
|
||||
const Stmt *getStmt() const {
|
||||
return static_cast<const Stmt *>(Data1.getPointer());
|
||||
}
|
||||
|
||||
static bool classof(const CFGElement *E) {
|
||||
return E->getKind() == Statement;
|
||||
@ -280,7 +280,7 @@ class CFGBlock {
|
||||
|
||||
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) {
|
||||
BumpVectorContext &C) {
|
||||
return Impl.insert(I, Cnt, E, C);
|
||||
}
|
||||
|
||||
@ -333,10 +333,21 @@ class CFGBlock {
|
||||
AdjacentBlocks Preds;
|
||||
AdjacentBlocks Succs;
|
||||
|
||||
/// NoReturn - This bit is set when the basic block contains a function call
|
||||
/// or implicit destructor that is attributed as 'noreturn'. In that case,
|
||||
/// control cannot technically ever proceed past this block. All such blocks
|
||||
/// will have a single immediate successor: the exit block. This allows them
|
||||
/// to be easily reached from the exit block and using this bit quickly
|
||||
/// recognized without scanning the contents of the block.
|
||||
///
|
||||
/// Optimization Note: This bit could be profitably folded with Terminator's
|
||||
/// storage if the memory usage of CFGBlock becomes an issue.
|
||||
unsigned HasNoReturnElement : 1;
|
||||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
|
||||
: Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1) {}
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false) {}
|
||||
~CFGBlock() {}
|
||||
|
||||
// Statement iterators
|
||||
@ -455,42 +466,45 @@ class CFGBlock {
|
||||
|
||||
// Manipulation of block contents
|
||||
|
||||
void setTerminator(Stmt* Statement) { Terminator = Statement; }
|
||||
void setLabel(Stmt* Statement) { Label = Statement; }
|
||||
void setTerminator(Stmt *Statement) { Terminator = Statement; }
|
||||
void setLabel(Stmt *Statement) { Label = Statement; }
|
||||
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
|
||||
void setHasNoReturnElement() { HasNoReturnElement = true; }
|
||||
|
||||
CFGTerminator getTerminator() { return Terminator; }
|
||||
const CFGTerminator getTerminator() const { return Terminator; }
|
||||
|
||||
Stmt* getTerminatorCondition();
|
||||
Stmt *getTerminatorCondition();
|
||||
|
||||
const Stmt* getTerminatorCondition() const {
|
||||
const Stmt *getTerminatorCondition() const {
|
||||
return const_cast<CFGBlock*>(this)->getTerminatorCondition();
|
||||
}
|
||||
|
||||
const Stmt *getLoopTarget() const { return LoopTarget; }
|
||||
|
||||
Stmt* getLabel() { return Label; }
|
||||
const Stmt* getLabel() const { return Label; }
|
||||
Stmt *getLabel() { return Label; }
|
||||
const Stmt *getLabel() const { return Label; }
|
||||
|
||||
bool hasNoReturnElement() const { return HasNoReturnElement; }
|
||||
|
||||
unsigned getBlockID() const { return BlockID; }
|
||||
|
||||
void dump(const CFG *cfg, const LangOptions &LO) const;
|
||||
void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
|
||||
void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const;
|
||||
void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
|
||||
void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
|
||||
|
||||
void addSuccessor(CFGBlock* Block, BumpVectorContext &C) {
|
||||
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) {
|
||||
void appendStmt(Stmt *statement, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGStmt(statement), C);
|
||||
}
|
||||
|
||||
void appendInitializer(CXXCtorInitializer *initializer,
|
||||
BumpVectorContext& C) {
|
||||
BumpVectorContext &C) {
|
||||
Elements.push_back(CFGInitializer(initializer), C);
|
||||
}
|
||||
|
||||
@ -506,14 +520,18 @@ class CFGBlock {
|
||||
Elements.push_back(CFGTemporaryDtor(E), C);
|
||||
}
|
||||
|
||||
void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
|
||||
}
|
||||
|
||||
// Destructors must be inserted in reversed order. So insertion is in two
|
||||
// steps. First we prepare space for some number of elements, then we insert
|
||||
// the elements beginning at the last position in prepared space.
|
||||
iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
|
||||
BumpVectorContext& C) {
|
||||
BumpVectorContext &C) {
|
||||
return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C));
|
||||
}
|
||||
iterator insertAutomaticObjDtor(iterator I, VarDecl* VD, Stmt* S) {
|
||||
iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
|
||||
*I = CFGAutomaticObjDtor(VD, S);
|
||||
return ++I;
|
||||
}
|
||||
@ -533,30 +551,46 @@ class CFG {
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class BuildOptions {
|
||||
llvm::BitVector alwaysAddMask;
|
||||
public:
|
||||
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
|
||||
ForcedBlkExprs **forcedBlkExprs;
|
||||
|
||||
bool PruneTriviallyFalseEdges:1;
|
||||
bool AddEHEdges:1;
|
||||
bool AddInitializers:1;
|
||||
bool AddImplicitDtors:1;
|
||||
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;
|
||||
}
|
||||
|
||||
BuildOptions()
|
||||
: forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
|
||||
, AddEHEdges(false)
|
||||
, AddInitializers(false)
|
||||
, AddImplicitDtors(false) {}
|
||||
: alwaysAddMask(Stmt::lastStmtConstant, false)
|
||||
,forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
|
||||
,AddEHEdges(false)
|
||||
,AddInitializers(false)
|
||||
,AddImplicitDtors(false) {}
|
||||
};
|
||||
|
||||
/// 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,
|
||||
static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
|
||||
const BuildOptions &BO);
|
||||
|
||||
/// createBlock - Create a new block in the CFG. The CFG owns the block;
|
||||
/// the caller should not directly free it.
|
||||
CFGBlock* createBlock();
|
||||
CFGBlock *createBlock();
|
||||
|
||||
/// setEntry - Set the entry block of the CFG. This is typically used
|
||||
/// only during CFG construction. Most CFG clients expect that the
|
||||
@ -565,7 +599,7 @@ class CFG {
|
||||
|
||||
/// setIndirectGotoBlock - Set the block used for indirect goto jumps.
|
||||
/// This is typically used only during CFG construction.
|
||||
void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
|
||||
void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Block Iterators
|
||||
@ -577,8 +611,8 @@ class CFG {
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
CFGBlock& front() { return *Blocks.front(); }
|
||||
CFGBlock& back() { return *Blocks.back(); }
|
||||
CFGBlock & front() { return *Blocks.front(); }
|
||||
CFGBlock & back() { return *Blocks.back(); }
|
||||
|
||||
iterator begin() { return Blocks.begin(); }
|
||||
iterator end() { return Blocks.end(); }
|
||||
@ -590,13 +624,25 @@ class CFG {
|
||||
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Blocks.rend(); }
|
||||
|
||||
CFGBlock& getEntry() { return *Entry; }
|
||||
const CFGBlock& getEntry() const { return *Entry; }
|
||||
CFGBlock& getExit() { return *Exit; }
|
||||
const CFGBlock& getExit() const { return *Exit; }
|
||||
CFGBlock & getEntry() { return *Entry; }
|
||||
const CFGBlock & getEntry() const { return *Entry; }
|
||||
CFGBlock & getExit() { return *Exit; }
|
||||
const CFGBlock & getExit() const { return *Exit; }
|
||||
|
||||
CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; }
|
||||
const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; }
|
||||
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();
|
||||
}
|
||||
try_block_iterator try_blocks_end() const {
|
||||
return TryDispatchBlocks.end();
|
||||
}
|
||||
|
||||
void addTryDispatchBlock(const CFGBlock *block) {
|
||||
TryDispatchBlocks.push_back(block);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Member templates useful for various batch operations over CFGs.
|
||||
@ -608,7 +654,7 @@ class CFG {
|
||||
for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
|
||||
BI != BE; ++BI) {
|
||||
if (const CFGStmt *stmt = BI->getAs<CFGStmt>())
|
||||
O(stmt->getStmt());
|
||||
O(const_cast<Stmt*>(stmt->getStmt()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -624,11 +670,11 @@ class CFG {
|
||||
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
|
||||
};
|
||||
|
||||
bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
|
||||
bool isBlkExpr(const Stmt *S) { return getBlkExprNum(S); }
|
||||
bool isBlkExpr(const Stmt *S) const {
|
||||
return const_cast<CFG*>(this)->isBlkExpr(S);
|
||||
}
|
||||
BlkExprNumTy getBlkExprNum(const Stmt* S);
|
||||
BlkExprNumTy getBlkExprNum(const Stmt *S);
|
||||
unsigned getNumBlkExprs();
|
||||
|
||||
/// getNumBlockIDs - Returns the total number of BlockIDs allocated (which
|
||||
@ -640,7 +686,7 @@ class CFG {
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void viewCFG(const LangOptions &LO) const;
|
||||
void print(llvm::raw_ostream& OS, const LangOptions &LO) const;
|
||||
void print(raw_ostream &OS, const LangOptions &LO) const;
|
||||
void dump(const LangOptions &LO) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -661,8 +707,8 @@ class CFG {
|
||||
}
|
||||
|
||||
private:
|
||||
CFGBlock* Entry;
|
||||
CFGBlock* Exit;
|
||||
CFGBlock *Entry;
|
||||
CFGBlock *Exit;
|
||||
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
|
||||
// for indirect gotos
|
||||
unsigned NumBlockIDs;
|
||||
@ -670,11 +716,15 @@ class CFG {
|
||||
// BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
|
||||
// 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;
|
||||
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;
|
||||
|
||||
};
|
||||
} // end namespace clang
|
||||
@ -703,11 +753,11 @@ template <> struct simplify_type< ::clang::CFGTerminator> {
|
||||
|
||||
// Traits for: CFGBlock
|
||||
|
||||
template <> struct GraphTraits< ::clang::CFGBlock* > {
|
||||
template <> struct GraphTraits< ::clang::CFGBlock *> {
|
||||
typedef ::clang::CFGBlock NodeType;
|
||||
typedef ::clang::CFGBlock::succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(::clang::CFGBlock* BB)
|
||||
static NodeType* getEntryNode(::clang::CFGBlock *BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
@ -717,11 +767,11 @@ template <> struct GraphTraits< ::clang::CFGBlock* > {
|
||||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits< const ::clang::CFGBlock* > {
|
||||
template <> struct GraphTraits< const ::clang::CFGBlock *> {
|
||||
typedef const ::clang::CFGBlock NodeType;
|
||||
typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(const clang::CFGBlock* BB)
|
||||
static NodeType* getEntryNode(const clang::CFGBlock *BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
@ -748,7 +798,7 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
|
||||
// Traits for: CFG
|
||||
|
||||
template <> struct GraphTraits< ::clang::CFG* >
|
||||
: public GraphTraits< ::clang::CFGBlock* > {
|
||||
: public GraphTraits< ::clang::CFGBlock *> {
|
||||
|
||||
typedef ::clang::CFG::iterator nodes_iterator;
|
||||
|
||||
@ -758,7 +808,7 @@ template <> struct GraphTraits< ::clang::CFG* >
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const ::clang::CFG* >
|
||||
: public GraphTraits<const ::clang::CFGBlock* > {
|
||||
: public GraphTraits<const ::clang::CFGBlock *> {
|
||||
|
||||
typedef ::clang::CFG::const_iterator nodes_iterator;
|
||||
|
||||
|
@ -14,12 +14,13 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA
|
||||
#define LLVM_CLANG_ANALYSIS_DS_COCOA
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class FunctionDecl;
|
||||
class ObjCMethodDecl;
|
||||
class QualType;
|
||||
|
||||
namespace ento {
|
||||
namespace cocoa {
|
||||
@ -33,8 +34,8 @@ namespace cocoa {
|
||||
return deriveNamingConvention(S, MD) == CreateRule;
|
||||
}
|
||||
|
||||
bool isRefType(QualType RetTy, llvm::StringRef Prefix,
|
||||
llvm::StringRef Name = llvm::StringRef());
|
||||
bool isRefType(QualType RetTy, StringRef Prefix,
|
||||
StringRef Name = StringRef());
|
||||
|
||||
bool isCocoaObjectRef(QualType T);
|
||||
|
||||
@ -43,7 +44,7 @@ namespace cocoa {
|
||||
namespace coreFoundation {
|
||||
bool isCFObjectRef(QualType T);
|
||||
|
||||
bool followsCreateRule(llvm::StringRef functionName);
|
||||
bool followsCreateRule(const FunctionDecl *FD);
|
||||
}
|
||||
|
||||
}} // end: "clang:ento"
|
||||
|
@ -30,11 +30,11 @@ namespace clang {
|
||||
|
||||
class DataflowWorkListTy {
|
||||
llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet;
|
||||
llvm::SmallVector<const CFGBlock *, 10> BlockQueue;
|
||||
SmallVector<const CFGBlock *, 10> BlockQueue;
|
||||
public:
|
||||
/// enqueue - Add a block to the worklist. Blocks already on the
|
||||
/// worklist are not added a second time.
|
||||
void enqueue(const CFGBlock* B) {
|
||||
void enqueue(const CFGBlock *B) {
|
||||
unsigned char &x = BlockSet[B];
|
||||
if (x == 1)
|
||||
return;
|
||||
@ -43,7 +43,7 @@ class DataflowWorkListTy {
|
||||
}
|
||||
|
||||
/// dequeue - Remove a block from the worklist.
|
||||
const CFGBlock* dequeue() {
|
||||
const CFGBlock *dequeue() {
|
||||
assert(!BlockQueue.empty());
|
||||
const CFGBlock *B = BlockQueue.back();
|
||||
BlockQueue.pop_back();
|
||||
@ -69,20 +69,20 @@ template <> struct ItrTraits<forward_analysis_tag> {
|
||||
typedef CFGBlock::const_succ_iterator NextBItr;
|
||||
typedef CFGBlock::const_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
static PrevBItr PrevBegin(const CFGBlock *B) { return B->pred_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock *B) { return B->pred_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
static NextBItr NextBegin(const CFGBlock *B) { return B->succ_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock *B) { return B->succ_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
|
||||
static StmtItr StmtBegin(const CFGBlock *B) { return B->begin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock *B) { return B->end(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
|
||||
return BlockEdge(Prev, B, 0);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
|
||||
return BlockEdge(B, Next, 0);
|
||||
}
|
||||
};
|
||||
@ -92,20 +92,20 @@ template <> struct ItrTraits<backward_analysis_tag> {
|
||||
typedef CFGBlock::const_pred_iterator NextBItr;
|
||||
typedef CFGBlock::const_reverse_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
static PrevBItr PrevBegin(const CFGBlock *B) { return B->succ_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock *B) { return B->succ_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
static NextBItr NextBegin(const CFGBlock *B) { return B->pred_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock *B) { return B->pred_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
|
||||
static StmtItr StmtBegin(const CFGBlock *B) { return B->rbegin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock *B) { return B->rend(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
|
||||
return BlockEdge(B, Prev, 0);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
|
||||
return BlockEdge(Next, B, 0);
|
||||
}
|
||||
};
|
||||
@ -162,7 +162,7 @@ class DataflowSolver {
|
||||
/// dataflow values using runOnCFG, as runOnBlock is intended to
|
||||
/// only be used for querying the dataflow values within a block
|
||||
/// with and Observer object.
|
||||
void runOnBlock(const CFGBlock* B, bool recordStmtValues) {
|
||||
void runOnBlock(const CFGBlock *B, bool recordStmtValues) {
|
||||
BlockDataMapTy& M = D.getBlockDataMap();
|
||||
typename BlockDataMapTy::iterator I = M.find(B);
|
||||
|
||||
@ -172,13 +172,13 @@ class DataflowSolver {
|
||||
}
|
||||
}
|
||||
|
||||
void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
|
||||
void runOnBlock(const CFGBlock &B, bool recordStmtValues) {
|
||||
runOnBlock(&B, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
|
||||
void runOnBlock(CFG::iterator &I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) {
|
||||
void runOnBlock(CFG::const_iterator &I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ class DataflowSolver {
|
||||
EnqueueBlocksOnWorklist(cfg, AnalysisDirTag());
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock* B = WorkList.dequeue();
|
||||
const CFGBlock *B = WorkList.dequeue();
|
||||
ProcessMerge(cfg, B);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
UpdateEdges(cfg, B, TF.getVal());
|
||||
@ -222,7 +222,7 @@ class DataflowSolver {
|
||||
WorkList.enqueue(&**I);
|
||||
}
|
||||
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock *B) {
|
||||
ValTy& V = TF.getVal();
|
||||
TF.SetTopValue(V);
|
||||
|
||||
@ -270,7 +270,7 @@ class DataflowSolver {
|
||||
}
|
||||
|
||||
/// ProcessBlock - Process the transfer functions for a given block.
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
|
||||
dataflow::forward_analysis_tag) {
|
||||
|
||||
TF.setCurrentBlock(B);
|
||||
@ -284,7 +284,7 @@ class DataflowSolver {
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
}
|
||||
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
|
||||
dataflow::backward_analysis_tag) {
|
||||
|
||||
TF.setCurrentBlock(B);
|
||||
@ -298,12 +298,12 @@ class DataflowSolver {
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
|
||||
void ProcessStmt(const Stmt *S, bool record, dataflow::forward_analysis_tag) {
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){
|
||||
void ProcessStmt(const Stmt *S, bool record, dataflow::backward_analysis_tag){
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
}
|
||||
@ -312,14 +312,14 @@ class DataflowSolver {
|
||||
/// block, update the dataflow value associated with the block's
|
||||
/// outgoing/incoming edges (depending on whether we do a
|
||||
// forward/backward analysis respectively)
|
||||
void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) {
|
||||
void UpdateEdges(CFG& cfg, const CFGBlock *B, ValTy& V) {
|
||||
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
|
||||
if (CFGBlock *NextBlk = *I)
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk);
|
||||
}
|
||||
|
||||
/// UpdateEdgeValue - Update the value associated with a given edge.
|
||||
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
|
||||
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock *TargetBlock) {
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
typename EdgeDataMapTy::iterator I = M.find(E);
|
||||
|
||||
|
@ -84,13 +84,13 @@ class DataflowValues {
|
||||
|
||||
/// getEdgeData - Retrieves the dataflow values associated with a
|
||||
/// CFG edge.
|
||||
ValTy& getEdgeData(const BlockEdge& E) {
|
||||
ValTy& getEdgeData(const BlockEdge &E) {
|
||||
typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
|
||||
assert (I != EdgeDataMap.end() && "No data associated with Edge.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getEdgeData(const BlockEdge& E) const {
|
||||
const ValTy& getEdgeData(const BlockEdge &E) const {
|
||||
return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
|
||||
}
|
||||
|
||||
@ -98,13 +98,13 @@ class DataflowValues {
|
||||
/// specified CFGBlock. If the dataflow analysis is a forward analysis,
|
||||
/// this data is associated with the END of the block. If the analysis
|
||||
/// is a backwards analysis, it is associated with the ENTRY of the block.
|
||||
ValTy& getBlockData(const CFGBlock* B) {
|
||||
ValTy& getBlockData(const CFGBlock *B) {
|
||||
typename BlockDataMapTy::iterator I = BlockDataMap.find(B);
|
||||
assert (I != BlockDataMap.end() && "No data associated with block.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getBlockData(const CFGBlock* B) const {
|
||||
const ValTy& getBlockData(const CFGBlock *B) const {
|
||||
return const_cast<DataflowValues*>(this)->getBlockData(B);
|
||||
}
|
||||
|
||||
@ -114,14 +114,14 @@ class DataflowValues {
|
||||
/// If the analysis is a backwards analysis, it is associated with
|
||||
/// the point after a Stmt. This data is only computed for block-level
|
||||
/// expressions, and only when requested when the analysis is executed.
|
||||
ValTy& getStmtData(const Stmt* S) {
|
||||
ValTy& getStmtData(const Stmt *S) {
|
||||
assert (StmtDataMap && "Dataflow values were not computed for statements.");
|
||||
typename StmtDataMapTy::iterator I = StmtDataMap->find(S);
|
||||
assert (I != StmtDataMap->end() && "No data associated with statement.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getStmtData(const Stmt* S) const {
|
||||
const ValTy& getStmtData(const Stmt *S) const {
|
||||
return const_cast<DataflowValues*>(this)->getStmtData(S);
|
||||
}
|
||||
|
||||
|
@ -21,15 +21,18 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class LocationContext;
|
||||
class AnalysisContext;
|
||||
class FunctionDecl;
|
||||
|
||||
class LocationContext;
|
||||
class ProgramPointTag;
|
||||
|
||||
class ProgramPoint {
|
||||
public:
|
||||
enum Kind { BlockEdgeKind,
|
||||
@ -42,7 +45,6 @@ class ProgramPoint {
|
||||
PreStoreKind,
|
||||
PostStoreKind,
|
||||
PostPurgeDeadSymbolsKind,
|
||||
PostStmtCustomKind,
|
||||
PostConditionKind,
|
||||
PostLValueKind,
|
||||
PostInitializerKind,
|
||||
@ -58,25 +60,33 @@ class ProgramPoint {
|
||||
// The LocationContext could be NULL to allow ProgramPoint to be used in
|
||||
// context insensitive analysis.
|
||||
const LocationContext *L;
|
||||
const void *Tag;
|
||||
const ProgramPointTag *Tag;
|
||||
|
||||
ProgramPoint();
|
||||
|
||||
protected:
|
||||
ProgramPoint(const void* P, Kind k, const LocationContext *l,
|
||||
const void *tag = 0)
|
||||
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,
|
||||
const void *tag = 0)
|
||||
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) {}
|
||||
|
||||
protected:
|
||||
const void* getData1() const { return Data.first; }
|
||||
const void* getData2() const { return Data.second; }
|
||||
const void *getData1() const { return Data.first; }
|
||||
const void *getData2() const { return Data.second; }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
const void *getTag() const { return Tag; }
|
||||
const ProgramPointTag *getTag() const { return Tag; }
|
||||
|
||||
const LocationContext *getLocationContext() const { return L; }
|
||||
|
||||
@ -93,7 +103,7 @@ class ProgramPoint {
|
||||
return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag;
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramPoint& RHS) const {
|
||||
bool operator!=(const ProgramPoint &RHS) const {
|
||||
return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag;
|
||||
}
|
||||
|
||||
@ -104,29 +114,30 @@ class ProgramPoint {
|
||||
ID.AddPointer(L);
|
||||
ID.AddPointer(Tag);
|
||||
}
|
||||
|
||||
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
|
||||
const LocationContext *LC,
|
||||
const ProgramPointTag *tag);
|
||||
|
||||
};
|
||||
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
public:
|
||||
BlockEntrance(const CFGBlock* B, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
: ProgramPoint(B, BlockEntranceKind, L, tag) {}
|
||||
BlockEntrance(const CFGBlock *B, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: ProgramPoint(B, BlockEntranceKind, L, tag) {
|
||||
assert(B && "BlockEntrance requires non-null block");
|
||||
}
|
||||
|
||||
const CFGBlock* getBlock() const {
|
||||
const CFGBlock *getBlock() const {
|
||||
return reinterpret_cast<const CFGBlock*>(getData1());
|
||||
}
|
||||
|
||||
const CFGElement getFirstElement() const {
|
||||
const CFGBlock* B = getBlock();
|
||||
const CFGBlock *B = getBlock();
|
||||
return B->empty() ? CFGElement() : B->front();
|
||||
}
|
||||
|
||||
/// Create a new BlockEntrance object that is the same as the original
|
||||
/// except for using the specified tag value.
|
||||
BlockEntrance withTag(const void *tag) {
|
||||
return BlockEntrance(getBlock(), getLocationContext(), tag);
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockEntranceKind;
|
||||
}
|
||||
@ -134,14 +145,14 @@ class BlockEntrance : public ProgramPoint {
|
||||
|
||||
class BlockExit : public ProgramPoint {
|
||||
public:
|
||||
BlockExit(const CFGBlock* B, const LocationContext *L)
|
||||
BlockExit(const CFGBlock *B, const LocationContext *L)
|
||||
: ProgramPoint(B, BlockExitKind, L) {}
|
||||
|
||||
const CFGBlock* getBlock() const {
|
||||
const CFGBlock *getBlock() const {
|
||||
return reinterpret_cast<const CFGBlock*>(getData1());
|
||||
}
|
||||
|
||||
const Stmt* getTerminator() const {
|
||||
const Stmt *getTerminator() const {
|
||||
return getBlock()->getTerminator();
|
||||
}
|
||||
|
||||
@ -153,7 +164,7 @@ class BlockExit : public ProgramPoint {
|
||||
class StmtPoint : public ProgramPoint {
|
||||
public:
|
||||
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
|
||||
const void *tag)
|
||||
const ProgramPointTag *tag)
|
||||
: ProgramPoint(S, p2, k, L, tag) {}
|
||||
|
||||
const Stmt *getStmt() const { return (const Stmt*) getData1(); }
|
||||
@ -170,7 +181,7 @@ class StmtPoint : public ProgramPoint {
|
||||
|
||||
class PreStmt : public StmtPoint {
|
||||
public:
|
||||
PreStmt(const Stmt *S, const LocationContext *L, const void *tag,
|
||||
PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
|
||||
const Stmt *SubStmt = 0)
|
||||
: StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
|
||||
|
||||
@ -183,16 +194,17 @@ class PreStmt : public StmtPoint {
|
||||
|
||||
class PostStmt : public StmtPoint {
|
||||
protected:
|
||||
PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L,
|
||||
const void *tag =0)
|
||||
PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
|
||||
const ProgramPointTag *tag =0)
|
||||
: StmtPoint(S, data, k, L, tag) {}
|
||||
|
||||
public:
|
||||
explicit PostStmt(const Stmt* S, Kind k,
|
||||
const LocationContext *L, const void *tag = 0)
|
||||
explicit PostStmt(const Stmt *S, Kind k,
|
||||
const LocationContext *L, const ProgramPointTag *tag = 0)
|
||||
: StmtPoint(S, NULL, k, L, tag) {}
|
||||
|
||||
explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0)
|
||||
explicit PostStmt(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: StmtPoint(S, NULL, PostStmtKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
@ -201,31 +213,11 @@ class PostStmt : public StmtPoint {
|
||||
}
|
||||
};
|
||||
|
||||
class PostStmtCustom : public PostStmt {
|
||||
public:
|
||||
PostStmtCustom(const Stmt* S,
|
||||
const std::pair<const void*, const void*>* TaggedData,\
|
||||
const LocationContext *L)
|
||||
: PostStmt(S, TaggedData, PostStmtCustomKind, L) {}
|
||||
|
||||
const std::pair<const void*, const void*>& getTaggedPair() const {
|
||||
return
|
||||
*reinterpret_cast<const std::pair<const void*, const void*>*>(getData2());
|
||||
}
|
||||
|
||||
const void* getTag() const { return getTaggedPair().first; }
|
||||
|
||||
const void* getTaggedData() const { return getTaggedPair().second; }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostStmtCustomKind;
|
||||
}
|
||||
};
|
||||
|
||||
// PostCondition represents the post program point of a branch condition.
|
||||
class PostCondition : public PostStmt {
|
||||
public:
|
||||
PostCondition(const Stmt* S, const LocationContext *L, const void *tag = 0)
|
||||
PostCondition(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: PostStmt(S, PostConditionKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
@ -236,7 +228,7 @@ class PostCondition : public PostStmt {
|
||||
class LocationCheck : public StmtPoint {
|
||||
protected:
|
||||
LocationCheck(const Stmt *S, const LocationContext *L,
|
||||
ProgramPoint::Kind K, const void *tag)
|
||||
ProgramPoint::Kind K, const ProgramPointTag *tag)
|
||||
: StmtPoint(S, NULL, K, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint *location) {
|
||||
@ -247,7 +239,8 @@ class LocationCheck : public StmtPoint {
|
||||
|
||||
class PreLoad : public LocationCheck {
|
||||
public:
|
||||
PreLoad(const Stmt *S, const LocationContext *L, const void *tag = 0)
|
||||
PreLoad(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: LocationCheck(S, L, PreLoadKind, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint *location) {
|
||||
@ -257,7 +250,8 @@ class PreLoad : public LocationCheck {
|
||||
|
||||
class PreStore : public LocationCheck {
|
||||
public:
|
||||
PreStore(const Stmt *S, const LocationContext *L, const void *tag = 0)
|
||||
PreStore(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: LocationCheck(S, L, PreStoreKind, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint *location) {
|
||||
@ -267,7 +261,8 @@ class PreStore : public LocationCheck {
|
||||
|
||||
class PostLoad : public PostStmt {
|
||||
public:
|
||||
PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0)
|
||||
PostLoad(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: PostStmt(S, PostLoadKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
@ -277,7 +272,8 @@ class PostLoad : public PostStmt {
|
||||
|
||||
class PostStore : public PostStmt {
|
||||
public:
|
||||
PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0)
|
||||
PostStore(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: PostStmt(S, PostStoreKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
@ -287,7 +283,8 @@ class PostStore : public PostStmt {
|
||||
|
||||
class PostLValue : public PostStmt {
|
||||
public:
|
||||
PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0)
|
||||
PostLValue(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: PostStmt(S, PostLValueKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
@ -297,8 +294,8 @@ class PostLValue : public PostStmt {
|
||||
|
||||
class PostPurgeDeadSymbols : public PostStmt {
|
||||
public:
|
||||
PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L,
|
||||
const void *tag = 0)
|
||||
PostPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
@ -308,14 +305,17 @@ class PostPurgeDeadSymbols : public PostStmt {
|
||||
|
||||
class BlockEdge : public ProgramPoint {
|
||||
public:
|
||||
BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L)
|
||||
: ProgramPoint(B1, B2, BlockEdgeKind, L) {}
|
||||
BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L)
|
||||
: ProgramPoint(B1, B2, BlockEdgeKind, L) {
|
||||
assert(B1 && "BlockEdge: source block must be non-null");
|
||||
assert(B2 && "BlockEdge: destination block must be non-null");
|
||||
}
|
||||
|
||||
const CFGBlock* getSrc() const {
|
||||
const CFGBlock *getSrc() const {
|
||||
return static_cast<const CFGBlock*>(getData1());
|
||||
}
|
||||
|
||||
const CFGBlock* getDst() const {
|
||||
const CFGBlock *getDst() const {
|
||||
return static_cast<const CFGBlock*>(getData2());
|
||||
}
|
||||
|
||||
@ -365,6 +365,29 @@ class CallExit : public StmtPoint {
|
||||
}
|
||||
};
|
||||
|
||||
/// 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.
|
||||
class ProgramPointTag {
|
||||
public:
|
||||
ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {}
|
||||
virtual ~ProgramPointTag();
|
||||
virtual StringRef getTagDescription() const = 0;
|
||||
|
||||
protected:
|
||||
/// Used to implement 'classof' in subclasses.
|
||||
const void *getTagKind() { return TagKind; }
|
||||
|
||||
private:
|
||||
const void *TagKind;
|
||||
};
|
||||
|
||||
class SimpleProgramPointTag : public ProgramPointTag {
|
||||
std::string desc;
|
||||
public:
|
||||
SimpleProgramPointTag(StringRef description);
|
||||
StringRef getTagDescription() const;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
@ -385,12 +408,12 @@ static inline clang::ProgramPoint getTombstoneKey() {
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::ProgramPoint& Loc) {
|
||||
static unsigned getHashValue(const clang::ProgramPoint &Loc) {
|
||||
return Loc.getHashValue();
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::ProgramPoint& L,
|
||||
const clang::ProgramPoint& R) {
|
||||
static bool isEqual(const clang::ProgramPoint &L,
|
||||
const clang::ProgramPoint &R) {
|
||||
return L == R;
|
||||
}
|
||||
|
||||
|
@ -62,16 +62,16 @@ struct DeclBitVector_Types {
|
||||
AnalysisDataTy() : NDecls(0) {}
|
||||
virtual ~AnalysisDataTy() {}
|
||||
|
||||
bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); }
|
||||
bool isTracked(const NamedDecl *SD) { return DMap.find(SD) != DMap.end(); }
|
||||
|
||||
Idx getIdx(const NamedDecl* SD) const {
|
||||
Idx getIdx(const NamedDecl *SD) const {
|
||||
DMapTy::const_iterator I = DMap.find(SD);
|
||||
return I == DMap.end() ? Idx() : Idx(I->second);
|
||||
}
|
||||
|
||||
unsigned getNumDecls() const { return NDecls; }
|
||||
|
||||
void Register(const NamedDecl* SD) {
|
||||
void Register(const NamedDecl *SD) {
|
||||
if (!isTracked(SD)) DMap[SD] = NDecls++;
|
||||
}
|
||||
|
||||
@ -117,11 +117,11 @@ struct DeclBitVector_Types {
|
||||
}
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const NamedDecl* ND, const AnalysisDataTy& AD) {
|
||||
operator()(const NamedDecl *ND, const AnalysisDataTy& AD) {
|
||||
return getBit(AD.getIdx(ND));
|
||||
}
|
||||
|
||||
bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const {
|
||||
bool operator()(const NamedDecl *ND, const AnalysisDataTy& AD) const {
|
||||
return getBit(AD.getIdx(ND));
|
||||
}
|
||||
|
||||
@ -171,14 +171,14 @@ struct StmtDeclBitVector_Types {
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy {
|
||||
ASTContext* ctx;
|
||||
ASTContext *ctx;
|
||||
CFG* cfg;
|
||||
public:
|
||||
AnalysisDataTy() : ctx(0), cfg(0) {}
|
||||
virtual ~AnalysisDataTy() {}
|
||||
|
||||
void setContext(ASTContext& c) { ctx = &c; }
|
||||
ASTContext& getContext() {
|
||||
void setContext(ASTContext &c) { ctx = &c; }
|
||||
ASTContext &getContext() {
|
||||
assert(ctx && "ASTContext should not be NULL.");
|
||||
return *ctx;
|
||||
}
|
||||
@ -186,10 +186,10 @@ struct StmtDeclBitVector_Types {
|
||||
void setCFG(CFG& c) { cfg = &c; }
|
||||
CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
|
||||
|
||||
bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
|
||||
bool isTracked(const Stmt *S) { return cfg->isBlkExpr(S); }
|
||||
using DeclBitVector_Types::AnalysisDataTy::isTracked;
|
||||
|
||||
unsigned getIdx(const Stmt* S) const {
|
||||
unsigned getIdx(const Stmt *S) const {
|
||||
CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
|
||||
assert(I && "Stmtession not tracked for bitvector.");
|
||||
return I;
|
||||
@ -248,11 +248,11 @@ struct StmtDeclBitVector_Types {
|
||||
}
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const Stmt* S, const AnalysisDataTy& AD) {
|
||||
operator()(const Stmt *S, const AnalysisDataTy& AD) {
|
||||
return BlkExprBV[AD.getIdx(S)];
|
||||
}
|
||||
const llvm::BitVector::reference
|
||||
operator()(const Stmt* S, const AnalysisDataTy& AD) const {
|
||||
operator()(const Stmt *S, const AnalysisDataTy& AD) const {
|
||||
return const_cast<ValTy&>(*this)(S,AD);
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@ static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \
|
||||
static_cast<CLASS##Decl*>(D)); \
|
||||
break;
|
||||
|
||||
#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D) {}
|
||||
#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D)\
|
||||
#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D) {}
|
||||
#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D)\
|
||||
{ static_cast<ImplClass*>(this)->VisitVarDecl(D); }
|
||||
|
||||
|
||||
@ -38,23 +38,23 @@ template <typename ImplClass>
|
||||
class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
|
||||
public:
|
||||
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR) {
|
||||
void VisitDeclRefExpr(DeclRefExpr *DR) {
|
||||
static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
|
||||
}
|
||||
|
||||
void VisitDeclStmt(DeclStmt* DS) {
|
||||
void VisitDeclStmt(DeclStmt *DS) {
|
||||
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
|
||||
DI != DE; ++DI) {
|
||||
Decl* D = *DI;
|
||||
Decl *D = *DI;
|
||||
static_cast<ImplClass*>(this)->VisitDecl(D);
|
||||
// Visit the initializer.
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(D))
|
||||
if (Expr* I = VD->getInit())
|
||||
if (VarDecl *VD = dyn_cast<VarDecl>(D))
|
||||
if (Expr *I = VD->getInit())
|
||||
static_cast<ImplClass*>(this)->Visit(I);
|
||||
}
|
||||
}
|
||||
|
||||
void VisitDecl(Decl* D) {
|
||||
void VisitDecl(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
DISPATCH_CASE(Function)
|
||||
DISPATCH_CASE(CXXMethod)
|
||||
@ -69,7 +69,7 @@ class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
|
||||
DISPATCH_CASE(UsingDirective)
|
||||
DISPATCH_CASE(Using)
|
||||
default:
|
||||
assert(false && "Subtype of ScopedDecl not handled.");
|
||||
llvm_unreachable("Subtype of ScopedDecl not handled.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ template <typename ImplClass>
|
||||
class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
|
||||
public:
|
||||
|
||||
void VisitStmt(Stmt* S) {
|
||||
void VisitStmt(Stmt *S) {
|
||||
static_cast< ImplClass* >(this)->VisitChildren(S);
|
||||
}
|
||||
|
||||
@ -45,13 +45,13 @@ break;
|
||||
CONDVAR_CASE(WhileStmt)
|
||||
#undef CONDVAR_CASE
|
||||
default:
|
||||
assert(false && "Infeasible");
|
||||
llvm_unreachable("Infeasible");
|
||||
}
|
||||
static_cast<ImplClass*>(this)->Visit(CondVar->getInit());
|
||||
}
|
||||
|
||||
// Defining operator() allows the visitor to be used as a C++ style functor.
|
||||
void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
|
||||
void operator()(Stmt *S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -33,7 +33,7 @@ static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
|
||||
|
||||
template <typename ImplClass, typename RetTy=void>
|
||||
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
Stmt* CurrentBlkStmt;
|
||||
Stmt *CurrentBlkStmt;
|
||||
|
||||
struct NullifyStmt {
|
||||
Stmt*& S;
|
||||
@ -45,9 +45,9 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
public:
|
||||
CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
|
||||
|
||||
Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
|
||||
Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; }
|
||||
|
||||
RetTy Visit(Stmt* S) {
|
||||
RetTy Visit(Stmt *S) {
|
||||
if (S == CurrentBlkStmt ||
|
||||
!static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
|
||||
return StmtVisitor<ImplClass,RetTy>::Visit(S);
|
||||
@ -67,7 +67,7 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
/// the list of statements in a CFGBlock. For substatements, or when there
|
||||
/// is no implementation provided for a BlockStmt_XXX method, we default
|
||||
/// to using StmtVisitor's Visit method.
|
||||
RetTy BlockStmt_Visit(Stmt* S) {
|
||||
RetTy BlockStmt_Visit(Stmt *S) {
|
||||
CurrentBlkStmt = S;
|
||||
NullifyStmt cleanup(CurrentBlkStmt);
|
||||
|
||||
@ -106,23 +106,23 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
|
||||
DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator)
|
||||
|
||||
RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
|
||||
RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt* S) {
|
||||
RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
|
||||
RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitExpr(Expr* E) {
|
||||
RetTy BlockStmt_VisitExpr(Expr *E) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitStmt(Stmt* S) {
|
||||
RetTy BlockStmt_VisitStmt(Stmt *S) {
|
||||
return static_cast<ImplClass*>(this)->Visit(S);
|
||||
}
|
||||
|
||||
@ -141,14 +141,14 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// VisitChildren: Call "Visit" on each child of S.
|
||||
void VisitChildren(Stmt* S) {
|
||||
void VisitChildren(Stmt *S) {
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case Stmt::StmtExprClass: {
|
||||
CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt();
|
||||
CompoundStmt *CS = cast<StmtExpr>(S)->getSubStmt();
|
||||
if (CS->body_empty()) return;
|
||||
static_cast<ImplClass*>(this)->Visit(CS->body_back());
|
||||
return;
|
||||
|
@ -54,7 +54,9 @@ class ExprArgument<string name> : Argument<name>;
|
||||
class FunctionArgument<string name> : Argument<name>;
|
||||
class TypeArgument<string name> : Argument<name>;
|
||||
class UnsignedArgument<string name> : Argument<name>;
|
||||
class SourceLocArgument<string name> : Argument<name>;
|
||||
class VariadicUnsignedArgument<string name> : Argument<name>;
|
||||
class VariadicExprArgument<string name> : Argument<name>;
|
||||
|
||||
// A version of the form major.minor[.subminor].
|
||||
class VersionArgument<string name> : Argument<name>;
|
||||
@ -89,7 +91,9 @@ class Attr {
|
||||
// The attribute will not be permitted in C++0x attribute-specifiers if
|
||||
// this is empty; the empty string can be used as a namespace.
|
||||
list<string> Namespaces = [];
|
||||
// Any additional text that should be included verbatim in the class.
|
||||
// Set to true for attributes with arguments which require delayed parsing.
|
||||
bit LateParsed = 0;
|
||||
// Any additional text that should be included verbatim in the class.
|
||||
code AdditionalMembers = [{}];
|
||||
}
|
||||
|
||||
@ -110,7 +114,7 @@ def Alias : InheritableAttr {
|
||||
}
|
||||
|
||||
def Aligned : InheritableAttr {
|
||||
let Spellings = ["align", "aligned"];
|
||||
let Spellings = ["aligned"];
|
||||
let Subjects = [NonBitField, NormalVar, Tag];
|
||||
let Args = [AlignedArgument<"Alignment">];
|
||||
let Namespaces = ["", "std"];
|
||||
@ -128,7 +132,7 @@ def AnalyzerNoReturn : InheritableAttr {
|
||||
let Spellings = ["analyzer_noreturn"];
|
||||
}
|
||||
|
||||
def Annotate : InheritableAttr {
|
||||
def Annotate : InheritableParamAttr {
|
||||
let Spellings = ["annotate"];
|
||||
let Args = [StringArgument<"Annotation">];
|
||||
}
|
||||
@ -167,6 +171,23 @@ def CDecl : InheritableAttr {
|
||||
let Spellings = ["cdecl", "__cdecl"];
|
||||
}
|
||||
|
||||
// cf_audited_transfer indicates that the given function has been
|
||||
// audited and has been marked with the appropriate cf_consumed and
|
||||
// cf_returns_retained attributes. It is generally applied by
|
||||
// '#pragma clang arc_cf_code_audited' rather than explicitly.
|
||||
def CFAuditedTransfer : InheritableAttr {
|
||||
let Spellings = ["cf_audited_transfer"];
|
||||
let Subjects = [Function];
|
||||
}
|
||||
|
||||
// cf_unknown_transfer is an explicit opt-out of cf_audited_transfer.
|
||||
// It indicates that the function has unknown or unautomatable
|
||||
// transfer semantics.
|
||||
def CFUnknownTransfer : InheritableAttr {
|
||||
let Spellings = ["cf_unknown_transfer"];
|
||||
let Subjects = [Function];
|
||||
}
|
||||
|
||||
def CFReturnsRetained : InheritableAttr {
|
||||
let Spellings = ["cf_returns_retained"];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
@ -284,7 +305,7 @@ def IBOutlet : InheritableAttr {
|
||||
|
||||
def IBOutletCollection : InheritableAttr {
|
||||
let Spellings = ["iboutletcollection"];
|
||||
let Args = [TypeArgument<"InterFace">];
|
||||
let Args = [TypeArgument<"Interface">, SourceLocArgument<"InterfaceLoc">];
|
||||
}
|
||||
|
||||
def Malloc : InheritableAttr {
|
||||
@ -317,6 +338,10 @@ def Naked : InheritableAttr {
|
||||
let Spellings = ["naked"];
|
||||
}
|
||||
|
||||
def ReturnsTwice : InheritableAttr {
|
||||
let Spellings = ["returns_twice"];
|
||||
}
|
||||
|
||||
def NoCommon : InheritableAttr {
|
||||
let Spellings = ["nocommon"];
|
||||
}
|
||||
@ -358,6 +383,12 @@ def NoThrow : InheritableAttr {
|
||||
let Spellings = ["nothrow"];
|
||||
}
|
||||
|
||||
def NSBridged : InheritableAttr {
|
||||
let Spellings = ["ns_bridged"];
|
||||
let Subjects = [Record];
|
||||
let Args = [IdentifierArgument<"BridgedType">];
|
||||
}
|
||||
|
||||
def NSReturnsRetained : InheritableAttr {
|
||||
let Spellings = ["ns_returns_retained"];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
@ -405,6 +436,11 @@ def ObjCPreciseLifetime : Attr {
|
||||
let Subjects = [Var];
|
||||
}
|
||||
|
||||
def ObjCReturnsInnerPointer : Attr {
|
||||
let Spellings = ["objc_returns_inner_pointer"];
|
||||
let Subjects = [ObjCMethod];
|
||||
}
|
||||
|
||||
def Overloadable : Attr {
|
||||
let Spellings = ["overloadable"];
|
||||
}
|
||||
@ -533,3 +569,108 @@ def WeakRef : InheritableAttr {
|
||||
def X86ForceAlignArgPointer : InheritableAttr {
|
||||
let Spellings = [];
|
||||
}
|
||||
|
||||
|
||||
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
|
||||
|
||||
def GuardedVar : InheritableAttr {
|
||||
let Spellings = ["guarded_var"];
|
||||
}
|
||||
|
||||
def PtGuardedVar : InheritableAttr {
|
||||
let Spellings = ["pt_guarded_var"];
|
||||
}
|
||||
|
||||
def Lockable : InheritableAttr {
|
||||
let Spellings = ["lockable"];
|
||||
}
|
||||
|
||||
def ScopedLockable : InheritableAttr {
|
||||
let Spellings = ["scoped_lockable"];
|
||||
}
|
||||
|
||||
def NoThreadSafetyAnalysis : InheritableAttr {
|
||||
let Spellings = ["no_thread_safety_analysis"];
|
||||
}
|
||||
|
||||
def GuardedBy : InheritableAttr {
|
||||
let Spellings = ["guarded_by"];
|
||||
let Args = [ExprArgument<"Arg">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def PtGuardedBy : InheritableAttr {
|
||||
let Spellings = ["pt_guarded_by"];
|
||||
let Args = [ExprArgument<"Arg">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def AcquiredAfter : InheritableAttr {
|
||||
let Spellings = ["acquired_after"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def AcquiredBefore : InheritableAttr {
|
||||
let Spellings = ["acquired_before"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def ExclusiveLockFunction : InheritableAttr {
|
||||
let Spellings = ["exclusive_lock_function"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def SharedLockFunction : InheritableAttr {
|
||||
let Spellings = ["shared_lock_function"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
// The first argument is an integer or boolean value specifying the return value
|
||||
// of a successful lock acquisition.
|
||||
def ExclusiveTrylockFunction : InheritableAttr {
|
||||
let Spellings = ["exclusive_trylock_function"];
|
||||
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
// The first argument is an integer or boolean value specifying the return value
|
||||
// of a successful lock acquisition.
|
||||
def SharedTrylockFunction : InheritableAttr {
|
||||
let Spellings = ["shared_trylock_function"];
|
||||
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def UnlockFunction : InheritableAttr {
|
||||
let Spellings = ["unlock_function"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def LockReturned : InheritableAttr {
|
||||
let Spellings = ["lock_returned"];
|
||||
let Args = [ExprArgument<"Arg">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def LocksExcluded : InheritableAttr {
|
||||
let Spellings = ["locks_excluded"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def ExclusiveLocksRequired : InheritableAttr {
|
||||
let Spellings = ["exclusive_locks_required"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
||||
def SharedLocksRequired : InheritableAttr {
|
||||
let Spellings = ["shared_locks_required"];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
// A -> "reference" to __builtin_va_list
|
||||
// V -> Vector, following num elements and a base type.
|
||||
// X -> _Complex, followed by the base type.
|
||||
// Y -> ptrdiff_t
|
||||
// P -> FILE
|
||||
// J -> jmp_buf
|
||||
// SJ -> sigjmp_buf
|
||||
@ -76,6 +77,7 @@
|
||||
// in that it accepts its arguments as a va_list rather than
|
||||
// through an ellipsis
|
||||
// e -> const, but only when -fmath-errno=0
|
||||
// j -> returns_twice (like setjmp)
|
||||
// FIXME: gcc has nonnull
|
||||
|
||||
#if defined(BUILTIN) && !defined(LIBBUILTIN)
|
||||
@ -96,9 +98,9 @@ BUILTIN(__builtin_fabsl, "LdLd", "ncF")
|
||||
BUILTIN(__builtin_fmod , "ddd" , "Fnc")
|
||||
BUILTIN(__builtin_fmodf, "fff" , "Fnc")
|
||||
BUILTIN(__builtin_fmodl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_frexp , "ddi*" , "Fnc")
|
||||
BUILTIN(__builtin_frexpf, "ffi*" , "Fnc")
|
||||
BUILTIN(__builtin_frexpl, "LdLdi*", "Fnc")
|
||||
BUILTIN(__builtin_frexp , "ddi*" , "Fn")
|
||||
BUILTIN(__builtin_frexpf, "ffi*" , "Fn")
|
||||
BUILTIN(__builtin_frexpl, "LdLdi*", "Fn")
|
||||
BUILTIN(__builtin_huge_val, "d", "nc")
|
||||
BUILTIN(__builtin_huge_valf, "f", "nc")
|
||||
BUILTIN(__builtin_huge_vall, "Ld", "nc")
|
||||
@ -108,9 +110,9 @@ BUILTIN(__builtin_infl , "Ld" , "nc")
|
||||
BUILTIN(__builtin_ldexp , "ddi" , "Fnc")
|
||||
BUILTIN(__builtin_ldexpf, "ffi" , "Fnc")
|
||||
BUILTIN(__builtin_ldexpl, "LdLdi", "Fnc")
|
||||
BUILTIN(__builtin_modf , "ddd*" , "Fnc")
|
||||
BUILTIN(__builtin_modff, "fff*" , "Fnc")
|
||||
BUILTIN(__builtin_modfl, "LdLdLd*", "Fnc")
|
||||
BUILTIN(__builtin_modf , "ddd*" , "Fn")
|
||||
BUILTIN(__builtin_modff, "fff*" , "Fn")
|
||||
BUILTIN(__builtin_modfl, "LdLdLd*", "Fn")
|
||||
BUILTIN(__builtin_nan, "dcC*" , "ncF")
|
||||
BUILTIN(__builtin_nanf, "fcC*" , "ncF")
|
||||
BUILTIN(__builtin_nanl, "LdcC*", "ncF")
|
||||
@ -233,9 +235,9 @@ BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_remainder , "ddd", "Fnc")
|
||||
BUILTIN(__builtin_remainderf, "fff", "Fnc")
|
||||
BUILTIN(__builtin_remainderl, "LdLdLd", "Fnc")
|
||||
BUILTIN(__builtin_remquo , "dddi*", "Fnc")
|
||||
BUILTIN(__builtin_remquof, "fffi*", "Fnc")
|
||||
BUILTIN(__builtin_remquol, "LdLdLdi*", "Fnc")
|
||||
BUILTIN(__builtin_remquo , "dddi*", "Fn")
|
||||
BUILTIN(__builtin_remquof, "fffi*", "Fn")
|
||||
BUILTIN(__builtin_remquol, "LdLdLdi*", "Fn")
|
||||
BUILTIN(__builtin_rint , "dd", "Fnc")
|
||||
BUILTIN(__builtin_rintf, "ff", "Fnc")
|
||||
BUILTIN(__builtin_rintl, "LdLd", "Fnc")
|
||||
@ -388,7 +390,7 @@ BUILTIN(__builtin_constant_p, "i.", "nct")
|
||||
BUILTIN(__builtin_classify_type, "i.", "nct")
|
||||
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
|
||||
BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc")
|
||||
BUILTIN(__builtin_va_start, "vA.", "n")
|
||||
BUILTIN(__builtin_va_start, "vA.", "nt")
|
||||
BUILTIN(__builtin_va_end, "vA", "n")
|
||||
BUILTIN(__builtin_va_copy, "vAA", "n")
|
||||
BUILTIN(__builtin_stdarg_start, "vA.", "n")
|
||||
@ -426,7 +428,7 @@ BUILTIN(__builtin_return_address, "v*IUi", "n")
|
||||
BUILTIN(__builtin_extract_return_addr, "v*v*", "n")
|
||||
BUILTIN(__builtin_frame_address, "v*IUi", "n")
|
||||
BUILTIN(__builtin_flt_rounds, "i", "nc")
|
||||
BUILTIN(__builtin_setjmp, "iv**", "")
|
||||
BUILTIN(__builtin_setjmp, "iv**", "j")
|
||||
BUILTIN(__builtin_longjmp, "vv**i", "r")
|
||||
BUILTIN(__builtin_unwind_init, "v", "")
|
||||
BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc")
|
||||
@ -584,12 +586,21 @@ BUILTIN(__sync_swap_4, "iiD*i.", "n")
|
||||
BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "n")
|
||||
BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "n")
|
||||
|
||||
|
||||
BUILTIN(__atomic_load, "v.", "t")
|
||||
BUILTIN(__atomic_store, "v.", "t")
|
||||
BUILTIN(__atomic_exchange, "v.", "t")
|
||||
BUILTIN(__atomic_compare_exchange_strong, "v.", "t")
|
||||
BUILTIN(__atomic_compare_exchange_weak, "v.", "t")
|
||||
BUILTIN(__atomic_fetch_add, "v.", "t")
|
||||
BUILTIN(__atomic_fetch_sub, "v.", "t")
|
||||
BUILTIN(__atomic_fetch_and, "v.", "t")
|
||||
BUILTIN(__atomic_fetch_or, "v.", "t")
|
||||
BUILTIN(__atomic_fetch_xor, "v.", "t")
|
||||
BUILTIN(__atomic_thread_fence, "vi", "n")
|
||||
BUILTIN(__atomic_signal_fence, "vi", "n")
|
||||
|
||||
// Non-overloaded atomic builtins.
|
||||
BUILTIN(__sync_synchronize, "v.", "n")
|
||||
// LLVM instruction builtin [Clang extension].
|
||||
BUILTIN(__builtin_llvm_memory_barrier,"vbbbbb", "n")
|
||||
// GCC does not support these, they are a Clang extension.
|
||||
BUILTIN(__sync_fetch_and_min, "iiD*i", "n")
|
||||
BUILTIN(__sync_fetch_and_max, "iiD*i", "n")
|
||||
@ -661,9 +672,26 @@ LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES)
|
||||
// POSIX unistd.h
|
||||
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(vfork, "iJ", "fj", "unistd.h", ALL_LANGUAGES)
|
||||
// POSIX setjmp.h
|
||||
|
||||
// In some systems setjmp is a macro that expands to _setjmp. We undefine
|
||||
// it here to avoid having two identical LIBBUILTIN entries.
|
||||
#undef setjmp
|
||||
LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(__sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(getcontext, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES)
|
||||
// non-standard but very common
|
||||
LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
|
||||
// id objc_msgSend(id, SEL, ...)
|
||||
LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG)
|
||||
|
||||
@ -687,8 +715,7 @@ LIBBUILTIN(objc_read_weak, "GG*", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_weak(id value, id *location)
|
||||
LIBBUILTIN(objc_assign_weak, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_ivar(id value, id dest, ptrdiff_t offset)
|
||||
// FIXME. Darwin has ptrdiff_t typedef'ed to int.
|
||||
LIBBUILTIN(objc_assign_ivar, "GGGi", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
LIBBUILTIN(objc_assign_ivar, "GGGY", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_global(id val, id *dest)
|
||||
LIBBUILTIN(objc_assign_global, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
|
||||
// id objc_assign_strongCast(id val, id *dest
|
||||
@ -738,5 +765,8 @@ LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
|
||||
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
|
||||
|
||||
// Annotation function
|
||||
BUILTIN(__builtin_annotation, "UiUicC*", "nc")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LIBBUILTIN
|
||||
|
@ -15,16 +15,13 @@
|
||||
#ifndef LLVM_CLANG_BASIC_BUILTINS_H
|
||||
#define LLVM_CLANG_BASIC_BUILTINS_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include <cstring>
|
||||
|
||||
// VC++ defines 'alloca' as an object-like macro, which interferes with our
|
||||
// builtins.
|
||||
#undef alloca
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> class SmallVectorImpl;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
@ -65,15 +62,18 @@ class Context {
|
||||
const Info *TSRecords;
|
||||
unsigned NumTSRecords;
|
||||
public:
|
||||
Context(const TargetInfo &Target);
|
||||
Context();
|
||||
|
||||
/// \brief Perform target-specific initialization
|
||||
void InitializeTarget(const TargetInfo &Target);
|
||||
|
||||
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
|
||||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
|
||||
/// such.
|
||||
void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts);
|
||||
|
||||
/// \brief Popular the vector with the names of all of the builtins.
|
||||
void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
|
||||
void GetBuiltinNames(SmallVectorImpl<const char *> &Names,
|
||||
bool NoBuiltins);
|
||||
|
||||
/// Builtin::GetName - Return the identifier name for the specified builtin,
|
||||
@ -103,6 +103,11 @@ class Context {
|
||||
return strchr(GetRecord(ID).Attributes, 'r') != 0;
|
||||
}
|
||||
|
||||
/// isReturnsTwice - Return true if we know this builtin can return twice.
|
||||
bool isReturnsTwice(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'j') != 0;
|
||||
}
|
||||
|
||||
/// isLibFunction - Return true if this is a builtin for a libc/libm function,
|
||||
/// with a "__builtin_" prefix (e.g. __builtin_abs).
|
||||
bool isLibFunction(unsigned ID) const {
|
||||
|
@ -74,3 +74,4 @@ def Friend : Decl;
|
||||
def FriendTemplate : Decl;
|
||||
def StaticAssert : Decl;
|
||||
def Block : Decl, DeclContext;
|
||||
def ClassScopeFunctionSpecialization : Decl;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
|
||||
#define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
@ -66,7 +67,7 @@ class DelayedCleanupPool {
|
||||
}
|
||||
|
||||
void doCleanup() {
|
||||
for (llvm::SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator
|
||||
for (SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator
|
||||
I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I)
|
||||
I->second(I->first);
|
||||
Cleanups.clear();
|
||||
@ -79,7 +80,7 @@ class DelayedCleanupPool {
|
||||
|
||||
private:
|
||||
llvm::DenseMap<void *, CleanupFn> Ptrs;
|
||||
llvm::SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups;
|
||||
SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups;
|
||||
|
||||
template <typename T>
|
||||
static void cleanupWithDelete(void *ptr) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "clang/Basic/DiagnosticIDs.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
@ -25,7 +26,7 @@
|
||||
#include <list>
|
||||
|
||||
namespace clang {
|
||||
class DiagnosticClient;
|
||||
class DiagnosticConsumer;
|
||||
class DiagnosticBuilder;
|
||||
class IdentifierInfo;
|
||||
class DeclContext;
|
||||
@ -64,7 +65,7 @@ class FixItHint {
|
||||
/// \brief Create a code modification hint that inserts the given
|
||||
/// code string at a specific location.
|
||||
static FixItHint CreateInsertion(SourceLocation InsertionLoc,
|
||||
llvm::StringRef Code) {
|
||||
StringRef Code) {
|
||||
FixItHint Hint;
|
||||
Hint.RemoveRange =
|
||||
CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
|
||||
@ -86,7 +87,7 @@ class FixItHint {
|
||||
/// \brief Create a code modification hint that replaces the given
|
||||
/// source range with the given code string.
|
||||
static FixItHint CreateReplacement(CharSourceRange RemoveRange,
|
||||
llvm::StringRef Code) {
|
||||
StringRef Code) {
|
||||
FixItHint Hint;
|
||||
Hint.RemoveRange = RemoveRange;
|
||||
Hint.CodeToInsert = Code;
|
||||
@ -94,17 +95,17 @@ class FixItHint {
|
||||
}
|
||||
|
||||
static FixItHint CreateReplacement(SourceRange RemoveRange,
|
||||
llvm::StringRef Code) {
|
||||
StringRef Code) {
|
||||
return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code);
|
||||
}
|
||||
};
|
||||
|
||||
/// Diagnostic - This concrete class is used by the front-end to report
|
||||
/// DiagnosticsEngine - This concrete class is used by the front-end to report
|
||||
/// problems and issues. It massages the diagnostics (e.g. handling things like
|
||||
/// "report warnings as errors" and passes them off to the DiagnosticClient for
|
||||
/// reporting to the user. Diagnostic is tied to one translation unit and
|
||||
/// one SourceManager.
|
||||
class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// "report warnings as errors" and passes them off to the DiagnosticConsumer
|
||||
/// for reporting to the user. DiagnosticsEngine is tied to one translation unit
|
||||
/// and one SourceManager.
|
||||
class DiagnosticsEngine : public llvm::RefCountedBase<DiagnosticsEngine> {
|
||||
public:
|
||||
/// Level - The level of the diagnostic, after it has been through mapping.
|
||||
enum Level {
|
||||
@ -148,7 +149,8 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
private:
|
||||
unsigned char AllExtensionsSilenced; // Used by __extension__
|
||||
bool IgnoreAllWarnings; // Ignore all warnings: -w
|
||||
bool WarningsAsErrors; // Treat warnings like errors:
|
||||
bool WarningsAsErrors; // Treat warnings like errors.
|
||||
bool EnableAllWarnings; // Enable all warnings.
|
||||
bool ErrorsAsFatal; // Treat errors like fatal errors.
|
||||
bool SuppressSystemWarnings; // Suppress warnings in system headers.
|
||||
bool SuppressAllDiagnostics; // Suppress all diagnostics.
|
||||
@ -158,7 +160,7 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
// 0 -> no limit.
|
||||
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags;
|
||||
DiagnosticClient *Client;
|
||||
DiagnosticConsumer *Client;
|
||||
bool OwnsDiagClient;
|
||||
SourceManager *SourceMgr;
|
||||
|
||||
@ -173,22 +175,22 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// the state so that we know what is the diagnostic state at any given
|
||||
/// source location.
|
||||
class DiagState {
|
||||
llvm::DenseMap<unsigned, unsigned> DiagMap;
|
||||
llvm::DenseMap<unsigned, DiagnosticMappingInfo> DiagMap;
|
||||
|
||||
public:
|
||||
typedef llvm::DenseMap<unsigned, unsigned>::const_iterator iterator;
|
||||
typedef llvm::DenseMap<unsigned, DiagnosticMappingInfo>::iterator
|
||||
iterator;
|
||||
typedef llvm::DenseMap<unsigned, DiagnosticMappingInfo>::const_iterator
|
||||
const_iterator;
|
||||
|
||||
void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; }
|
||||
|
||||
diag::Mapping getMapping(diag::kind Diag) const {
|
||||
iterator I = DiagMap.find(Diag);
|
||||
if (I != DiagMap.end())
|
||||
return (diag::Mapping)I->second;
|
||||
return diag::Mapping();
|
||||
void setMappingInfo(diag::kind Diag, DiagnosticMappingInfo Info) {
|
||||
DiagMap[Diag] = Info;
|
||||
}
|
||||
|
||||
iterator begin() const { return DiagMap.begin(); }
|
||||
iterator end() const { return DiagMap.end(); }
|
||||
DiagnosticMappingInfo &getOrAddMappingInfo(diag::kind Diag);
|
||||
|
||||
const_iterator begin() const { return DiagMap.begin(); }
|
||||
const_iterator end() const { return DiagMap.end(); }
|
||||
};
|
||||
|
||||
/// \brief Keeps and automatically disposes all DiagStates that we create.
|
||||
@ -254,10 +256,10 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// \brief Indicates that an unrecoverable error has occurred.
|
||||
bool UnrecoverableErrorOccurred;
|
||||
|
||||
/// \brief Toggles for DiagnosticErrorTrap to check whether an error occurred
|
||||
/// \brief Counts for DiagnosticErrorTrap to check whether an error occurred
|
||||
/// during a parsing section, e.g. during parsing a function.
|
||||
bool TrapErrorOccurred;
|
||||
bool TrapUnrecoverableErrorOccurred;
|
||||
unsigned TrapNumErrorsOccurred;
|
||||
unsigned TrapNumUnrecoverableErrorsOccurred;
|
||||
|
||||
/// LastDiagLevel - This is the level of the last diagnostic emitted. This is
|
||||
/// used to emit continuation diagnostics with the same level as the
|
||||
@ -283,9 +285,9 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
const char *Argument, unsigned ArgumentLen,
|
||||
const ArgumentValue *PrevArgs,
|
||||
unsigned NumPrevArgs,
|
||||
llvm::SmallVectorImpl<char> &Output,
|
||||
SmallVectorImpl<char> &Output,
|
||||
void *Cookie,
|
||||
llvm::SmallVectorImpl<intptr_t> &QualTypeVals);
|
||||
SmallVectorImpl<intptr_t> &QualTypeVals);
|
||||
void *ArgToStringCookie;
|
||||
ArgToStringFnTy ArgToStringFn;
|
||||
|
||||
@ -301,21 +303,25 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
std::string DelayedDiagArg2;
|
||||
|
||||
public:
|
||||
explicit Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
|
||||
DiagnosticClient *client = 0,
|
||||
explicit DiagnosticsEngine(
|
||||
const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
|
||||
DiagnosticConsumer *client = 0,
|
||||
bool ShouldOwnClient = true);
|
||||
~Diagnostic();
|
||||
~DiagnosticsEngine();
|
||||
|
||||
const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
|
||||
return Diags;
|
||||
}
|
||||
|
||||
DiagnosticClient *getClient() { return Client; }
|
||||
const DiagnosticClient *getClient() const { return Client; }
|
||||
DiagnosticConsumer *getClient() { return Client; }
|
||||
const DiagnosticConsumer *getClient() const { return Client; }
|
||||
|
||||
/// \brief Determine whether this \c DiagnosticsEngine object own its client.
|
||||
bool ownsClient() const { return OwnsDiagClient; }
|
||||
|
||||
/// \brief Return the current diagnostic client along with ownership of that
|
||||
/// client.
|
||||
DiagnosticClient *takeClient() {
|
||||
DiagnosticConsumer *takeClient() {
|
||||
OwnsDiagClient = false;
|
||||
return Client;
|
||||
}
|
||||
@ -328,8 +334,8 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic characterization methods, used by a client to customize how
|
||||
// diagnostics are emitted.
|
||||
// DiagnosticsEngine characterization methods, used by a client to customize
|
||||
// how diagnostics are emitted.
|
||||
//
|
||||
|
||||
/// pushMappings - Copies the current DiagMappings and pushes the new copy
|
||||
@ -346,7 +352,7 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
///
|
||||
/// \param ShouldOwnClient true if the diagnostic object should take
|
||||
/// ownership of \c client.
|
||||
void setClient(DiagnosticClient *client, bool ShouldOwnClient = true);
|
||||
void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true);
|
||||
|
||||
/// setErrorLimit - Specify a limit for the number of errors we should
|
||||
/// emit before giving up. Zero disables the limit.
|
||||
@ -369,6 +375,12 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
|
||||
bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
|
||||
|
||||
/// setEnableAllWarnings - When set to true, any unmapped ignored warnings
|
||||
/// are no longer ignored. If this and IgnoreAllWarnings are both set,
|
||||
/// then that one wins.
|
||||
void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }
|
||||
bool getEnableAllWarnngs() const { return EnableAllWarnings; }
|
||||
|
||||
/// setWarningsAsErrors - When set to true, any warnings reported are issued
|
||||
/// as errors.
|
||||
void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
|
||||
@ -435,10 +447,20 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
///
|
||||
/// 'Loc' is the source location that this change of diagnostic state should
|
||||
/// take affect. It can be null if we are setting the state from command-line.
|
||||
bool setDiagnosticGroupMapping(llvm::StringRef Group, diag::Mapping Map,
|
||||
SourceLocation Loc = SourceLocation()) {
|
||||
return Diags->setDiagnosticGroupMapping(Group, Map, Loc, *this);
|
||||
}
|
||||
bool setDiagnosticGroupMapping(StringRef Group, diag::Mapping Map,
|
||||
SourceLocation Loc = SourceLocation());
|
||||
|
||||
/// \brief Set the warning-as-error flag for the given diagnostic group. This
|
||||
/// function always only operates on the current diagnostic state.
|
||||
///
|
||||
/// \returns True if the given group is unknown, false otherwise.
|
||||
bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled);
|
||||
|
||||
/// \brief Set the error-as-fatal flag for the given diagnostic group. This
|
||||
/// function always only operates on the current diagnostic state.
|
||||
///
|
||||
/// \returns True if the given group is unknown, false otherwise.
|
||||
bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled);
|
||||
|
||||
bool hasErrorOccurred() const { return ErrorOccurred; }
|
||||
bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
|
||||
@ -457,7 +479,7 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
|
||||
/// and level. If this is the first request for this diagnosic, it is
|
||||
/// registered and created, otherwise the existing ID is returned.
|
||||
unsigned getCustomDiagID(Level L, llvm::StringRef Message) {
|
||||
unsigned getCustomDiagID(Level L, StringRef Message) {
|
||||
return Diags->getCustomDiagID((DiagnosticIDs::Level)L, Message);
|
||||
}
|
||||
|
||||
@ -467,8 +489,8 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
const char *Modifier, unsigned ModLen,
|
||||
const char *Argument, unsigned ArgLen,
|
||||
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
|
||||
llvm::SmallVectorImpl<char> &Output,
|
||||
llvm::SmallVectorImpl<intptr_t> &QualTypeVals) const {
|
||||
SmallVectorImpl<char> &Output,
|
||||
SmallVectorImpl<intptr_t> &QualTypeVals) const {
|
||||
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
|
||||
PrevArgs, NumPrevArgs, Output, ArgToStringCookie,
|
||||
QualTypeVals);
|
||||
@ -484,18 +506,17 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
void Reset();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic classification and reporting interfaces.
|
||||
// DiagnosticsEngine classification and reporting interfaces.
|
||||
//
|
||||
|
||||
/// \brief Based on the way the client configured the Diagnostic
|
||||
/// \brief Based on the way the client configured the DiagnosticsEngine
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
/// the DiagnosticClient.
|
||||
/// the DiagnosticConsumer.
|
||||
///
|
||||
/// \param Loc The source location we are interested in finding out the
|
||||
/// diagnostic state. Can be null in order to query the latest state.
|
||||
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
|
||||
diag::Mapping *mapping = 0) const {
|
||||
return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this, mapping);
|
||||
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const {
|
||||
return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this);
|
||||
}
|
||||
|
||||
/// Report - Issue the message to the client. @c DiagID is a member of the
|
||||
@ -527,13 +548,13 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
///
|
||||
/// \param Arg1 A string argument that will be provided to the
|
||||
/// diagnostic. A copy of this string will be stored in the
|
||||
/// Diagnostic object itself.
|
||||
/// DiagnosticsEngine object itself.
|
||||
///
|
||||
/// \param Arg2 A string argument that will be provided to the
|
||||
/// diagnostic. A copy of this string will be stored in the
|
||||
/// Diagnostic object itself.
|
||||
void SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1 = "",
|
||||
llvm::StringRef Arg2 = "");
|
||||
/// DiagnosticsEngine object itself.
|
||||
void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "",
|
||||
StringRef Arg2 = "");
|
||||
|
||||
/// \brief Clear out the current diagnostic.
|
||||
void Clear() { CurDiagID = ~0U; }
|
||||
@ -542,23 +563,6 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// \brief Report the delayed diagnostic.
|
||||
void ReportDelayed();
|
||||
|
||||
|
||||
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
|
||||
/// specified builtin diagnostic. This returns the high bit encoding, or zero
|
||||
/// if the field is completely uninitialized.
|
||||
diag::Mapping getDiagnosticMappingInfo(diag::kind Diag,
|
||||
DiagState *State) const {
|
||||
return State->getMapping(Diag);
|
||||
}
|
||||
|
||||
void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map,
|
||||
DiagState *State,
|
||||
bool isUser, bool isPragma) const {
|
||||
if (isUser) Map |= 8; // Set the high bit for user mappings.
|
||||
if (isPragma) Map |= 0x10; // Set the bit for diagnostic pragma mappings.
|
||||
State->setMapping((diag::kind)DiagId, Map);
|
||||
}
|
||||
|
||||
// This is private state used by DiagnosticBuilder. We put it here instead of
|
||||
// in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight
|
||||
// object. This implementation choice means that we can only have one
|
||||
@ -567,7 +571,7 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
// diagnostic is in flight at a time.
|
||||
friend class DiagnosticIDs;
|
||||
friend class DiagnosticBuilder;
|
||||
friend class DiagnosticInfo;
|
||||
friend class Diagnostic;
|
||||
friend class PartialDiagnostic;
|
||||
friend class DiagnosticErrorTrap;
|
||||
|
||||
@ -614,7 +618,7 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// only support 10 ranges, could easily be extended if needed.
|
||||
CharSourceRange DiagRanges[10];
|
||||
|
||||
enum { MaxFixItHints = 3 };
|
||||
enum { MaxFixItHints = 6 };
|
||||
|
||||
/// FixItHints - If valid, provides a hint with some code
|
||||
/// to insert, remove, or modify at a particular position.
|
||||
@ -637,28 +641,30 @@ class Diagnostic : public llvm::RefCountedBase<Diagnostic> {
|
||||
/// between the time the instance was created and the time it was
|
||||
/// queried.
|
||||
class DiagnosticErrorTrap {
|
||||
Diagnostic &Diag;
|
||||
DiagnosticsEngine &Diag;
|
||||
unsigned NumErrors;
|
||||
unsigned NumUnrecoverableErrors;
|
||||
|
||||
public:
|
||||
explicit DiagnosticErrorTrap(Diagnostic &Diag)
|
||||
explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag)
|
||||
: Diag(Diag) { reset(); }
|
||||
|
||||
/// \brief Determine whether any errors have occurred since this
|
||||
/// object instance was created.
|
||||
bool hasErrorOccurred() const {
|
||||
return Diag.TrapErrorOccurred;
|
||||
return Diag.TrapNumErrorsOccurred > NumErrors;
|
||||
}
|
||||
|
||||
/// \brief Determine whether any unrecoverable errors have occurred since this
|
||||
/// object instance was created.
|
||||
bool hasUnrecoverableErrorOccurred() const {
|
||||
return Diag.TrapUnrecoverableErrorOccurred;
|
||||
return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors;
|
||||
}
|
||||
|
||||
// Set to initial state of "no errors occurred".
|
||||
void reset() {
|
||||
Diag.TrapErrorOccurred = false;
|
||||
Diag.TrapUnrecoverableErrorOccurred = false;
|
||||
NumErrors = Diag.TrapNumErrorsOccurred;
|
||||
NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred;
|
||||
}
|
||||
};
|
||||
|
||||
@ -667,9 +673,9 @@ class DiagnosticErrorTrap {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// DiagnosticBuilder - This is a little helper class used to produce
|
||||
/// diagnostics. This is constructed by the Diagnostic::Report method, and
|
||||
/// allows insertion of extra information (arguments and source ranges) into the
|
||||
/// currently "in flight" diagnostic. When the temporary for the builder is
|
||||
/// diagnostics. This is constructed by the DiagnosticsEngine::Report method,
|
||||
/// and allows insertion of extra information (arguments and source ranges) into
|
||||
/// the currently "in flight" diagnostic. When the temporary for the builder is
|
||||
/// destroyed, the diagnostic is issued.
|
||||
///
|
||||
/// Note that many of these will be created as temporary objects (many call
|
||||
@ -678,12 +684,12 @@ class DiagnosticErrorTrap {
|
||||
/// the common fields to registers, eliminating increments of the NumArgs field,
|
||||
/// for example.
|
||||
class DiagnosticBuilder {
|
||||
mutable Diagnostic *DiagObj;
|
||||
mutable DiagnosticsEngine *DiagObj;
|
||||
mutable unsigned NumArgs, NumRanges, NumFixItHints;
|
||||
|
||||
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
|
||||
friend class Diagnostic;
|
||||
explicit DiagnosticBuilder(Diagnostic *diagObj)
|
||||
friend class DiagnosticsEngine;
|
||||
explicit DiagnosticBuilder(DiagnosticsEngine *diagObj)
|
||||
: DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
|
||||
|
||||
friend class PartialDiagnostic;
|
||||
@ -731,7 +737,7 @@ class DiagnosticBuilder {
|
||||
///
|
||||
/// \pre \c isActive()
|
||||
unsigned getDiagID() const {
|
||||
assert(isActive() && "Diagnostic is inactive");
|
||||
assert(isActive() && "DiagnosticsEngine is inactive");
|
||||
return DiagObj->CurDiagID;
|
||||
}
|
||||
|
||||
@ -743,17 +749,17 @@ class DiagnosticBuilder {
|
||||
/// return Diag(...);
|
||||
operator bool() const { return true; }
|
||||
|
||||
void AddString(llvm::StringRef S) const {
|
||||
assert(NumArgs < Diagnostic::MaxArguments &&
|
||||
void AddString(StringRef S) const {
|
||||
assert(NumArgs < DiagnosticsEngine::MaxArguments &&
|
||||
"Too many arguments to diagnostic!");
|
||||
if (DiagObj) {
|
||||
DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string;
|
||||
DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string;
|
||||
DiagObj->DiagArgumentsStr[NumArgs++] = S;
|
||||
}
|
||||
}
|
||||
|
||||
void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
|
||||
assert(NumArgs < Diagnostic::MaxArguments &&
|
||||
void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
|
||||
assert(NumArgs < DiagnosticsEngine::MaxArguments &&
|
||||
"Too many arguments to diagnostic!");
|
||||
if (DiagObj) {
|
||||
DiagObj->DiagArgumentsKind[NumArgs] = Kind;
|
||||
@ -770,15 +776,17 @@ class DiagnosticBuilder {
|
||||
}
|
||||
|
||||
void AddFixItHint(const FixItHint &Hint) const {
|
||||
assert(NumFixItHints < Diagnostic::MaxFixItHints &&
|
||||
assert(NumFixItHints < DiagnosticsEngine::MaxFixItHints &&
|
||||
"Too many fix-it hints!");
|
||||
if (NumFixItHints >= DiagnosticsEngine::MaxFixItHints)
|
||||
return; // Don't crash in release builds
|
||||
if (DiagObj)
|
||||
DiagObj->FixItHints[NumFixItHints++] = Hint;
|
||||
}
|
||||
};
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
llvm::StringRef S) {
|
||||
StringRef S) {
|
||||
DB.AddString(S);
|
||||
return DB;
|
||||
}
|
||||
@ -786,30 +794,30 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const char *Str) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str),
|
||||
Diagnostic::ak_c_string);
|
||||
DiagnosticsEngine::ak_c_string);
|
||||
return DB;
|
||||
}
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) {
|
||||
DB.AddTaggedVal(I, Diagnostic::ak_sint);
|
||||
DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
|
||||
return DB;
|
||||
}
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) {
|
||||
DB.AddTaggedVal(I, Diagnostic::ak_sint);
|
||||
DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
|
||||
return DB;
|
||||
}
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
unsigned I) {
|
||||
DB.AddTaggedVal(I, Diagnostic::ak_uint);
|
||||
DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
|
||||
return DB;
|
||||
}
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const IdentifierInfo *II) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(II),
|
||||
Diagnostic::ak_identifierinfo);
|
||||
DiagnosticsEngine::ak_identifierinfo);
|
||||
return DB;
|
||||
}
|
||||
|
||||
@ -823,7 +831,7 @@ typename llvm::enable_if<llvm::is_same<T, DeclContext>,
|
||||
const DiagnosticBuilder &>::type
|
||||
operator<<(const DiagnosticBuilder &DB, T *DC) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
|
||||
Diagnostic::ak_declcontext);
|
||||
DiagnosticsEngine::ak_declcontext);
|
||||
return DB;
|
||||
}
|
||||
|
||||
@ -848,33 +856,33 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
/// Report - Issue the message to the client. DiagID is a member of the
|
||||
/// diag::kind enum. This actually returns a new instance of DiagnosticBuilder
|
||||
/// which emits the diagnostics (through ProcessDiag) when it is destroyed.
|
||||
inline DiagnosticBuilder Diagnostic::Report(SourceLocation Loc,
|
||||
inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc,
|
||||
unsigned DiagID){
|
||||
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
|
||||
CurDiagLoc = Loc;
|
||||
CurDiagID = DiagID;
|
||||
return DiagnosticBuilder(this);
|
||||
}
|
||||
inline DiagnosticBuilder Diagnostic::Report(unsigned DiagID) {
|
||||
inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) {
|
||||
return Report(SourceLocation(), DiagID);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DiagnosticInfo
|
||||
// Diagnostic
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// DiagnosticInfo - This is a little helper class (which is basically a smart
|
||||
/// pointer that forward info from Diagnostic) that allows clients to enquire
|
||||
/// about the currently in-flight diagnostic.
|
||||
class DiagnosticInfo {
|
||||
const Diagnostic *DiagObj;
|
||||
llvm::StringRef StoredDiagMessage;
|
||||
/// Diagnostic - This is a little helper class (which is basically a smart
|
||||
/// pointer that forward info from DiagnosticsEngine) that allows clients to
|
||||
/// enquire about the currently in-flight diagnostic.
|
||||
class Diagnostic {
|
||||
const DiagnosticsEngine *DiagObj;
|
||||
StringRef StoredDiagMessage;
|
||||
public:
|
||||
explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {}
|
||||
DiagnosticInfo(const Diagnostic *DO, llvm::StringRef storedDiagMessage)
|
||||
explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {}
|
||||
Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage)
|
||||
: DiagObj(DO), StoredDiagMessage(storedDiagMessage) {}
|
||||
|
||||
const Diagnostic *getDiags() const { return DiagObj; }
|
||||
const DiagnosticsEngine *getDiags() const { return DiagObj; }
|
||||
unsigned getID() const { return DiagObj->CurDiagID; }
|
||||
const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; }
|
||||
bool hasSourceManager() const { return DiagObj->hasSourceManager(); }
|
||||
@ -884,49 +892,49 @@ class DiagnosticInfo {
|
||||
|
||||
/// getArgKind - Return the kind of the specified index. Based on the kind
|
||||
/// of argument, the accessors below can be used to get the value.
|
||||
Diagnostic::ArgumentKind getArgKind(unsigned Idx) const {
|
||||
DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const {
|
||||
assert(Idx < getNumArgs() && "Argument index out of range!");
|
||||
return (Diagnostic::ArgumentKind)DiagObj->DiagArgumentsKind[Idx];
|
||||
return (DiagnosticsEngine::ArgumentKind)DiagObj->DiagArgumentsKind[Idx];
|
||||
}
|
||||
|
||||
/// getArgStdStr - Return the provided argument string specified by Idx.
|
||||
const std::string &getArgStdStr(unsigned Idx) const {
|
||||
assert(getArgKind(Idx) == Diagnostic::ak_std_string &&
|
||||
assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string &&
|
||||
"invalid argument accessor!");
|
||||
return DiagObj->DiagArgumentsStr[Idx];
|
||||
}
|
||||
|
||||
/// getArgCStr - Return the specified C string argument.
|
||||
const char *getArgCStr(unsigned Idx) const {
|
||||
assert(getArgKind(Idx) == Diagnostic::ak_c_string &&
|
||||
assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string &&
|
||||
"invalid argument accessor!");
|
||||
return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]);
|
||||
}
|
||||
|
||||
/// getArgSInt - Return the specified signed integer argument.
|
||||
int getArgSInt(unsigned Idx) const {
|
||||
assert(getArgKind(Idx) == Diagnostic::ak_sint &&
|
||||
assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint &&
|
||||
"invalid argument accessor!");
|
||||
return (int)DiagObj->DiagArgumentsVal[Idx];
|
||||
}
|
||||
|
||||
/// getArgUInt - Return the specified unsigned integer argument.
|
||||
unsigned getArgUInt(unsigned Idx) const {
|
||||
assert(getArgKind(Idx) == Diagnostic::ak_uint &&
|
||||
assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint &&
|
||||
"invalid argument accessor!");
|
||||
return (unsigned)DiagObj->DiagArgumentsVal[Idx];
|
||||
}
|
||||
|
||||
/// getArgIdentifier - Return the specified IdentifierInfo argument.
|
||||
const IdentifierInfo *getArgIdentifier(unsigned Idx) const {
|
||||
assert(getArgKind(Idx) == Diagnostic::ak_identifierinfo &&
|
||||
assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo &&
|
||||
"invalid argument accessor!");
|
||||
return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]);
|
||||
}
|
||||
|
||||
/// getRawArg - Return the specified non-string argument in an opaque form.
|
||||
intptr_t getRawArg(unsigned Idx) const {
|
||||
assert(getArgKind(Idx) != Diagnostic::ak_std_string &&
|
||||
assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string &&
|
||||
"invalid argument accessor!");
|
||||
return DiagObj->DiagArgumentsVal[Idx];
|
||||
}
|
||||
@ -959,12 +967,12 @@ class DiagnosticInfo {
|
||||
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
|
||||
/// formal arguments into the %0 slots. The result is appended onto the Str
|
||||
/// array.
|
||||
void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const;
|
||||
void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const;
|
||||
|
||||
/// FormatDiagnostic - Format the given format-string into the
|
||||
/// output buffer using the arguments stored in this diagnostic.
|
||||
void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
|
||||
llvm::SmallVectorImpl<char> &OutStr) const;
|
||||
SmallVectorImpl<char> &OutStr) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -973,7 +981,7 @@ class DiagnosticInfo {
|
||||
*/
|
||||
class StoredDiagnostic {
|
||||
unsigned ID;
|
||||
Diagnostic::Level Level;
|
||||
DiagnosticsEngine::Level Level;
|
||||
FullSourceLoc Loc;
|
||||
std::string Message;
|
||||
std::vector<CharSourceRange> Ranges;
|
||||
@ -981,18 +989,22 @@ class StoredDiagnostic {
|
||||
|
||||
public:
|
||||
StoredDiagnostic();
|
||||
StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info);
|
||||
StoredDiagnostic(Diagnostic::Level Level, unsigned ID,
|
||||
llvm::StringRef Message);
|
||||
StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info);
|
||||
StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
|
||||
StringRef Message);
|
||||
StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
|
||||
StringRef Message, FullSourceLoc Loc,
|
||||
ArrayRef<CharSourceRange> Ranges,
|
||||
ArrayRef<FixItHint> Fixits);
|
||||
~StoredDiagnostic();
|
||||
|
||||
/// \brief Evaluates true when this object stores a diagnostic.
|
||||
operator bool() const { return Message.size() > 0; }
|
||||
|
||||
unsigned getID() const { return ID; }
|
||||
Diagnostic::Level getLevel() const { return Level; }
|
||||
DiagnosticsEngine::Level getLevel() const { return Level; }
|
||||
const FullSourceLoc &getLocation() const { return Loc; }
|
||||
llvm::StringRef getMessage() const { return Message; }
|
||||
StringRef getMessage() const { return Message; }
|
||||
|
||||
void setLocation(FullSourceLoc Loc) { this->Loc = Loc; }
|
||||
|
||||
@ -1007,20 +1019,20 @@ class StoredDiagnostic {
|
||||
unsigned fixit_size() const { return FixIts.size(); }
|
||||
};
|
||||
|
||||
/// DiagnosticClient - This is an abstract interface implemented by clients of
|
||||
/// DiagnosticConsumer - This is an abstract interface implemented by clients of
|
||||
/// the front-end, which formats and prints fully processed diagnostics.
|
||||
class DiagnosticClient {
|
||||
class DiagnosticConsumer {
|
||||
protected:
|
||||
unsigned NumWarnings; // Number of warnings reported
|
||||
unsigned NumErrors; // Number of errors reported
|
||||
|
||||
public:
|
||||
DiagnosticClient() : NumWarnings(0), NumErrors(0) { }
|
||||
DiagnosticConsumer() : NumWarnings(0), NumErrors(0) { }
|
||||
|
||||
unsigned getNumErrors() const { return NumErrors; }
|
||||
unsigned getNumWarnings() const { return NumWarnings; }
|
||||
|
||||
virtual ~DiagnosticClient();
|
||||
virtual ~DiagnosticConsumer();
|
||||
|
||||
/// BeginSourceFile - Callback to inform the diagnostic client that processing
|
||||
/// of a source file is beginning.
|
||||
@ -1043,8 +1055,8 @@ class DiagnosticClient {
|
||||
|
||||
/// IncludeInDiagnosticCounts - This method (whose default implementation
|
||||
/// returns true) indicates whether the diagnostics handled by this
|
||||
/// DiagnosticClient should be included in the number of diagnostics reported
|
||||
/// by Diagnostic.
|
||||
/// DiagnosticConsumer should be included in the number of diagnostics
|
||||
/// reported by DiagnosticsEngine.
|
||||
virtual bool IncludeInDiagnosticCounts() const;
|
||||
|
||||
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
|
||||
@ -1052,8 +1064,24 @@ class DiagnosticClient {
|
||||
///
|
||||
/// Default implementation just keeps track of the total number of warnings
|
||||
/// and errors.
|
||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
||||
const DiagnosticInfo &Info);
|
||||
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
|
||||
const Diagnostic &Info);
|
||||
|
||||
/// \brief Clone the diagnostic consumer, producing an equivalent consumer
|
||||
/// that can be used in a different context.
|
||||
virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const = 0;
|
||||
};
|
||||
|
||||
/// IgnoringDiagConsumer - This is a diagnostic client that just ignores all
|
||||
/// diags.
|
||||
class IgnoringDiagConsumer : public DiagnosticConsumer {
|
||||
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
|
||||
const Diagnostic &Info) {
|
||||
// Just ignore it.
|
||||
}
|
||||
DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
|
||||
return new IgnoringDiagConsumer();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -18,8 +18,6 @@ def MAP_IGNORE : DiagMapping;
|
||||
def MAP_WARNING : DiagMapping;
|
||||
def MAP_ERROR : DiagMapping;
|
||||
def MAP_FATAL : DiagMapping;
|
||||
def MAP_WARNING_NO_WERROR : DiagMapping;
|
||||
def MAP_WARNING_SHOW_IN_SYSTEM_HEADER : DiagMapping;
|
||||
|
||||
// Define the diagnostic classes.
|
||||
class DiagClass;
|
||||
@ -59,6 +57,8 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
|
||||
DiagClass Class = DC;
|
||||
bit SFINAE = 1;
|
||||
bit AccessControl = 0;
|
||||
bit WarningNoWerror = 0;
|
||||
bit WarningShowInSystemHeader = 0;
|
||||
DiagMapping DefaultMapping = defaultmapping;
|
||||
DiagGroup Group;
|
||||
string CategoryName = "";
|
||||
@ -77,9 +77,11 @@ class DefaultIgnore { DiagMapping DefaultMapping = MAP_IGNORE; }
|
||||
class DefaultWarn { DiagMapping DefaultMapping = MAP_WARNING; }
|
||||
class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; }
|
||||
class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; }
|
||||
class DefaultWarnNoWerror { DiagMapping DefaultMapping= MAP_WARNING_NO_WERROR; }
|
||||
class DefaultWarnNoWerror {
|
||||
bit WarningNoWerror = 1;
|
||||
}
|
||||
class DefaultWarnShowInSystemHeader {
|
||||
DiagMapping DefaultMapping = MAP_WARNING_SHOW_IN_SYSTEM_HEADER;
|
||||
bit WarningShowInSystemHeader = 1;
|
||||
}
|
||||
|
||||
class NoSFINAE { bit SFINAE = 0; }
|
||||
|
@ -57,6 +57,10 @@ def note_odr_number_of_bases : Note<
|
||||
def note_odr_enumerator : Note<"enumerator %0 with value %1 here">;
|
||||
def note_odr_missing_enumerator : Note<"no corresponding enumerator here">;
|
||||
|
||||
def err_odr_field_type_inconsistent : Error<
|
||||
"field %0 declared with incompatible types in different "
|
||||
"translation units (%1 vs. %2)">;
|
||||
|
||||
// Importing Objective-C ASTs
|
||||
def err_odr_ivar_type_inconsistent : Error<
|
||||
"instance variable %0 declared with incompatible types in different "
|
||||
|
@ -52,18 +52,31 @@ def err_invalid_storage_class_in_func_decl : Error<
|
||||
"invalid storage class specifier in function declarator">;
|
||||
def err_expected_namespace_name : Error<"expected namespace name">;
|
||||
def ext_variadic_templates : ExtWarn<
|
||||
"variadic templates are a C++0x extension">, InGroup<CXX0x>;
|
||||
"variadic templates are a C++11 extension">, InGroup<CXX11>;
|
||||
def warn_cxx98_compat_variadic_templates :
|
||||
Warning<"variadic templates are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def err_default_special_members : Error<
|
||||
"only special member functions may be defaulted">;
|
||||
def err_friends_define_only_namespace_scope : Error<
|
||||
"cannot define a function with non-namespace scope in a friend declaration">;
|
||||
def err_deleted_non_function : Error<
|
||||
"only functions can have deleted definitions">;
|
||||
def err_module_not_found : Error<"module '%0' not found">, DefaultFatal;
|
||||
def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal;
|
||||
def err_module_cycle : Error<"cyclic dependency in module '%0': %1">,
|
||||
DefaultFatal;
|
||||
def warn_module_build : Warning<"building module '%0' from source">,
|
||||
InGroup<ModuleBuild>, DefaultIgnore;
|
||||
def note_pragma_entered_here : Note<"#pragma entered here">;
|
||||
|
||||
// Sema && Lex
|
||||
def ext_longlong : Extension<
|
||||
"'long long' is an extension when C99 mode is not enabled">,
|
||||
InGroup<LongLong>;
|
||||
def warn_cxx98_compat_longlong : Warning<
|
||||
"'long long' is incompatible with C++98">,
|
||||
InGroup<CXX98CompatPedantic>, DefaultIgnore;
|
||||
def warn_integer_too_large : Warning<
|
||||
"integer constant is too large for its type">;
|
||||
def warn_integer_too_large_for_signed : Warning<
|
||||
|
@ -65,6 +65,9 @@ def err_drv_command_signalled : Error<
|
||||
"%0 command failed due to signal %1 (use -v to see invocation)">;
|
||||
def err_drv_invalid_mfloat_abi : Error<
|
||||
"invalid float ABI '%0'">;
|
||||
def err_drv_invalid_libcxx_deployment : Error<
|
||||
"invalid deployment target for -stdlib=libc++ (requires %0 or later)">;
|
||||
|
||||
def err_drv_I_dash_not_supported : Error<
|
||||
"'%0' not supported, please use -iquote instead">;
|
||||
def err_drv_unknown_argument : Error<"unknown argument: '%0'">;
|
||||
@ -123,4 +126,7 @@ def warn_drv_objc_gc_unsupported : Warning<
|
||||
def warn_drv_pch_not_first_include : Warning<
|
||||
"precompiled header '%0' was ignored because '%1' is not first '-include'">;
|
||||
|
||||
def note_drv_command_failed_diag_msg : Note<
|
||||
"diagnostic msg: %0">;
|
||||
|
||||
}
|
||||
|
@ -112,139 +112,11 @@ def err_relocatable_without_isysroot : Error<
|
||||
def warn_pch_target_triple : Error<
|
||||
"PCH file was compiled for the target '%0' but the current translation "
|
||||
"unit is being compiled for target '%1'">;
|
||||
def warn_pch_c99 : Error<
|
||||
"C99 support was %select{disabled|enabled}0 in PCH file but is "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_c1x : Error<
|
||||
"C1X support was %select{disabled|enabled}0 in PCH file but is "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_cplusplus : Error<
|
||||
"C++ support was %select{disabled|enabled}0 in PCH file but is "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_cplusplus0x : Error<
|
||||
"C++0x support was %select{disabled|enabled}0 in PCH file but is "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objective_c : Error<
|
||||
"Objective-C support was %select{disabled|enabled}0 in PCH file but is "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objective_c2 : Error<
|
||||
"Objective-C 2.0 support was %select{disabled|enabled}0 in PCH file but "
|
||||
"is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_nonfragile_abi : Error<
|
||||
"PCH file was compiled with the %select{32-bit|non-fragile}0 Objective-C "
|
||||
"ABI but the %select{32-bit|non-fragile}1 Objective-C ABI is selected">;
|
||||
def warn_pch_nonfragile_abi2 : Error<
|
||||
"PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 "
|
||||
"Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 "
|
||||
"Objective-C ABI is selected">;
|
||||
def warn_pch_auto_ref_count : Error<
|
||||
"PCH file was compiled %select{without|with} automated reference counting,"
|
||||
"which is currently %select{disabled|enabled}">;
|
||||
def warn_pch_apple_kext : Error<
|
||||
"PCH file was compiled %select{with|without}0 support for Apple's kernel "
|
||||
"extensions ABI but it is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objc_auto_properties : Error<
|
||||
"PCH file was compiled %select{with|without}0 support for auto-synthesized "
|
||||
"@properties but it is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_no_constant_cfstrings : Error<
|
||||
"Objctive-C NSstring generation support was %select{disabled|enabled}0 "
|
||||
"in PCH file but currently %select{disabled|enabled}1">;
|
||||
def warn_pch_extensions : Error<
|
||||
"extensions were %select{enabled|disabled}0 in PCH file but are "
|
||||
"currently %select{enabled|disabled}1">;
|
||||
def warn_pch_gnu_extensions : Error<
|
||||
"GNU extensions were %select{disabled|enabled}0 in PCH file but are "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_gnu_keywords : Error<
|
||||
"GNU keywords were %select{disabled|enabled}0 in PCH file but are "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_microsoft_extensions : Error<
|
||||
"Microsoft extensions were %select{disabled|enabled}0 in PCH file but are "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_ms_bitfields : Error<
|
||||
"Microsoft-compatible structure layout was %select{disabled|enabled}0 in "
|
||||
"PCH file but is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_heinous_extensions : Error<
|
||||
"heinous extensions were %select{disabled|enabled}0 in PCH file but are "
|
||||
"currently %select{disabled|enabled}1">;
|
||||
def warn_pch_lax_vector_conversions : Error<
|
||||
"lax vector conversions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_altivec : Error<
|
||||
"AltiVec initializers were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_opencl : Error<
|
||||
"OpenCL language extensions were %select{disabled|enabled}0 in PCH file "
|
||||
"but are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_cuda : Error<
|
||||
"CUDA language extensions were %select{disabled|enabled}0 in PCH file "
|
||||
"but are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_elide_constructors : Error<
|
||||
"Elidable copy constructors were %select{disabled|enabled}0 in PCH file "
|
||||
"but are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_exceptions : Error<
|
||||
"exceptions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objc_exceptions : Error<
|
||||
"Objective-C exceptions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_cxx_exceptions : Error<
|
||||
"C++ exceptions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_sjlj_exceptions : Error<
|
||||
"sjlj-exceptions were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_objc_runtime : Error<
|
||||
"PCH file was compiled with the %select{NeXT|GNU}0 runtime but the "
|
||||
"%select{NeXT|GNU}1 runtime is selected">;
|
||||
def warn_pch_freestanding : Error<
|
||||
"PCH file was compiled with a %select{hosted|freestanding}0 "
|
||||
"implementation but a %select{hosted|freestanding}1 implementation "
|
||||
"is selected">;
|
||||
def warn_pch_builtins : Error<
|
||||
"PCH file was compiled with builtins %select{enabled|disabled}0 but "
|
||||
"builtins are currently %select{enabled|disabled}1">;
|
||||
def warn_pch_thread_safe_statics : Error<
|
||||
"PCH file was compiled %select{without|with}0 thread-safe statics but "
|
||||
"thread-safe statics are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_posix_threads : Error<
|
||||
"PCH file was compiled %select{without|with}0 POSIX thread support but "
|
||||
"POSIX threads are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_stack_protector : Error<
|
||||
"stack protector was %select{off|on|required}0 in PCH file but "
|
||||
"is currently %select{off|on|required}1">;
|
||||
def warn_pch_blocks : Error<
|
||||
"blocks were %select{disabled|enabled}0 in PCH file but "
|
||||
"are currently %select{disabled|enabled}1">;
|
||||
def warn_pch_math_errno : Error<
|
||||
"math functions %select{do not respect|respect}0 'errno' in PCH "
|
||||
"file but they are currently set to %select{not respect|respect}1 "
|
||||
"'errno'">;
|
||||
def warn_pch_optimize : Error<
|
||||
"the macro '__OPTIMIZE__' was %select{not defined|defined}0 in "
|
||||
"the PCH file but is currently %select{undefined|defined}1">;
|
||||
def warn_pch_optimize_size : Error<
|
||||
"the macro '__OPTIMIZE_SIZE__' was %select{not defined|defined}0 in "
|
||||
"the PCH file but is currently %select{undefined|defined}1">;
|
||||
def warn_pch_static : Error<
|
||||
"the PCH file was compiled %select{dynamic|static}0 but the "
|
||||
"current translation unit is being compiled as %select{dynamic|static}1">;
|
||||
def warn_pch_pic_level : Error<
|
||||
"PCH file was compiled with PIC level %0, but the current translation "
|
||||
"unit will be compiled with PIC level %1">;
|
||||
def warn_pch_gnu_inline : Error<
|
||||
"PCH file was compiled with %select{C99|GNU|}0 inline semantics but "
|
||||
"%select{C99|GNU}1 inline semantics are currently selected">;
|
||||
def warn_pch_no_inline : Error<
|
||||
"the macro '__NO_INLINE__' was %select{not defined|defined}0 in "
|
||||
"the PCH file but is currently %select{undefined|defined}1">;
|
||||
def warn_pch_deprecated : Error<
|
||||
"the macro '__DEPRECATED' was %select{not defined|defined}0 in "
|
||||
"the PCH file but is currently %select{undefined|defined}1">;
|
||||
def warn_pch_gc_mode : Error<
|
||||
"the PCH file was built with %select{no||hybrid}0 garbage collection but "
|
||||
"the current translation unit will compiled with %select{no||hybrid}1 "
|
||||
"garbage collection">;
|
||||
def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in "
|
||||
"PCH file but is currently %select{disabled|enabled}2">;
|
||||
def err_pch_langopt_value_mismatch : Error<
|
||||
"%0 differs in PCH file vs. current file">;
|
||||
|
||||
def warn_pch_version_too_old : Error<
|
||||
"PCH file uses an older PCH format that is no longer supported">;
|
||||
def warn_pch_version_too_new : Error<
|
||||
@ -266,18 +138,6 @@ def warn_macro_name_used_in_pch : Error<
|
||||
def warn_pch_compiler_options_mismatch : Error<
|
||||
"compiler options used when building the precompiled header differ from "
|
||||
"the options used when using the precompiled header">;
|
||||
def warn_pch_access_control : Error<
|
||||
"C++ access control was %select{disabled|enabled}0 in the PCH file but "
|
||||
"is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_char_signed : Error<
|
||||
"char was %select{unsigned|signed}0 in the PCH file but "
|
||||
"is currently %select{unsigned|signed}1">;
|
||||
def warn_pch_short_wchar : Error<
|
||||
"-fshort-wchar was %select{disabled|enabled}0 in the PCH file but "
|
||||
"is currently %select{disabled|enabled}1">;
|
||||
def warn_pch_short_enums : Error<
|
||||
"-fshort-enums was %select{disabled|enabled}0 in the PCH file but "
|
||||
"is currently %select{disabled|enabled}1">;
|
||||
|
||||
def err_not_a_pch_file : Error<
|
||||
"'%0' does not appear to be a precompiled header file">, DefaultFatal;
|
||||
@ -291,6 +151,11 @@ def warn_unknown_warning_specifier : Warning<
|
||||
"unknown %0 warning specifier: '%1'">,
|
||||
InGroup<DiagGroup<"unknown-warning-option"> >;
|
||||
|
||||
def warn_unkwown_analyzer_checker : Warning<
|
||||
def warn_unknown_analyzer_checker : Warning<
|
||||
"no analyzer checkers are associated with '%0'">;
|
||||
def warn_incompatible_analyzer_plugin_api : Warning<
|
||||
"checker plugin '%0' is not compatible with this version of the analyzer">,
|
||||
InGroup<DiagGroup<"analyzer-incompatible-plugin"> >;
|
||||
def note_incompatible_analyzer_plugin_api : Note<
|
||||
"current API version is '%0', but plugin was compiled with version '%1'">;
|
||||
}
|
||||
|
@ -54,9 +54,16 @@ def ExtraTokens : DiagGroup<"extra-tokens">;
|
||||
def FormatExtraArgs : DiagGroup<"format-extra-args">;
|
||||
def FormatZeroLength : DiagGroup<"format-zero-length">;
|
||||
|
||||
def CXXHexFloats : DiagGroup<"c++-hex-floats">;
|
||||
def CXX98Compat : DiagGroup<"c++98-compat">;
|
||||
// Warnings for C++11 features which are Extensions in C++98 mode.
|
||||
def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat]>;
|
||||
|
||||
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
|
||||
def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>;
|
||||
|
||||
def CXX11Compat : DiagGroup<"c++11-compat", [CXX11Narrowing]>;
|
||||
def : DiagGroup<"c++0x-compat", [CXX11Compat]>;
|
||||
|
||||
def : DiagGroup<"c++0x-compat", [CXXHexFloats]>;
|
||||
def : DiagGroup<"effc++">;
|
||||
def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
|
||||
def FourByteMultiChar : DiagGroup<"four-char-constants">;
|
||||
@ -66,13 +73,15 @@ def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
|
||||
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
|
||||
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
|
||||
def : DiagGroup<"import">;
|
||||
def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types">;
|
||||
def : DiagGroup<"init-self">;
|
||||
def : DiagGroup<"inline">;
|
||||
def : DiagGroup<"int-to-pointer-cast">;
|
||||
def : DiagGroup<"invalid-pch">;
|
||||
def LiteralRange : DiagGroup<"literal-range">;
|
||||
def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args">;
|
||||
def : DiagGroup<"main">;
|
||||
def MalformedWarningCheck : DiagGroup<"malformed-warning-check">;
|
||||
def Main : DiagGroup<"main">;
|
||||
def MissingBraces : DiagGroup<"missing-braces">;
|
||||
def MissingDeclarations: DiagGroup<"missing-declarations">;
|
||||
def : DiagGroup<"missing-format-attribute">;
|
||||
@ -84,6 +93,7 @@ def : DiagGroup<"newline-eof">;
|
||||
def LongLong : DiagGroup<"long-long">;
|
||||
def MismatchedTags : DiagGroup<"mismatched-tags">;
|
||||
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
|
||||
def ModuleBuild : DiagGroup<"module-build">;
|
||||
def NullDereference : DiagGroup<"null-dereference">;
|
||||
def InitializerOverrides : DiagGroup<"initializer-overrides">;
|
||||
def NonNull : DiagGroup<"nonnull">;
|
||||
@ -95,6 +105,9 @@ def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">;
|
||||
def : DiagGroup<"overflow">;
|
||||
def OverlengthStrings : DiagGroup<"overlength-strings">;
|
||||
def OverloadedVirtual : DiagGroup<"overloaded-virtual">;
|
||||
def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
|
||||
def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
|
||||
def ObjCContinuationPropertyType :DiagGroup<"objc-continuation-property-type">;
|
||||
def Packed : DiagGroup<"packed">;
|
||||
def Padded : DiagGroup<"padded">;
|
||||
def PointerArith : DiagGroup<"pointer-arith">;
|
||||
@ -108,6 +121,8 @@ def ReturnType : DiagGroup<"return-type">;
|
||||
def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy">;
|
||||
def SelfAssignment : DiagGroup<"self-assign">;
|
||||
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
|
||||
def Sentinel : DiagGroup<"sentinel">;
|
||||
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
|
||||
def : DiagGroup<"sequence-point">;
|
||||
def Shadow : DiagGroup<"shadow">;
|
||||
def : DiagGroup<"shorten-64-to-32">;
|
||||
@ -152,6 +167,7 @@ def UnknownPragmas : DiagGroup<"unknown-pragmas">;
|
||||
def UnknownAttributes : DiagGroup<"attributes">;
|
||||
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args">;
|
||||
def UnusedArgument : DiagGroup<"unused-argument">;
|
||||
def UnusedComparison : DiagGroup<"unused-comparison">;
|
||||
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
|
||||
def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
|
||||
def UnneededMemberFunction : DiagGroup<"unneeded-member-function">;
|
||||
@ -160,9 +176,11 @@ def UnusedMemberFunction : DiagGroup<"unused-member-function",
|
||||
[UnneededMemberFunction]>;
|
||||
def UnusedLabel : DiagGroup<"unused-label">;
|
||||
def UnusedParameter : DiagGroup<"unused-parameter">;
|
||||
def UnusedValue : DiagGroup<"unused-value">;
|
||||
def UnusedResult : DiagGroup<"unused-result">;
|
||||
def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult]>;
|
||||
def UnusedVariable : DiagGroup<"unused-variable">;
|
||||
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
|
||||
def UserDefinedLiterals : DiagGroup<"user-defined-literals">;
|
||||
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
|
||||
def Reorder : DiagGroup<"reorder">;
|
||||
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
|
||||
@ -183,6 +201,7 @@ def Selector : DiagGroup<"selector">;
|
||||
def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">;
|
||||
def Protocol : DiagGroup<"protocol">;
|
||||
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
|
||||
def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">;
|
||||
def : DiagGroup<"variadic-macros">;
|
||||
def VariadicMacros : DiagGroup<"variadic-macros">;
|
||||
def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
|
||||
@ -202,9 +221,11 @@ def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">;
|
||||
// missing parentheses; it is off by default. We do not include it
|
||||
// in -Wparentheses because most users who use -Wparentheses explicitly
|
||||
// do not want these warnings.
|
||||
def ParenthesesOnEquality : DiagGroup<"parentheses-equality">;
|
||||
def Parentheses : DiagGroup<"parentheses",
|
||||
[LogicalOpParentheses,
|
||||
BitwiseOpParentheses]>;
|
||||
BitwiseOpParentheses,
|
||||
ParenthesesOnEquality]>;
|
||||
|
||||
// -Wconversion has its own warnings, but we split a few out for
|
||||
// legacy reasons:
|
||||
@ -216,6 +237,7 @@ def Conversion : DiagGroup<"conversion",
|
||||
[DiagGroup<"shorten-64-to-32">,
|
||||
DiagGroup<"constant-conversion">,
|
||||
DiagGroup<"literal-conversion">,
|
||||
DiagGroup<"string-conversion">,
|
||||
DiagGroup<"sign-conversion">,
|
||||
BoolConversions]>,
|
||||
DiagCategory<"Value Conversion Issue">;
|
||||
@ -228,11 +250,12 @@ def Unused : DiagGroup<"unused",
|
||||
DiagCategory<"Unused Entity Issue">;
|
||||
|
||||
// Format settings.
|
||||
def FormatInvalidSpecifier : DiagGroup<"format-invalid-specifier">;
|
||||
def FormatSecurity : DiagGroup<"format-security">;
|
||||
def FormatY2K : DiagGroup<"format-y2k">;
|
||||
def Format : DiagGroup<"format",
|
||||
[FormatExtraArgs, FormatZeroLength, NonNull,
|
||||
FormatSecurity, FormatY2K]>,
|
||||
FormatSecurity, FormatY2K, FormatInvalidSpecifier]>,
|
||||
DiagCategory<"Format String Issue">;
|
||||
def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>;
|
||||
def Format2 : DiagGroup<"format=2",
|
||||
@ -243,6 +266,7 @@ def Extra : DiagGroup<"extra", [
|
||||
IgnoredQualifiers,
|
||||
InitializerOverrides,
|
||||
SemiBeforeMethodBody,
|
||||
MissingMethodReturnType,
|
||||
SignCompare,
|
||||
UnusedParameter
|
||||
]>;
|
||||
@ -265,12 +289,15 @@ def Most : DiagGroup<"most", [
|
||||
Uninitialized,
|
||||
UnknownPragmas,
|
||||
Unused,
|
||||
VectorConversions,
|
||||
VolatileRegisterVar,
|
||||
ObjCMissingSuperCalls,
|
||||
OverloadedVirtual
|
||||
]>;
|
||||
|
||||
// -Wall is -Wmost -Wparentheses
|
||||
// Thread Safety warnings
|
||||
def ThreadSafety : DiagGroup<"thread-safety">;
|
||||
|
||||
// -Wall is -Wmost -Wparentheses -Wtop-level-comparison
|
||||
def : DiagGroup<"all", [Most, Parentheses]>;
|
||||
|
||||
// Aliases.
|
||||
@ -283,14 +310,16 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
|
||||
def NonGCC : DiagGroup<"non-gcc",
|
||||
[SignCompare, Conversion, LiteralRange]>;
|
||||
|
||||
// A warning group for warnings about using C++0x features as extensions in
|
||||
// A warning group for warnings about using C++11 features as extensions in
|
||||
// earlier C++ versions.
|
||||
def CXX0xStaticNonIntegralInitializer :
|
||||
DiagGroup<"c++0x-static-nonintegral-init">;
|
||||
def CXX0x : DiagGroup<"c++0x-extensions", [CXX0xStaticNonIntegralInitializer]>;
|
||||
def CXX11 : DiagGroup<"c++11-extensions">;
|
||||
def : DiagGroup<"c++0x-extensions", [CXX11]>;
|
||||
def DelegatingCtorCycles :
|
||||
DiagGroup<"delegating-ctor-cycles">;
|
||||
|
||||
// A warning group for warnings about using C1X features as extensions.
|
||||
def C1X : DiagGroup<"c1x-extensions">;
|
||||
|
||||
// A warning group for warnings about GCC extensions.
|
||||
def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
|
||||
|
||||
@ -299,3 +328,4 @@ def Microsoft : DiagGroup<"microsoft">;
|
||||
|
||||
def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">;
|
||||
|
||||
def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">;
|
||||
|
@ -16,10 +16,16 @@
|
||||
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
namespace llvm {
|
||||
template<typename T, unsigned> class SmallVector;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class Diagnostic;
|
||||
class DiagnosticsEngine;
|
||||
class SourceLocation;
|
||||
struct WarningOption;
|
||||
|
||||
// Import the diagnostic enums themselves.
|
||||
namespace diag {
|
||||
@ -43,7 +49,7 @@ namespace clang {
|
||||
// Get typedefs for common diagnostics.
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
|
||||
SFINAE,ACCESS,CATEGORY,NOWERROR,SHOWINSYSHEADER,BRIEF,FULL) ENUM,
|
||||
#include "clang/Basic/DiagnosticCommonKinds.inc"
|
||||
NUM_BUILTIN_COMMON_DIAGNOSTICS
|
||||
#undef DIAG
|
||||
@ -59,20 +65,47 @@ namespace clang {
|
||||
MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it.
|
||||
MAP_WARNING = 2, //< Map this diagnostic to a warning.
|
||||
MAP_ERROR = 3, //< Map this diagnostic to an error.
|
||||
MAP_FATAL = 4, //< Map this diagnostic to a fatal error.
|
||||
|
||||
/// Map this diagnostic to "warning", but make it immune to -Werror. This
|
||||
/// happens when you specify -Wno-error=foo.
|
||||
MAP_WARNING_NO_WERROR = 5,
|
||||
/// Map this diagnostic to "warning", but make it immune to
|
||||
/// -Wno-system-headers.
|
||||
MAP_WARNING_SHOW_IN_SYSTEM_HEADER = 6,
|
||||
/// Map this diagnostic to "error", but make it immune to -Wfatal-errors.
|
||||
/// This happens for -Wno-fatal-errors=foo.
|
||||
MAP_ERROR_NO_WFATAL = 7
|
||||
MAP_FATAL = 4 //< Map this diagnostic to a fatal error.
|
||||
};
|
||||
}
|
||||
|
||||
class DiagnosticMappingInfo {
|
||||
unsigned Mapping : 3;
|
||||
unsigned IsUser : 1;
|
||||
unsigned IsPragma : 1;
|
||||
unsigned HasShowInSystemHeader : 1;
|
||||
unsigned HasNoWarningAsError : 1;
|
||||
unsigned HasNoErrorAsFatal : 1;
|
||||
|
||||
public:
|
||||
static DiagnosticMappingInfo Make(diag::Mapping Mapping, bool IsUser,
|
||||
bool IsPragma) {
|
||||
DiagnosticMappingInfo Result;
|
||||
Result.Mapping = Mapping;
|
||||
Result.IsUser = IsUser;
|
||||
Result.IsPragma = IsPragma;
|
||||
Result.HasShowInSystemHeader = 0;
|
||||
Result.HasNoWarningAsError = 0;
|
||||
Result.HasNoErrorAsFatal = 0;
|
||||
return Result;
|
||||
}
|
||||
|
||||
diag::Mapping getMapping() const { return diag::Mapping(Mapping); }
|
||||
void setMapping(diag::Mapping Value) { Mapping = Value; }
|
||||
|
||||
bool isUser() const { return IsUser; }
|
||||
bool isPragma() const { return IsPragma; }
|
||||
|
||||
bool hasShowInSystemHeader() const { return HasShowInSystemHeader; }
|
||||
void setShowInSystemHeader(bool Value) { HasShowInSystemHeader = Value; }
|
||||
|
||||
bool hasNoWarningAsError() const { return HasNoWarningAsError; }
|
||||
void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; }
|
||||
|
||||
bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; }
|
||||
void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; }
|
||||
};
|
||||
|
||||
/// \brief Used for handling and querying diagnostic IDs. Can be used and shared
|
||||
/// by multiple Diagnostics for multiple translation units.
|
||||
class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
|
||||
@ -93,7 +126,7 @@ class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
|
||||
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
|
||||
/// and level. If this is the first request for this diagnosic, it is
|
||||
/// registered and created, otherwise the existing ID is returned.
|
||||
unsigned getCustomDiagID(Level L, llvm::StringRef Message);
|
||||
unsigned getCustomDiagID(Level L, StringRef Message);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic classification and reporting interfaces.
|
||||
@ -101,14 +134,18 @@ class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
|
||||
|
||||
/// getDescription - Given a diagnostic ID, return a description of the
|
||||
/// issue.
|
||||
llvm::StringRef getDescription(unsigned DiagID) const;
|
||||
StringRef getDescription(unsigned DiagID) const;
|
||||
|
||||
/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
|
||||
/// level of the specified diagnostic ID is a Warning or Extension.
|
||||
/// This only works on builtin diagnostics, not custom ones, and is not legal to
|
||||
/// call on NOTEs.
|
||||
/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic level
|
||||
/// of the specified diagnostic ID is a Warning or Extension. This only works
|
||||
/// on builtin diagnostics, not custom ones, and is not legal to call on
|
||||
/// NOTEs.
|
||||
static bool isBuiltinWarningOrExtension(unsigned DiagID);
|
||||
|
||||
/// \brief Return true if the specified diagnostic is mapped to errors by
|
||||
/// default.
|
||||
static bool isDefaultMappingAsError(unsigned DiagID);
|
||||
|
||||
/// \brief Determine whether the given built-in diagnostic ID is a
|
||||
/// Note.
|
||||
static bool isBuiltinNote(unsigned DiagID);
|
||||
@ -132,7 +169,7 @@ class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
|
||||
/// getWarningOptionForDiag - Return the lowest-level warning option that
|
||||
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
|
||||
/// the diagnostic, this returns null.
|
||||
static llvm::StringRef getWarningOptionForDiag(unsigned DiagID);
|
||||
static StringRef getWarningOptionForDiag(unsigned DiagID);
|
||||
|
||||
/// getCategoryNumberForDiag - Return the category number that a specified
|
||||
/// DiagID belongs to, or 0 if no category.
|
||||
@ -143,7 +180,7 @@ class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
|
||||
|
||||
/// getCategoryNameFromID - Given a category ID, return the name of the
|
||||
/// category.
|
||||
static llvm::StringRef getCategoryNameFromID(unsigned CategoryID);
|
||||
static StringRef getCategoryNameFromID(unsigned CategoryID);
|
||||
|
||||
/// \brief Enumeration describing how the the emission of a diagnostic should
|
||||
/// be treated when it occurs during C++ template argument deduction.
|
||||
@ -182,56 +219,80 @@ class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
|
||||
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
|
||||
|
||||
/// getName - Given a diagnostic ID, return its name
|
||||
static llvm::StringRef getName(unsigned DiagID);
|
||||
static StringRef getName(unsigned DiagID);
|
||||
|
||||
/// getIdFromName - Given a diagnostic name, return its ID, or 0
|
||||
static unsigned getIdFromName(llvm::StringRef Name);
|
||||
static unsigned getIdFromName(StringRef Name);
|
||||
|
||||
/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
|
||||
/// of the issue
|
||||
static llvm::StringRef getBriefExplanation(unsigned DiagID);
|
||||
static StringRef getBriefExplanation(unsigned DiagID);
|
||||
|
||||
/// getFullExplanation - Given a diagnostic ID, return a full explanation
|
||||
/// of the issue
|
||||
static llvm::StringRef getFullExplanation(unsigned DiagID);
|
||||
static StringRef getFullExplanation(unsigned DiagID);
|
||||
|
||||
/// Iterator class used for traversing all statically declared
|
||||
/// diagnostics.
|
||||
class diag_iterator {
|
||||
const void *impl;
|
||||
|
||||
friend class DiagnosticIDs;
|
||||
diag_iterator(const void *im) : impl(im) {}
|
||||
public:
|
||||
diag_iterator &operator++();
|
||||
bool operator==(const diag_iterator &x) const { return impl == x.impl; }
|
||||
bool operator!=(const diag_iterator &x) const { return impl != x.impl; }
|
||||
|
||||
llvm::StringRef getDiagName() const;
|
||||
unsigned getDiagID() const;
|
||||
};
|
||||
|
||||
static diag_iterator diags_begin();
|
||||
static diag_iterator diags_end();
|
||||
|
||||
/// \brief Get the set of all diagnostic IDs in the group with the given name.
|
||||
///
|
||||
/// \param Diags [out] - On return, the diagnostics in the group.
|
||||
/// \returns True if the given group is unknown, false otherwise.
|
||||
bool getDiagnosticsInGroup(StringRef Group,
|
||||
llvm::SmallVectorImpl<diag::kind> &Diags) const;
|
||||
|
||||
private:
|
||||
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
|
||||
/// "unknown-pragmas" to have the specified mapping. This returns true and
|
||||
/// ignores the request if "Group" was unknown, false otherwise.
|
||||
bool setDiagnosticGroupMapping(llvm::StringRef Group, diag::Mapping Map,
|
||||
SourceLocation Loc, Diagnostic &Diag) const;
|
||||
|
||||
/// \brief Based on the way the client configured the Diagnostic
|
||||
/// \brief Get the set of all diagnostic IDs in the given group.
|
||||
///
|
||||
/// \param Diags [out] - On return, the diagnostics in the group.
|
||||
void getDiagnosticsInGroup(const WarningOption *Group,
|
||||
llvm::SmallVectorImpl<diag::kind> &Diags) const;
|
||||
|
||||
/// \brief Based on the way the client configured the DiagnosticsEngine
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
/// the DiagnosticClient.
|
||||
///
|
||||
/// \param Loc The source location we are interested in finding out the
|
||||
/// diagnostic state. Can be null in order to query the latest state.
|
||||
DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
|
||||
const Diagnostic &Diag,
|
||||
diag::Mapping *mapping = 0) const;
|
||||
const DiagnosticsEngine &Diag) const;
|
||||
|
||||
/// getDiagnosticLevel - This is an internal implementation helper used when
|
||||
/// DiagClass is already known.
|
||||
DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID,
|
||||
unsigned DiagClass,
|
||||
SourceLocation Loc,
|
||||
const Diagnostic &Diag,
|
||||
diag::Mapping *mapping = 0) const;
|
||||
const DiagnosticsEngine &Diag) const;
|
||||
|
||||
/// ProcessDiag - This is the method used to report a diagnostic that is
|
||||
/// finally fully formed.
|
||||
///
|
||||
/// \returns true if the diagnostic was emitted, false if it was
|
||||
/// suppressed.
|
||||
bool ProcessDiag(Diagnostic &Diag) const;
|
||||
bool ProcessDiag(DiagnosticsEngine &Diag) const;
|
||||
|
||||
/// \brief Whether the diagnostic may leave the AST in a state where some
|
||||
/// invariants can break.
|
||||
bool isUnrecoverable(unsigned DiagID) const;
|
||||
|
||||
friend class Diagnostic;
|
||||
friend class DiagnosticsEngine;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -24,6 +24,11 @@ def escaped_newline_block_comment_end : Warning<
|
||||
def backslash_newline_space : Warning<
|
||||
"backslash and newline separated by space">;
|
||||
|
||||
// Digraphs.
|
||||
def warn_cxx98_compat_less_colon_colon : Warning<
|
||||
"'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
|
||||
// Trigraphs.
|
||||
def trigraph_ignored : Warning<"trigraph ignored">, InGroup<Trigraphs>;
|
||||
def trigraph_ignored_block_comment : Warning<
|
||||
@ -38,12 +43,16 @@ def ext_multi_line_bcpl_comment : Extension<"multi-line // comment">,
|
||||
def ext_bcpl_comment : Extension<
|
||||
"// comments are not allowed in this language">,
|
||||
InGroup<Comment>;
|
||||
def ext_no_newline_eof : Extension<"no newline at end of file">;
|
||||
def ext_backslash_newline_eof : Extension<"backslash-newline at end of file">;
|
||||
def ext_no_newline_eof : Extension<"no newline at end of file">,
|
||||
InGroup<DiagGroup<"newline-eof">>;
|
||||
def ext_dollar_in_identifier : Extension<"'$' in identifier">;
|
||||
def charize_microsoft_ext : Extension<"@# is a microsoft extension">;
|
||||
|
||||
def ext_token_used : Extension<"extension used">;
|
||||
def ext_token_used : Extension<"extension used">,
|
||||
InGroup<DiagGroup<"language-extension-token">>;
|
||||
|
||||
def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">,
|
||||
InGroup<CXX11Compat>;
|
||||
|
||||
def warn_unterminated_string : ExtWarn<"missing terminating '\"' character">;
|
||||
def warn_unterminated_char : ExtWarn<"missing terminating ' character">;
|
||||
@ -55,6 +64,18 @@ def err_unterminated___pragma : Error<"missing terminating ')' character">;
|
||||
|
||||
def err_conflict_marker : Error<"version control conflict marker in file">;
|
||||
|
||||
def err_raw_delim_too_long : Error<
|
||||
"raw string delimiter longer than 16 characters"
|
||||
"; use PREFIX( )PREFIX to delimit raw string">;
|
||||
def err_invalid_char_raw_delim : Error<
|
||||
"invalid character '%0' character in raw string delimiter"
|
||||
"; use PREFIX( )PREFIX to delimit raw string">;
|
||||
def err_unterminated_raw_string : Error<
|
||||
"raw string missing terminating delimiter )%0\"">;
|
||||
def warn_cxx98_compat_raw_string_literal : Warning<
|
||||
"raw string literals are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
|
||||
def ext_multichar_character_literal : ExtWarn<
|
||||
"multi-character character constant">, InGroup<MultiChar>;
|
||||
def ext_four_char_character_literal : Extension<
|
||||
@ -77,17 +98,14 @@ def err_invalid_suffix_integer_constant : Error<
|
||||
"invalid suffix '%0' on integer constant">;
|
||||
def err_invalid_suffix_float_constant : Error<
|
||||
"invalid suffix '%0' on floating constant">;
|
||||
def warn_extraneous_wide_char_constant : Warning<
|
||||
"extraneous characters in wide character constant ignored">;
|
||||
def warn_extraneous_char_constant : Warning<
|
||||
"extraneous characters in character constant ignored">;
|
||||
def warn_char_constant_too_large : Warning<
|
||||
"character constant too long for its type">;
|
||||
def err_exponent_has_no_digits : Error<"exponent has no digits">;
|
||||
def ext_imaginary_constant : Extension<"imaginary constants are an extension">;
|
||||
def err_hexconstant_requires_exponent : Error<
|
||||
"hexadecimal floating constants require an exponent">;
|
||||
def ext_hexconstant_cplusplus : Extension<
|
||||
"hexadecimal floating constants are a C99 feature that is incompatible with "
|
||||
"C++0x">, InGroup<CXXHexFloats>;
|
||||
def ext_hexconstant_invalid : Extension<
|
||||
"hexadecimal floating constants are a C99 feature">;
|
||||
def ext_binary_literal : Extension<
|
||||
@ -102,6 +120,11 @@ def warn_ucn_escape_too_large : ExtWarn<
|
||||
"character unicode escape sequence too long for its type">;
|
||||
def warn_ucn_not_valid_in_c89 : ExtWarn<
|
||||
"unicode escape sequences are only valid in C99 or C++">;
|
||||
def warn_cxx98_compat_unicode_literal : Warning<
|
||||
"unicode literals are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def err_unsupported_string_concat : Error<
|
||||
"unsupported non-standard concatenation of string literals">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PTH Diagnostics
|
||||
@ -167,6 +190,9 @@ def ext_pp_bad_vaargs_use : Extension<
|
||||
def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">;
|
||||
def ext_variadic_macro : Extension<"variadic macros were introduced in C99">,
|
||||
InGroup<VariadicMacros>;
|
||||
def warn_cxx98_compat_variadic_macro : Warning<
|
||||
"variadic macros are incompatible with C++98">,
|
||||
InGroup<CXX98CompatPedantic>, DefaultIgnore;
|
||||
def ext_named_variadic_macro : Extension<
|
||||
"named variadic macros are a GNU extension">, InGroup<VariadicMacros>;
|
||||
def ext_embedded_directive : Extension<
|
||||
@ -175,10 +201,13 @@ def ext_missing_varargs_arg : Extension<
|
||||
"varargs argument missing, but tolerated as an extension">;
|
||||
def ext_empty_fnmacro_arg : Extension<
|
||||
"empty macro arguments were standardized in C99">;
|
||||
def warn_cxx98_compat_empty_fnmacro_arg : Warning<
|
||||
"empty macro argument list is incompatible with C++98">,
|
||||
InGroup<CXX98CompatPedantic>, DefaultIgnore;
|
||||
|
||||
def err_pp_invalid_directive : Error<"invalid preprocessing directive">;
|
||||
def err_pp_hash_error : Error<"#error%0">;
|
||||
def warn_pp_file_not_found : Warning<"'%0' file not found">, DefaultFatal;
|
||||
def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
|
||||
def err_pp_error_opening_file : Error<
|
||||
"error opening file '%0': %1">, DefaultFatal;
|
||||
def err_pp_empty_filename : Error<"empty filename">;
|
||||
@ -230,6 +259,13 @@ def err_pp_used_poisoned_id : Error<"attempt to use a poisoned identifier">;
|
||||
def err_feature_check_malformed : Error<
|
||||
"builtin feature check macro requires a parenthesized identifier">;
|
||||
|
||||
def err_warning_check_malformed : Error<
|
||||
"builtin warning check macro requires a parenthesized string">,
|
||||
InGroup<MalformedWarningCheck>;
|
||||
def warn_has_warning_invalid_option :
|
||||
ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">,
|
||||
InGroup<MalformedWarningCheck>;
|
||||
|
||||
def err__Pragma_malformed : Error<
|
||||
"_Pragma takes a parenthesized string literal">;
|
||||
def err_pragma_comment_malformed : Error<
|
||||
@ -315,5 +351,20 @@ def err_pp_linemarker_invalid_pop : Error<
|
||||
"invalid line marker flag '2': cannot pop empty include stack">;
|
||||
def ext_pp_line_too_big : Extension<
|
||||
"C requires #line number to be less than %0, allowed as extension">;
|
||||
def warn_cxx98_compat_pp_line_too_big : Warning<
|
||||
"#line number greater than 32767 is incompatible with C++98">,
|
||||
InGroup<CXX98CompatPedantic>, DefaultIgnore;
|
||||
|
||||
def err_pp_export_non_macro : Error<"no macro named %0 to export">;
|
||||
|
||||
def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">;
|
||||
def err_pp_double_begin_of_arc_cf_code_audited : Error<
|
||||
"already inside '#pragma clang arc_cf_code_audited'">;
|
||||
def err_pp_unmatched_end_of_arc_cf_code_audited : Error<
|
||||
"not currently inside '#pragma clang arc_cf_code_audited'">;
|
||||
def err_pp_include_in_arc_cf_code_audited : Error<
|
||||
"cannot #include files inside '#pragma clang arc_cf_code_audited'">;
|
||||
def err_pp_eof_in_arc_cf_code_audited : Error<
|
||||
"'#pragma clang arc_cf_code_audited' was not ended within this file">;
|
||||
|
||||
}
|
||||
|
@ -28,10 +28,6 @@ def ext_extra_struct_semi : Extension<
|
||||
def ext_extra_ivar_semi : Extension<
|
||||
"extra ';' inside instance variable list">;
|
||||
|
||||
def auto_storage_class : ExtWarn<
|
||||
"'auto' storage class specifier is redundant and will be "
|
||||
"removed in future releases">;
|
||||
|
||||
def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">;
|
||||
def ext_plain_complex : ExtWarn<
|
||||
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
|
||||
@ -57,7 +53,7 @@ def ext_c99_variable_decl_in_for_loop : Extension<
|
||||
def ext_c99_compound_literal : Extension<
|
||||
"compound literals are a C99-specific feature">;
|
||||
def ext_enumerator_list_comma : Extension<
|
||||
"commas at the end of enumerator lists are a %select{C99|C++0x}0-specific "
|
||||
"commas at the end of enumerator lists are a %select{C99|C++11}0-specific "
|
||||
"feature">;
|
||||
def err_enumerator_list_missing_comma : Error<
|
||||
"missing ',' between enumerators">;
|
||||
@ -68,12 +64,15 @@ def ext_ms_enum_fixed_underlying_type : Extension<
|
||||
InGroup<Microsoft>;
|
||||
|
||||
def ext_c1x_generic_selection : Extension<
|
||||
"generic selections are a C1X-specific feature">;
|
||||
"generic selections are a C1X-specific feature">, InGroup<C1X>;
|
||||
def err_duplicate_default_assoc : Error<
|
||||
"duplicate default generic association">;
|
||||
def note_previous_default_assoc : Note<
|
||||
"previous default generic association is here">;
|
||||
|
||||
def ext_c1x_alignas : Extension<
|
||||
"_Alignas is a C1X-specific feature">, InGroup<C1X>;
|
||||
|
||||
def ext_gnu_indirect_goto : Extension<
|
||||
"use of GNU indirect-goto extension">, InGroup<GNU>;
|
||||
def ext_gnu_address_of_label : Extension<
|
||||
@ -188,16 +187,26 @@ def err_invalid_reference_qualifier_application : Error<
|
||||
def err_illegal_decl_reference_to_reference : Error<
|
||||
"%0 declared as a reference to a reference">;
|
||||
def ext_rvalue_reference : ExtWarn<
|
||||
"rvalue references are a C++0x extension">, InGroup<CXX0x>;
|
||||
"rvalue references are a C++11 extension">, InGroup<CXX11>;
|
||||
def ext_ref_qualifier : ExtWarn<
|
||||
"reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>;
|
||||
"reference qualifiers on functions are a C++11 extension">, InGroup<CXX11>;
|
||||
def ext_inline_namespace : ExtWarn<
|
||||
"inline namespaces are a C++0x feature">, InGroup<CXX0x>;
|
||||
"inline namespaces are a C++11 feature">, InGroup<CXX11>;
|
||||
def err_generalized_initializer_lists : Error<
|
||||
"generalized initializer lists are a C++0x extension unsupported in Clang">;
|
||||
"generalized initializer lists are a C++11 extension unsupported in Clang">;
|
||||
def ext_generalized_initializer_lists : ExtWarn<
|
||||
"generalized initializer lists are a C++0x extension unsupported in Clang">,
|
||||
InGroup<CXX0x>;
|
||||
"generalized initializer lists are a C++11 extension unsupported in Clang">,
|
||||
InGroup<CXX11>;
|
||||
def ext_auto_type_specifier : ExtWarn<
|
||||
"'auto' type specifier is a C++11 extension">, InGroup<CXX11>;
|
||||
def warn_auto_storage_class : Warning<
|
||||
"'auto' storage class specifier is redundant and incompatible with C++11">,
|
||||
InGroup<CXX11Compat>;
|
||||
def ext_auto_storage_class : ExtWarn<
|
||||
"'auto' storage class specifier is not permitted in C++11, and will not "
|
||||
"be supported in future releases">;
|
||||
def ext_for_range : ExtWarn<
|
||||
"range-based for loop is a C++11 extension">, InGroup<CXX11>;
|
||||
def err_argument_required_after_attribute : Error<
|
||||
"argument required after attribute">;
|
||||
def err_missing_param : Error<"expected parameter declarator">;
|
||||
@ -219,6 +228,9 @@ def err_typename_invalid_storageclass : Error<
|
||||
"type name does not allow storage class to be specified">;
|
||||
def err_typename_invalid_functionspec : Error<
|
||||
"type name does not allow function specifier to be specified">;
|
||||
def err_typename_identifiers_only : Error<
|
||||
"typename is allowed for identifiers only">;
|
||||
|
||||
def err_invalid_decl_spec_combination : Error<
|
||||
"cannot combine with previous '%0' declaration specifier">;
|
||||
def err_invalid_vector_decl_spec_combination : Error<
|
||||
@ -250,7 +262,7 @@ def err_unexected_colon_in_nested_name_spec : Error<
|
||||
def err_bool_redeclaration : Error<
|
||||
"redeclaration of C++ built-in type 'bool'">;
|
||||
def ext_c1x_static_assert : Extension<
|
||||
"_Static_assert is a C1X-specific feature">;
|
||||
"_Static_assert is a C1X-specific feature">, InGroup<C1X>;
|
||||
|
||||
/// Objective-C parser diagnostics
|
||||
def err_expected_minus_or_plus : Error<
|
||||
@ -342,6 +354,8 @@ def err_destructor_template_id : Error<
|
||||
"destructor name %0 does not refer to a template">;
|
||||
def err_default_arg_unparsed : Error<
|
||||
"unexpected end of default argument expression">;
|
||||
def err_parser_impl_limit_overflow : Error<
|
||||
"parser recursion limit reached, program too complex">, DefaultFatal;
|
||||
|
||||
// C++ derived classes
|
||||
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
|
||||
@ -357,10 +371,15 @@ def err_default_delete_in_multiple_declaration : Error<
|
||||
"'= %select{default|delete}0' is a function definition and must occur in a "
|
||||
"standalone declaration">;
|
||||
|
||||
def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def warn_cxx98_compat_attribute : Warning<
|
||||
"attributes are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def err_cxx0x_attribute_forbids_arguments : Error<
|
||||
"C++0x attribute '%0' cannot have an argument list">;
|
||||
"C++11 attribute '%0' cannot have an argument list">;
|
||||
def err_cxx0x_attribute_requires_arguments : Error<
|
||||
"C++0x attribute '%0' must have an argument list">;
|
||||
"C++1 attribute '%0' must have an argument list">;
|
||||
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
|
||||
|
||||
/// C++ Templates
|
||||
@ -385,7 +404,7 @@ def err_two_right_angle_brackets_need_space : Error<
|
||||
"a space is required between consecutive right angle brackets (use '> >')">;
|
||||
def warn_cxx0x_right_shift_in_template_arg : Warning<
|
||||
"use of right-shift operator ('>>') in template argument will require "
|
||||
"parentheses in C++0x">;
|
||||
"parentheses in C++11">;
|
||||
def err_multiple_template_declarators : Error<
|
||||
"%select{|a template declaration|an explicit template specialization|"
|
||||
"an explicit template instantiation}0 can "
|
||||
@ -446,31 +465,31 @@ def err_missing_whitespace_digraph : Error<
|
||||
" which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">;
|
||||
|
||||
def warn_deleted_function_accepted_as_extension: ExtWarn<
|
||||
"deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
|
||||
"deleted function definition accepted as a C++11 extension">, InGroup<CXX11>;
|
||||
def warn_defaulted_function_accepted_as_extension: ExtWarn<
|
||||
"defaulted function definition accepted as a C++0x extension">,
|
||||
InGroup<CXX0x>;
|
||||
"defaulted function definition accepted as a C++11 extension">,
|
||||
InGroup<CXX11>;
|
||||
|
||||
// C++0x in-class member initialization
|
||||
// C++11 in-class member initialization
|
||||
def warn_nonstatic_member_init_accepted_as_extension: ExtWarn<
|
||||
"in-class initialization of non-static data member accepted as a C++0x extension">,
|
||||
InGroup<CXX0x>;
|
||||
"in-class initialization of non-static data member accepted as a C++11 extension">,
|
||||
InGroup<CXX11>;
|
||||
def err_bitfield_member_init: Error<
|
||||
"bitfield member cannot have an in-class initializer">;
|
||||
def err_incomplete_array_member_init: Error<
|
||||
"array bound cannot be deduced from an in-class initializer">;
|
||||
|
||||
// C++0x alias-declaration
|
||||
// C++11 alias-declaration
|
||||
def ext_alias_declaration : ExtWarn<
|
||||
"alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
|
||||
"alias declarations accepted as a C++11 extension">, InGroup<CXX11>;
|
||||
def err_alias_declaration_not_identifier : Error<
|
||||
"name defined in alias declaration must be an identifier">;
|
||||
def err_alias_declaration_specialization : Error<
|
||||
"%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
|
||||
|
||||
// C++0x override control
|
||||
// C++11 override control
|
||||
def ext_override_control_keyword : Extension<
|
||||
"'%0' keyword accepted as a C++0x extension">, InGroup<CXX0x>;
|
||||
"'%0' keyword accepted as a C++11 extension">, InGroup<CXX11>;
|
||||
|
||||
def err_duplicate_virt_specifier : Error<
|
||||
"class member already marked '%0'">;
|
||||
@ -487,6 +506,15 @@ def err_paren_sizeof_parameter_pack : Error<
|
||||
def err_sizeof_parameter_pack : Error<
|
||||
"expected parenthesized parameter pack name in 'sizeof...' expression">;
|
||||
|
||||
// C++11 lambda expressions
|
||||
def err_expected_comma_or_rsquare : Error<
|
||||
"expected ',' or ']' in lambda capture list">;
|
||||
def err_this_captured_by_reference : Error<
|
||||
"'this' cannot be captured by reference">;
|
||||
def err_expected_capture : Error<
|
||||
"expected variable name or 'this' in lambda capture list">;
|
||||
def err_expected_lambda_body : Error<"expected body of lambda expression">;
|
||||
|
||||
// Availability attribute
|
||||
def err_expected_version : Error<
|
||||
"expected a version of the form 'major[.minor[.subminor]]'">;
|
||||
@ -559,6 +587,14 @@ def err_seh___except_filter : Error<
|
||||
|
||||
def err_seh___finally_block : Error<
|
||||
"%0 only allowed in __finally block">;
|
||||
|
||||
|
||||
} // end of Parse Issue category.
|
||||
|
||||
let CategoryName = "Modules Issue" in {
|
||||
def err_module_expected_ident : Error<
|
||||
"expected a module name after '__import_module__'">;
|
||||
def err_module_expected_semi : Error<
|
||||
"expected a semicolon name after module name">;
|
||||
}
|
||||
|
||||
} // end of Parser diagnostics
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user