Vendor import of clang trunk r238337:
https://llvm.org/svn/llvm-project/cfe/trunk@238337
This commit is contained in:
parent
d5f23b0b75
commit
5e20cdd81c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=283627 svn path=/vendor/clang/clang-trunk-r238337/; revision=283628; tag=vendor/clang/clang-trunk-r238337
@ -402,6 +402,7 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||
FILES_MATCHING
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*.h"
|
||||
)
|
||||
endif()
|
||||
|
||||
@ -440,6 +441,11 @@ if(CLANG_ENABLE_STATIC_ANALYZER)
|
||||
add_definitions(-DCLANG_ENABLE_STATIC_ANALYZER)
|
||||
endif()
|
||||
|
||||
set(OPENMP_DEFAULT_LIB "" CACHE STRING "OpenMP library used by default for -fopenmp.")
|
||||
if(OPENMP_DEFAULT_LIB)
|
||||
add_definitions(-DOPENMP_DEFAULT_LIB=${OPENMP_DEFAULT_LIB})
|
||||
endif()
|
||||
|
||||
# Clang version information
|
||||
set(CLANG_EXECUTABLE_VERSION
|
||||
"${CLANG_VERSION_MAJOR}.${CLANG_VERSION_MINOR}" CACHE STRING
|
||||
|
@ -12,6 +12,10 @@ N: Aaron Ballman
|
||||
E: aaron@aaronballman.com
|
||||
D: Clang attributes
|
||||
|
||||
N: Alexey Bataev
|
||||
E: a.bataev@hotmail.com
|
||||
D: OpenMP support
|
||||
|
||||
N: Chandler Carruth
|
||||
E: chandlerc@gmail.com
|
||||
E: chandlerc@google.com
|
||||
@ -23,7 +27,11 @@ D: Debug Information, autotools/configure/make build, inline assembly
|
||||
|
||||
N: Doug Gregor
|
||||
E: dgregor@apple.com
|
||||
D: All parts of Clang not covered by someone else
|
||||
D: Emeritus owner
|
||||
|
||||
N: Reid Kleckner
|
||||
E: rnk@google.com
|
||||
D: Microsoft C++ ABI compatibility and general Windows support
|
||||
|
||||
N: Anton Korobeynikov
|
||||
E: anton@korobeynikov.info
|
||||
@ -43,4 +51,4 @@ D: Compiler driver
|
||||
|
||||
N: Richard Smith
|
||||
E: richard@metafoo.co.uk
|
||||
D: Clang Semantic Analysis (tools/clang/lib/Sema/* tools/clang/include/clang/Sema/*)
|
||||
D: All parts of Clang not covered by someone else
|
||||
|
@ -4,7 +4,7 @@ LLVM Release License
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007-2014 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
@ -1476,6 +1476,18 @@ def get_tokens(self):
|
||||
"""
|
||||
return TokenGroup.get_tokens(self._tu, self.extent)
|
||||
|
||||
def get_field_offsetof(self):
|
||||
"""Returns the offsetof the FIELD_DECL pointed by this Cursor."""
|
||||
return conf.lib.clang_Cursor_getOffsetOfField(self)
|
||||
|
||||
def is_anonymous(self):
|
||||
"""
|
||||
Check if the record is anonymous.
|
||||
"""
|
||||
if self.kind == CursorKind.FIELD_DECL:
|
||||
return self.type.get_declaration().is_anonymous()
|
||||
return conf.lib.clang_Cursor_isAnonymous(self)
|
||||
|
||||
def is_bitfield(self):
|
||||
"""
|
||||
Check if the field is a bitfield.
|
||||
@ -1884,6 +1896,21 @@ def get_ref_qualifier(self):
|
||||
return RefQualifierKind.from_id(
|
||||
conf.lib.clang_Type_getCXXRefQualifier(self))
|
||||
|
||||
def get_fields(self):
|
||||
"""Return an iterator for accessing the fields of this type."""
|
||||
|
||||
def visitor(field, children):
|
||||
assert field != conf.lib.clang_getNullCursor()
|
||||
|
||||
# Create reference to TU so it isn't GC'd before Cursor.
|
||||
field._tu = self._tu
|
||||
fields.append(field)
|
||||
return 1 # continue
|
||||
fields = []
|
||||
conf.lib.clang_Type_visitFields(self,
|
||||
callbacks['fields_visit'](visitor), fields)
|
||||
return iter(fields)
|
||||
|
||||
@property
|
||||
def spelling(self):
|
||||
"""Retrieve the spelling of this Type."""
|
||||
@ -2780,6 +2807,7 @@ def cursor(self):
|
||||
callbacks['translation_unit_includes'] = CFUNCTYPE(None, c_object_p,
|
||||
POINTER(SourceLocation), c_uint, py_object)
|
||||
callbacks['cursor_visit'] = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
|
||||
callbacks['fields_visit'] = CFUNCTYPE(c_int, Cursor, py_object)
|
||||
|
||||
# Functions strictly alphabetical order.
|
||||
functionList = [
|
||||
@ -3367,6 +3395,10 @@ def cursor(self):
|
||||
[Cursor, c_uint],
|
||||
c_ulonglong),
|
||||
|
||||
("clang_Cursor_isAnonymous",
|
||||
[Cursor],
|
||||
bool),
|
||||
|
||||
("clang_Cursor_isBitField",
|
||||
[Cursor],
|
||||
bool),
|
||||
@ -3381,6 +3413,10 @@ def cursor(self):
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_Cursor_getOffsetOfField",
|
||||
[Cursor],
|
||||
c_longlong),
|
||||
|
||||
("clang_Type_getAlignOf",
|
||||
[Type],
|
||||
c_longlong),
|
||||
@ -3401,6 +3437,10 @@ def cursor(self):
|
||||
("clang_Type_getCXXRefQualifier",
|
||||
[Type],
|
||||
c_uint),
|
||||
|
||||
("clang_Type_visitFields",
|
||||
[Type, callbacks['fields_visit'], py_object],
|
||||
c_uint),
|
||||
]
|
||||
|
||||
class LibclangError(Exception):
|
||||
|
@ -363,6 +363,7 @@ def test_offset():
|
||||
"""Ensure Cursor.get_record_field_offset works in anonymous records"""
|
||||
source="""
|
||||
struct Test {
|
||||
struct {int a;} typeanon;
|
||||
struct {
|
||||
int bariton;
|
||||
union {
|
||||
@ -371,15 +372,23 @@ def test_offset():
|
||||
};
|
||||
int bar;
|
||||
};"""
|
||||
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64)),
|
||||
(['-target','nvptx64-unknown-unknown'],(8,24,0,32,64)),
|
||||
(['-target','i386-pc-win32'],(8,16,0,32,64)),
|
||||
(['-target','msp430-none-none'],(2,14,0,32,64))]
|
||||
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64,96)),
|
||||
(['-target','nvptx64-unknown-unknown'],(8,24,0,32,64,96)),
|
||||
(['-target','i386-pc-win32'],(8,16,0,32,64,96)),
|
||||
(['-target','msp430-none-none'],(2,14,0,32,64,96))]
|
||||
for flags, values in tries:
|
||||
align,total,bariton,foo,bar = values
|
||||
align,total,f1,bariton,foo,bar = values
|
||||
tu = get_tu(source)
|
||||
teststruct = get_cursor(tu, 'Test')
|
||||
fields = list(teststruct.get_children())
|
||||
children = list(teststruct.get_children())
|
||||
fields = list(teststruct.type.get_fields())
|
||||
assert children[0].kind == CursorKind.STRUCT_DECL
|
||||
assert children[0].spelling != "typeanon"
|
||||
assert children[1].spelling == "typeanon"
|
||||
assert fields[0].kind == CursorKind.FIELD_DECL
|
||||
assert fields[1].kind == CursorKind.FIELD_DECL
|
||||
assert fields[1].is_anonymous()
|
||||
assert teststruct.type.get_offset("typeanon") == f1
|
||||
assert teststruct.type.get_offset("bariton") == bariton
|
||||
assert teststruct.type.get_offset("foo") == foo
|
||||
assert teststruct.type.get_offset("bar") == bar
|
||||
|
@ -23,8 +23,7 @@ Typical slowdown introduced by AddressSanitizer is **2x**.
|
||||
How to build
|
||||
============
|
||||
|
||||
Follow the `clang build instructions <../get_started.html>`_. CMake build is
|
||||
supported.
|
||||
Build LLVM/Clang with `CMake <http://llvm.org/docs/CMake.html>`_.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
@ -594,7 +594,9 @@ retainable pointer type <arc.misc.c-retainable>` and it is:
|
||||
* a message send, and the declared method either has the
|
||||
``cf_returns_not_retained`` attribute or it has neither the
|
||||
``cf_returns_retained`` attribute nor a :ref:`selector family
|
||||
<arc.method-families>` that implies a retained result.
|
||||
<arc.method-families>` that implies a retained result, or
|
||||
* :when-revised:`[beginning LLVM 3.6]` :revision:`a load from a` ``const``
|
||||
:revision:`non-system global variable.`
|
||||
|
||||
An expression is :arc-term:`known retained` if it is an rvalue of :ref:`C
|
||||
retainable pointer type <arc.misc.c-retainable>` and it is:
|
||||
@ -631,6 +633,12 @@ retain-agnostic, the conversion is treated as a ``__bridge`` cast.
|
||||
to an ObjC-typed local, and then calling ``CFRelease`` when done --- are a
|
||||
bit too likely to be accidentally accepted, leading to mysterious behavior.
|
||||
|
||||
For loads from ``const`` global variables of :ref:`C retainable pointer type
|
||||
<arc.misc.c-retainable>`, it is reasonable to assume that global system
|
||||
constants were initialitzed with true constants (e.g. string literals), but
|
||||
user constants might have been initialized with something dynamically
|
||||
allocated, using a global initializer.
|
||||
|
||||
.. _arc.objects.restrictions.conversion-exception-contextual:
|
||||
|
||||
Conversion from retainable object pointer type in certain contexts
|
||||
|
@ -155,10 +155,23 @@ the configuration (without a prefix: ``Auto``).
|
||||
|
||||
This applies to round brackets (parentheses), angle brackets and square
|
||||
brackets. This will result in formattings like
|
||||
\code
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
\endcode
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
|
||||
**AlignConsecutiveAssignments** (``bool``)
|
||||
If ``true``, aligns consecutive assignments.
|
||||
|
||||
This will align the assignment operators of consecutive lines. This
|
||||
will result in formattings like
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int aaaa = 12;
|
||||
int b = 23;
|
||||
int ccc = 23;
|
||||
|
||||
**AlignEscapedNewlinesLeft** (``bool``)
|
||||
If ``true``, aligns escaped newlines as far left as possible.
|
||||
@ -330,10 +343,11 @@ the configuration (without a prefix: ``Auto``).
|
||||
instead of as function calls.
|
||||
|
||||
These are expected to be macros of the form:
|
||||
\code
|
||||
FOREACH(<variable-declaration>, ...)
|
||||
<loop-body>
|
||||
\endcode
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
FOREACH(<variable-declaration>, ...)
|
||||
<loop-body>
|
||||
|
||||
For example: BOOST_FOREACH.
|
||||
|
||||
|
145
docs/ControlFlowIntegrity.rst
Normal file
145
docs/ControlFlowIntegrity.rst
Normal file
@ -0,0 +1,145 @@
|
||||
======================
|
||||
Control Flow Integrity
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
ControlFlowIntegrityDesign
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Clang includes an implementation of a number of control flow integrity (CFI)
|
||||
schemes, which are designed to abort the program upon detecting certain forms
|
||||
of undefined behavior that can potentially allow attackers to subvert the
|
||||
program's control flow. These schemes have been optimized for performance,
|
||||
allowing developers to enable them in release builds.
|
||||
|
||||
To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``.
|
||||
As currently implemented, CFI relies on link-time optimization (LTO); the CFI
|
||||
schemes imply ``-flto``, and the linker used must support LTO, for example
|
||||
via the `gold plugin`_. To allow the checks to be implemented efficiently,
|
||||
the program must be structured such that certain object files are compiled
|
||||
with CFI enabled, and are statically linked into the program. This may
|
||||
preclude the use of shared libraries in some cases.
|
||||
|
||||
Clang currently implements forward-edge CFI for member function calls and
|
||||
bad cast checking. More schemes are under development.
|
||||
|
||||
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
|
||||
|
||||
Forward-Edge CFI for Virtual Calls
|
||||
----------------------------------
|
||||
|
||||
This scheme checks that virtual calls take place using a vptr of the correct
|
||||
dynamic type; that is, the dynamic type of the called object must be a
|
||||
derived class of the static type of the object used to make the call.
|
||||
This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vcall``.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not) must be compiled
|
||||
with ``-fsanitize=cfi-vcall`` enabled and be statically linked into the
|
||||
program. Classes in the C++ standard library (under namespace ``std``) are
|
||||
exempted from checking, and therefore programs may be linked against a
|
||||
pre-built standard library, but this may change in the future.
|
||||
|
||||
Performance
|
||||
~~~~~~~~~~~
|
||||
|
||||
A performance overhead of less than 1% has been measured by running the
|
||||
Dromaeo benchmark suite against an instrumented version of the Chromium
|
||||
web browser. Another good performance benchmark for this mechanism is the
|
||||
virtual-call-heavy SPEC 2006 xalancbmk.
|
||||
|
||||
Note that this scheme has not yet been optimized for binary size; an increase
|
||||
of up to 15% has been observed for Chromium.
|
||||
|
||||
Bad Cast Checking
|
||||
-----------------
|
||||
|
||||
This scheme checks that pointer casts are made to an object of the correct
|
||||
dynamic type; that is, the dynamic type of the object must be a derived class
|
||||
of the pointee type of the cast. The checks are currently only introduced
|
||||
where the class being casted to is a polymorphic class.
|
||||
|
||||
Bad casts are not in themselves control flow integrity violations, but they
|
||||
can also create security vulnerabilities, and the implementation uses many
|
||||
of the same mechanisms.
|
||||
|
||||
There are two types of bad cast that may be forbidden: bad casts
|
||||
from a base class to a derived class (which can be checked with
|
||||
``-fsanitize=cfi-derived-cast``), and bad casts from a pointer of
|
||||
type ``void*`` or another unrelated type (which can be checked with
|
||||
``-fsanitize=cfi-unrelated-cast``).
|
||||
|
||||
The difference between these two types of casts is that the first is defined
|
||||
by the C++ standard to produce an undefined value, while the second is not
|
||||
in itself undefined behavior (it is well defined to cast the pointer back
|
||||
to its original type).
|
||||
|
||||
If a program as a matter of policy forbids the second type of cast, that
|
||||
restriction can normally be enforced. However it may in some cases be necessary
|
||||
for a function to perform a forbidden cast to conform with an external API
|
||||
(e.g. the ``allocate`` member function of a standard library allocator). Such
|
||||
functions may be blacklisted using a :doc:`SanitizerSpecialCaseList`.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not) must be compiled with
|
||||
``-fsanitize=cfi-derived-cast`` or ``-fsanitize=cfi-unrelated-cast`` enabled
|
||||
and be statically linked into the program. Classes in the C++ standard library
|
||||
(under namespace ``std``) are exempted from checking, and therefore programs
|
||||
may be linked against a pre-built standard library, but this may change in
|
||||
the future.
|
||||
|
||||
Non-Virtual Member Function Call Checking
|
||||
-----------------------------------------
|
||||
|
||||
This scheme checks that non-virtual calls take place using an object of
|
||||
the correct dynamic type; that is, the dynamic type of the called object
|
||||
must be a derived class of the static type of the object used to make the
|
||||
call. The checks are currently only introduced where the object is of a
|
||||
polymorphic class type. This CFI scheme can be enabled on its own using
|
||||
``-fsanitize=cfi-nvcall``.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not) must be compiled
|
||||
with ``-fsanitize=cfi-nvcall`` enabled and be statically linked into the
|
||||
program. Classes in the C++ standard library (under namespace ``std``) are
|
||||
exempted from checking, and therefore programs may be linked against a
|
||||
pre-built standard library, but this may change in the future.
|
||||
|
||||
.. _cfi-strictness:
|
||||
|
||||
Strictness
|
||||
~~~~~~~~~~
|
||||
|
||||
If a class has a single non-virtual base and does not introduce or override
|
||||
virtual member functions or fields other than an implicitly defined virtual
|
||||
destructor, it will have the same layout and virtual function semantics as
|
||||
its base. By default, casts to such classes are checked as if they were made
|
||||
to the least derived such class.
|
||||
|
||||
Casting an instance of a base class to such a derived class is technically
|
||||
undefined behavior, but it is a relatively common hack for introducing
|
||||
member functions on class instances with specific properties that works under
|
||||
most compilers and should not have security implications, so we allow it by
|
||||
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
|
||||
|
||||
Design
|
||||
------
|
||||
|
||||
Please refer to the :doc:`design document<ControlFlowIntegrityDesign>`.
|
||||
|
||||
Publications
|
||||
------------
|
||||
|
||||
`Control-Flow Integrity: Principles, Implementations, and Applications <http://research.microsoft.com/pubs/64250/ccs05.pdf>`_.
|
||||
Martin Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti.
|
||||
|
||||
`Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM <http://www.pcc.me.uk/~peter/acad/usenix14.pdf>`_.
|
||||
Caroline Tice, Tom Roeder, Peter Collingbourne, Stephen Checkoway,
|
||||
Úlfar Erlingsson, Luis Lozano, Geoff Pike.
|
275
docs/ControlFlowIntegrityDesign.rst
Normal file
275
docs/ControlFlowIntegrityDesign.rst
Normal file
@ -0,0 +1,275 @@
|
||||
===========================================
|
||||
Control Flow Integrity Design Documentation
|
||||
===========================================
|
||||
|
||||
This page documents the design of the :doc:`ControlFlowIntegrity` schemes
|
||||
supported by Clang.
|
||||
|
||||
Forward-Edge CFI for Virtual Calls
|
||||
==================================
|
||||
|
||||
This scheme works by allocating, for each static type used to make a virtual
|
||||
call, a region of read-only storage in the object file holding a bit vector
|
||||
that maps onto to the region of storage used for those virtual tables. Each
|
||||
set bit in the bit vector corresponds to the `address point`_ for a virtual
|
||||
table compatible with the static type for which the bit vector is being built.
|
||||
|
||||
For example, consider the following three C++ classes:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
struct A {
|
||||
virtual void f1();
|
||||
virtual void f2();
|
||||
virtual void f3();
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
virtual void f1();
|
||||
virtual void f2();
|
||||
virtual void f3();
|
||||
};
|
||||
|
||||
struct C : A {
|
||||
virtual void f1();
|
||||
virtual void f2();
|
||||
virtual void f3();
|
||||
};
|
||||
|
||||
The scheme will cause the virtual tables for A, B and C to be laid out
|
||||
consecutively:
|
||||
|
||||
.. csv-table:: Virtual Table Layout for A, B, C
|
||||
:header: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
|
||||
A::offset-to-top, &A::rtti, &A::f1, &A::f2, &A::f3, B::offset-to-top, &B::rtti, &B::f1, &B::f2, &B::f3, C::offset-to-top, &C::rtti, &C::f1, &C::f2, &C::f3
|
||||
|
||||
The bit vector for static types A, B and C will look like this:
|
||||
|
||||
.. csv-table:: Bit Vectors for A, B, C
|
||||
:header: Class, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
|
||||
A, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0
|
||||
B, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
|
||||
C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
|
||||
|
||||
Bit vectors are represented in the object file as byte arrays. By loading
|
||||
from indexed offsets into the byte array and applying a mask, a program can
|
||||
test bits from the bit set with a relatively short instruction sequence. Bit
|
||||
vectors may overlap so long as they use different bits. For the full details,
|
||||
see the `ByteArrayBuilder`_ class.
|
||||
|
||||
In this case, assuming A is laid out at offset 0 in bit 0, B at offset 0 in
|
||||
bit 1 and C at offset 0 in bit 2, the byte array would look like this:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
char bits[] = { 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 5, 0, 0 };
|
||||
|
||||
To emit a virtual call, the compiler will assemble code that checks that
|
||||
the object's virtual table pointer is in-bounds and aligned and that the
|
||||
relevant bit is set in the bit vector.
|
||||
|
||||
For example on x86 a typical virtual call may look like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
ca7fbb: 48 8b 0f mov (%rdi),%rcx
|
||||
ca7fbe: 48 8d 15 c3 42 fb 07 lea 0x7fb42c3(%rip),%rdx
|
||||
ca7fc5: 48 89 c8 mov %rcx,%rax
|
||||
ca7fc8: 48 29 d0 sub %rdx,%rax
|
||||
ca7fcb: 48 c1 c0 3d rol $0x3d,%rax
|
||||
ca7fcf: 48 3d 7f 01 00 00 cmp $0x17f,%rax
|
||||
ca7fd5: 0f 87 36 05 00 00 ja ca8511
|
||||
ca7fdb: 48 8d 15 c0 0b f7 06 lea 0x6f70bc0(%rip),%rdx
|
||||
ca7fe2: f6 04 10 10 testb $0x10,(%rax,%rdx,1)
|
||||
ca7fe6: 0f 84 25 05 00 00 je ca8511
|
||||
ca7fec: ff 91 98 00 00 00 callq *0x98(%rcx)
|
||||
[...]
|
||||
ca8511: 0f 0b ud2
|
||||
|
||||
The compiler relies on co-operation from the linker in order to assemble
|
||||
the bit vectors for the whole program. It currently does this using LLVM's
|
||||
`bit sets`_ mechanism together with link-time optimization.
|
||||
|
||||
.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general
|
||||
.. _bit sets: http://llvm.org/docs/BitSets.html
|
||||
.. _ByteArrayBuilder: http://llvm.org/docs/doxygen/html/structllvm_1_1ByteArrayBuilder.html
|
||||
|
||||
Optimizations
|
||||
-------------
|
||||
|
||||
The scheme as described above is the fully general variant of the scheme.
|
||||
Most of the time we are able to apply one or more of the following
|
||||
optimizations to improve binary size or performance.
|
||||
|
||||
In fact, if you try the above example with the current version of the
|
||||
compiler, you will probably find that it will not use the described virtual
|
||||
table layout or machine instructions. Some of the optimizations we are about
|
||||
to introduce cause the compiler to use a different layout or a different
|
||||
sequence of machine instructions.
|
||||
|
||||
Stripping Leading/Trailing Zeros in Bit Vectors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If a bit vector contains leading or trailing zeros, we can strip them from
|
||||
the vector. The compiler will emit code to check if the pointer is in range
|
||||
of the region covered by ones, and perform the bit vector check using a
|
||||
truncated version of the bit vector. For example, the bit vectors for our
|
||||
example class hierarchy will be emitted like this:
|
||||
|
||||
.. csv-table:: Bit Vectors for A, B, C
|
||||
:header: Class, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
|
||||
A, , , 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ,
|
||||
B, , , , , , , , 1, , , , , , ,
|
||||
C, , , , , , , , , , , , , 1, ,
|
||||
|
||||
Short Inline Bit Vectors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the vector is sufficiently short, we can represent it as an inline constant
|
||||
on x86. This saves us a few instructions when reading the correct element
|
||||
of the bit vector.
|
||||
|
||||
If the bit vector fits in 32 bits, the code looks like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
dc2: 48 8b 03 mov (%rbx),%rax
|
||||
dc5: 48 8d 15 14 1e 00 00 lea 0x1e14(%rip),%rdx
|
||||
dcc: 48 89 c1 mov %rax,%rcx
|
||||
dcf: 48 29 d1 sub %rdx,%rcx
|
||||
dd2: 48 c1 c1 3d rol $0x3d,%rcx
|
||||
dd6: 48 83 f9 03 cmp $0x3,%rcx
|
||||
dda: 77 2f ja e0b <main+0x9b>
|
||||
ddc: ba 09 00 00 00 mov $0x9,%edx
|
||||
de1: 0f a3 ca bt %ecx,%edx
|
||||
de4: 73 25 jae e0b <main+0x9b>
|
||||
de6: 48 89 df mov %rbx,%rdi
|
||||
de9: ff 10 callq *(%rax)
|
||||
[...]
|
||||
e0b: 0f 0b ud2
|
||||
|
||||
Or if the bit vector fits in 64 bits:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
11a6: 48 8b 03 mov (%rbx),%rax
|
||||
11a9: 48 8d 15 d0 28 00 00 lea 0x28d0(%rip),%rdx
|
||||
11b0: 48 89 c1 mov %rax,%rcx
|
||||
11b3: 48 29 d1 sub %rdx,%rcx
|
||||
11b6: 48 c1 c1 3d rol $0x3d,%rcx
|
||||
11ba: 48 83 f9 2a cmp $0x2a,%rcx
|
||||
11be: 77 35 ja 11f5 <main+0xb5>
|
||||
11c0: 48 ba 09 00 00 00 00 movabs $0x40000000009,%rdx
|
||||
11c7: 04 00 00
|
||||
11ca: 48 0f a3 ca bt %rcx,%rdx
|
||||
11ce: 73 25 jae 11f5 <main+0xb5>
|
||||
11d0: 48 89 df mov %rbx,%rdi
|
||||
11d3: ff 10 callq *(%rax)
|
||||
[...]
|
||||
11f5: 0f 0b ud2
|
||||
|
||||
If the bit vector consists of a single bit, there is only one possible
|
||||
virtual table, and the check can consist of a single equality comparison:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
9a2: 48 8b 03 mov (%rbx),%rax
|
||||
9a5: 48 8d 0d a4 13 00 00 lea 0x13a4(%rip),%rcx
|
||||
9ac: 48 39 c8 cmp %rcx,%rax
|
||||
9af: 75 25 jne 9d6 <main+0x86>
|
||||
9b1: 48 89 df mov %rbx,%rdi
|
||||
9b4: ff 10 callq *(%rax)
|
||||
[...]
|
||||
9d6: 0f 0b ud2
|
||||
|
||||
Virtual Table Layout
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The compiler lays out classes of disjoint hierarchies in separate regions
|
||||
of the object file. At worst, bit vectors in disjoint hierarchies only
|
||||
need to cover their disjoint hierarchy. But the closer that classes in
|
||||
sub-hierarchies are laid out to each other, the smaller the bit vectors for
|
||||
those sub-hierarchies need to be (see "Stripping Leading/Trailing Zeros in Bit
|
||||
Vectors" above). The `GlobalLayoutBuilder`_ class is responsible for laying
|
||||
out the globals efficiently to minimize the sizes of the underlying bitsets.
|
||||
|
||||
.. _GlobalLayoutBuilder: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/LowerBitSets.h?view=markup
|
||||
|
||||
Alignment
|
||||
~~~~~~~~~
|
||||
|
||||
If all gaps between address points in a particular bit vector are multiples
|
||||
of powers of 2, the compiler can compress the bit vector by strengthening
|
||||
the alignment requirements of the virtual table pointer. For example, given
|
||||
this class hierarchy:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
struct A {
|
||||
virtual void f1();
|
||||
virtual void f2();
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
virtual void f1();
|
||||
virtual void f2();
|
||||
virtual void f3();
|
||||
virtual void f4();
|
||||
virtual void f5();
|
||||
virtual void f6();
|
||||
};
|
||||
|
||||
struct C : A {
|
||||
virtual void f1();
|
||||
virtual void f2();
|
||||
};
|
||||
|
||||
The virtual tables will be laid out like this:
|
||||
|
||||
.. csv-table:: Virtual Table Layout for A, B, C
|
||||
:header: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
|
||||
A::offset-to-top, &A::rtti, &A::f1, &A::f2, B::offset-to-top, &B::rtti, &B::f1, &B::f2, &B::f3, &B::f4, &B::f5, &B::f6, C::offset-to-top, &C::rtti, &C::f1, &C::f2
|
||||
|
||||
Notice that each address point for A is separated by 4 words. This lets us
|
||||
emit a compressed bit vector for A that looks like this:
|
||||
|
||||
.. csv-table::
|
||||
:header: 2, 6, 10, 14
|
||||
|
||||
1, 1, 0, 1
|
||||
|
||||
At call sites, the compiler will strengthen the alignment requirements by
|
||||
using a different rotate count. For example, on a 64-bit machine where the
|
||||
address points are 4-word aligned (as in A from our example), the ``rol``
|
||||
instruction may look like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
dd2: 48 c1 c1 3b rol $0x3b,%rcx
|
||||
|
||||
Padding to Powers of 2
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Of course, this alignment scheme works best if the address points are
|
||||
in fact aligned correctly. To make this more likely to happen, we insert
|
||||
padding between virtual tables that in many cases aligns address points to
|
||||
a power of 2. Specifically, our padding aligns virtual tables to the next
|
||||
highest power of 2 bytes; because address points for specific base classes
|
||||
normally appear at fixed offsets within the virtual table, this normally
|
||||
has the effect of aligning the address points as well.
|
||||
|
||||
This scheme introduces tradeoffs between decreased space overhead for
|
||||
instructions and bit vectors and increased overhead in the form of padding. We
|
||||
therefore limit the amount of padding so that we align to no more than 128
|
||||
bytes. This number was found experimentally to provide a good tradeoff.
|
||||
|
||||
Eliminating Bit Vector Checks for All-Ones Bit Vectors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the bit vector is all ones, the bit vector check is redundant; we simply
|
||||
need to check that the address is in range and well aligned. This is more
|
||||
likely to occur if the virtual tables are padded.
|
@ -1323,11 +1323,13 @@ range of iterators over declarations of "``f``".
|
||||
``DeclContext`` manages multiply-defined declaration contexts internally. The
|
||||
function ``DeclContext::getPrimaryContext`` retrieves the "primary" context for
|
||||
a given ``DeclContext`` instance, which is the ``DeclContext`` responsible for
|
||||
maintaining the lookup table used for the semantics-centric view. Given the
|
||||
primary context, one can follow the chain of ``DeclContext`` nodes that define
|
||||
additional declarations via ``DeclContext::getNextContext``. Note that these
|
||||
functions are used internally within the lookup and insertion methods of the
|
||||
``DeclContext``, so the vast majority of clients can ignore them.
|
||||
maintaining the lookup table used for the semantics-centric view. Given a
|
||||
DeclContext, one can obtain the set of declaration contexts that are semanticaly
|
||||
connected to this declaration context, in source order, including this context
|
||||
(which will be the only result, for non-namespace contexts) via
|
||||
``DeclContext::collectAllContexts``. Note that these functions are used
|
||||
internally within the lookup and insertion methods of the ``DeclContext``, so
|
||||
the vast majority of clients can ignore them.
|
||||
|
||||
.. _CFG:
|
||||
|
||||
@ -1619,192 +1621,304 @@ How to change Clang
|
||||
|
||||
How to add an attribute
|
||||
-----------------------
|
||||
Attributes are a form of metadata that can be attached to a program construct,
|
||||
allowing the programmer to pass semantic information along to the compiler for
|
||||
various uses. For example, attributes may be used to alter the code generation
|
||||
for a program construct, or to provide extra semantic information for static
|
||||
analysis. This document explains how to add a custom attribute to Clang.
|
||||
Documentation on existing attributes can be found `here
|
||||
<//clang.llvm.org/docs/AttributeReference.html>`_.
|
||||
|
||||
Attribute Basics
|
||||
^^^^^^^^^^^^^^^^
|
||||
Attributes in Clang are handled in three stages: parsing into a parsed attribute
|
||||
representation, conversion from a parsed attribute into a semantic attribute,
|
||||
and then the semantic handling of the attribute.
|
||||
|
||||
Attributes in clang come in two forms: parsed form, and semantic form. Both
|
||||
forms are represented via a tablegen definition of the attribute, specified in
|
||||
Attr.td.
|
||||
Parsing of the attribute is determined by the various syntactic forms attributes
|
||||
can take, such as GNU, C++11, and Microsoft style attributes, as well as other
|
||||
information provided by the table definition of the attribute. Ultimately, the
|
||||
parsed representation of an attribute object is an ``AttributeList`` object.
|
||||
These parsed attributes chain together as a list of parsed attributes attached
|
||||
to a declarator or declaration specifier. The parsing of attributes is handled
|
||||
automatically by Clang, except for attributes spelled as keywords. When
|
||||
implementing a keyword attribute, the parsing of the keyword and creation of the
|
||||
``AttributeList`` object must be done manually.
|
||||
|
||||
Eventually, ``Sema::ProcessDeclAttributeList()`` is called with a ``Decl`` and
|
||||
an ``AttributeList``, at which point the parsed attribute can be transformed
|
||||
into a semantic attribute. The process by which a parsed attribute is converted
|
||||
into a semantic attribute depends on the attribute definition and semantic
|
||||
requirements of the attribute. The end result, however, is that the semantic
|
||||
attribute object is attached to the ``Decl`` object, and can be obtained by a
|
||||
call to ``Decl::getAttr<T>()``.
|
||||
|
||||
The structure of the semantic attribute is also governed by the attribute
|
||||
definition given in Attr.td. This definition is used to automatically generate
|
||||
functionality used for the implementation of the attribute, such as a class
|
||||
derived from ``clang::Attr``, information for the parser to use, automated
|
||||
semantic checking for some attributes, etc.
|
||||
|
||||
|
||||
``include/clang/Basic/Attr.td``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The first step to adding a new attribute to Clang is to add its definition to
|
||||
`include/clang/Basic/Attr.td
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?view=markup>`_.
|
||||
This tablegen definition must derive from the ``Attr`` (tablegen, not
|
||||
semantic) type, or one of its derivatives. Most attributes will derive from the
|
||||
``InheritableAttr`` type, which specifies that the attribute can be inherited by
|
||||
later redeclarations of the ``Decl`` it is associated with.
|
||||
``InheritableParamAttr`` is similar to ``InheritableAttr``, except that the
|
||||
attribute is written on a parameter instead of a declaration. If the attribute
|
||||
is intended to apply to a type instead of a declaration, such an attribute
|
||||
should derive from ``TypeAttr``, and will generally not be given an AST
|
||||
representation. (Note that this document does not cover the creation of type
|
||||
attributes.) An attribute that inherits from ``IgnoredAttr`` is parsed, but will
|
||||
generate an ignored attribute diagnostic when used, which may be useful when an
|
||||
attribute is supported by another vendor but not supported by clang.
|
||||
|
||||
First, add your attribute to the `include/clang/Basic/Attr.td
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?view=markup>`_
|
||||
file.
|
||||
The definition will specify several key pieces of information, such as the
|
||||
semantic name of the attribute, the spellings the attribute supports, the
|
||||
arguments the attribute expects, and more. Most members of the ``Attr`` tablegen
|
||||
type do not require definitions in the derived definition as the default
|
||||
suffice. However, every attribute must specify at least a spelling list, a
|
||||
subject list, and a documentation list.
|
||||
|
||||
Each attribute gets a ``def`` inheriting from ``Attr`` or one of its
|
||||
subclasses. ``InheritableAttr`` means that the attribute also applies to
|
||||
subsequent declarations of the same name. ``InheritableParamAttr`` is similar
|
||||
to ``InheritableAttr``, except that the attribute is written on a parameter
|
||||
instead of a declaration, type or statement. Attributes inheriting from
|
||||
``TypeAttr`` are pure type attributes which generally are not given a
|
||||
representation in the AST. Attributes inheriting from ``TargetSpecificAttr``
|
||||
are attributes specific to one or more target architectures. An attribute that
|
||||
inherits from ``IgnoredAttr`` is parsed, but will generate an ignored attribute
|
||||
diagnostic when used. The attribute type may be useful when an attribute is
|
||||
supported by another vendor, but not supported by clang.
|
||||
Spellings
|
||||
~~~~~~~~~
|
||||
All attributes are required to specify a spelling list that denotes the ways in
|
||||
which the attribute can be spelled. For instance, a single semantic attribute
|
||||
may have a keyword spelling, as well as a C++11 spelling and a GNU spelling. An
|
||||
empty spelling list is also permissible and may be useful for attributes which
|
||||
are created implicitly. The following spellings are accepted:
|
||||
|
||||
``Spellings`` lists the strings that can appear in ``__attribute__((here))`` or
|
||||
``[[here]]``. All such strings will be synonymous. Possible ``Spellings``
|
||||
are: ``GNU`` (for use with GNU-style __attribute__ spellings), ``Declspec``
|
||||
(for use with Microsoft Visual Studio-style __declspec spellings), ``CXX11`
|
||||
(for use with C++11-style [[foo]] and [[foo::bar]] spellings), and ``Keyword``
|
||||
(for use with attributes that are implemented as keywords, like C++11's
|
||||
``override`` or ``final``). If you want to allow the ``[[]]`` C++11 syntax, you
|
||||
have to define a list of ``Namespaces``, which will let users write
|
||||
``[[namespace::spelling]]``. Using the empty string for a namespace will allow
|
||||
users to write just the spelling with no "``::``". Attributes which g++-4.8
|
||||
or later accepts should also have a ``CXX11<"gnu", "spelling">`` spelling.
|
||||
============ ================================================================
|
||||
Spelling Description
|
||||
============ ================================================================
|
||||
``GNU`` Spelled with a GNU-style ``__attribute__((attr))`` syntax and
|
||||
placement.
|
||||
``CXX11`` Spelled with a C++-style ``[[attr]]`` syntax. If the attribute
|
||||
is meant to be used by Clang, it should set the namespace to
|
||||
``"clang"``.
|
||||
``Declspec`` Spelled with a Microsoft-style ``__declspec(attr)`` syntax.
|
||||
``Keyword`` The attribute is spelled as a keyword, and required custom
|
||||
parsing.
|
||||
``GCC`` Specifies two spellings: the first is a GNU-style spelling, and
|
||||
the second is a C++-style spelling with the ``gnu`` namespace.
|
||||
Attributes should only specify this spelling for attributes
|
||||
supported by GCC.
|
||||
``Pragma`` The attribute is spelled as a ``#pragma``, and requires custom
|
||||
processing within the preprocessor. If the attribute is meant to
|
||||
be used by Clang, it should set the namespace to ``"clang"``.
|
||||
Note that this spelling is not used for declaration attributes.
|
||||
============ ================================================================
|
||||
|
||||
``Subjects`` restricts what kinds of AST node to which this attribute can
|
||||
appertain (roughly, attach). The subjects are specified via a ``SubjectList``,
|
||||
which specify the list of subjects. Additionally, subject-related diagnostics
|
||||
can be specified to be warnings or errors, with the default being a warning.
|
||||
The diagnostics displayed to the user are automatically determined based on
|
||||
the subjects in the list, but a custom diagnostic parameter can also be
|
||||
specified in the ``SubjectList``. The diagnostics generated for subject list
|
||||
violations are either ``diag::warn_attribute_wrong_decl_type`` or
|
||||
``diag::err_attribute_wrong_decl_type``, and the parameter enumeration is
|
||||
found in `include/clang/Sema/AttributeList.h
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?view=markup>`_
|
||||
If you add new Decl nodes to the ``SubjectList``, you may need to update the
|
||||
logic used to automatically determine the diagnostic parameter in `utils/TableGen/ClangAttrEmitter.cpp
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?view=markup>`_.
|
||||
Subjects
|
||||
~~~~~~~~
|
||||
Attributes appertain to one or more ``Decl`` subjects. If the attribute attempts
|
||||
to attach to a subject that is not in the subject list, a diagnostic is issued
|
||||
automatically. Whether the diagnostic is a warning or an error depends on how
|
||||
the attribute's ``SubjectList`` is defined, but the default behavior is to warn.
|
||||
The diagnostics displayed to the user are automatically determined based on the
|
||||
subjects in the list, but a custom diagnostic parameter can also be specified in
|
||||
the ``SubjectList``. The diagnostics generated for subject list violations are
|
||||
either ``diag::warn_attribute_wrong_decl_type`` or
|
||||
``diag::err_attribute_wrong_decl_type``, and the parameter enumeration is found
|
||||
in `include/clang/Sema/AttributeList.h
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?view=markup>`_
|
||||
If a previously unused Decl node is added to the ``SubjectList``, the logic used
|
||||
to automatically determine the diagnostic parameter in `utils/TableGen/ClangAttrEmitter.cpp
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?view=markup>`_
|
||||
may need to be updated.
|
||||
|
||||
Diagnostic checking for attribute subject lists is automated except when
|
||||
``HasCustomParsing`` is set to ``1``.
|
||||
|
||||
By default, all subjects in the SubjectList must either be a Decl node defined
|
||||
in ``DeclNodes.td``, or a statement node defined in ``StmtNodes.td``. However,
|
||||
more complex subjects can be created by creating a ``SubsetSubject`` object.
|
||||
Each such object has a base subject which it appertains to (which must be a
|
||||
Decl or Stmt node, and not a SubsetSubject node), and some custom code which is
|
||||
called when determining whether an attribute appertains to the subject. For
|
||||
instance, a ``NonBitField`` SubsetSubject appertains to a ``FieldDecl``, and
|
||||
tests whether the given FieldDecl is a bit field. When a SubsetSubject is
|
||||
By default, all subjects in the SubjectList must either be a Decl node defined
|
||||
in ``DeclNodes.td``, or a statement node defined in ``StmtNodes.td``. However,
|
||||
more complex subjects can be created by creating a ``SubsetSubject`` object.
|
||||
Each such object has a base subject which it appertains to (which must be a
|
||||
Decl or Stmt node, and not a SubsetSubject node), and some custom code which is
|
||||
called when determining whether an attribute appertains to the subject. For
|
||||
instance, a ``NonBitField`` SubsetSubject appertains to a ``FieldDecl``, and
|
||||
tests whether the given FieldDecl is a bit field. When a SubsetSubject is
|
||||
specified in a SubjectList, a custom diagnostic parameter must also be provided.
|
||||
|
||||
``Args`` names the arguments the attribute takes, in order. If ``Args`` is
|
||||
Diagnostic checking for attribute subject lists is automated except when
|
||||
``HasCustomParsing`` is set to ``1``.
|
||||
|
||||
Documentation
|
||||
~~~~~~~~~~~~~
|
||||
All attributes must have some form of documentation associated with them.
|
||||
Documentation is table generated on the public web server by a server-side
|
||||
process that runs daily. Generally, the documentation for an attribute is a
|
||||
stand-alone definition in `include/clang/Basic/AttrDocs.td
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttdDocs.td?view=markup>`_
|
||||
that is named after the attribute being documented.
|
||||
|
||||
If the attribute is not for public consumption, or is an implicitly-created
|
||||
attribute that has no visible spelling, the documentation list can specify the
|
||||
``Undocumented`` object. Otherwise, the attribute should have its documentation
|
||||
added to AttrDocs.td.
|
||||
|
||||
Documentation derives from the ``Documentation`` tablegen type. All derived
|
||||
types must specify a documentation category and the actual documentation itself.
|
||||
Additionally, it can specify a custom heading for the attribute, though a
|
||||
default heading will be chosen when possible.
|
||||
|
||||
There are four predefined documentation categories: ``DocCatFunction`` for
|
||||
attributes that appertain to function-like subjects, ``DocCatVariable`` for
|
||||
attributes that appertain to variable-like subjects, ``DocCatType`` for type
|
||||
attributes, and ``DocCatStmt`` for statement attributes. A custom documentation
|
||||
category should be used for groups of attributes with similar functionality.
|
||||
Custom categories are good for providing overview information for the attributes
|
||||
grouped under it. For instance, the consumed annotation attributes define a
|
||||
custom category, ``DocCatConsumed``, that explains what consumed annotations are
|
||||
at a high level.
|
||||
|
||||
Documentation content (whether it is for an attribute or a category) is written
|
||||
using reStructuredText (RST) syntax.
|
||||
|
||||
After writing the documentation for the attribute, it should be locally tested
|
||||
to ensure that there are no issues generating the documentation on the server.
|
||||
Local testing requires a fresh build of clang-tblgen. To generate the attribute
|
||||
documentation, execute the following command::
|
||||
|
||||
clang-tblgen -gen-attr-docs -I /path/to/clang/include /path/to/clang/include/clang/Basic/Attr.td -o /path/to/clang/docs/AttributeReference.rst
|
||||
|
||||
When testing locally, *do not* commit changes to ``AttributeReference.rst``.
|
||||
This file is generated by the server automatically, and any changes made to this
|
||||
file will be overwritten.
|
||||
|
||||
Arguments
|
||||
~~~~~~~~~
|
||||
Attributes may optionally specify a list of arguments that can be passed to the
|
||||
attribute. Attribute arguments specify both the parsed form and the semantic
|
||||
form of the attribute. For example, if ``Args`` is
|
||||
``[StringArgument<"Arg1">, IntArgument<"Arg2">]`` then
|
||||
``__attribute__((myattribute("Hello", 3)))`` will be a valid use. Attribute
|
||||
arguments specify both the parsed form and the semantic form of the attribute.
|
||||
The previous example shows an attribute which requires two attributes while
|
||||
parsing, and the Attr subclass' constructor for the attribute will require a
|
||||
string and integer argument.
|
||||
``__attribute__((myattribute("Hello", 3)))`` will be a valid use; it requires
|
||||
two arguments while parsing, and the Attr subclass' constructor for the
|
||||
semantic attribute will require a string and integer argument.
|
||||
|
||||
Diagnostic checking for argument counts is automated except when
|
||||
``HasCustomParsing`` is set to ``1``, or when the attribute uses an optional or
|
||||
variadic argument. Diagnostic checking for argument semantics is not automated.
|
||||
All arguments have a name and a flag that specifies whether the argument is
|
||||
optional. The associated C++ type of the argument is determined by the argument
|
||||
definition type. If the existing argument types are insufficient, new types can
|
||||
be created, but it requires modifying `utils/TableGen/ClangAttrEmitter.cpp
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?view=markup>`_
|
||||
to properly support the type.
|
||||
|
||||
If the parsed form of the attribute is more complex, or differs from the
|
||||
semantic form, the ``HasCustomParsing`` bit can be set to ``1`` for the class,
|
||||
and the parsing code in `Parser::ParseGNUAttributeArgs
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?view=markup>`_
|
||||
can be updated for the special case. Note that this only applies to arguments
|
||||
with a GNU spelling -- attributes with a __declspec spelling currently ignore
|
||||
Other Properties
|
||||
~~~~~~~~~~~~~~~~
|
||||
The ``Attr`` definition has other members which control the behavior of the
|
||||
attribute. Many of them are special-purpose and beyond the scope of this
|
||||
document, however a few deserve mention.
|
||||
|
||||
If the parsed form of the attribute is more complex, or differs from the
|
||||
semantic form, the ``HasCustomParsing`` bit can be set to ``1`` for the class,
|
||||
and the parsing code in `Parser::ParseGNUAttributeArgs()
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?view=markup>`_
|
||||
can be updated for the special case. Note that this only applies to arguments
|
||||
with a GNU spelling -- attributes with a __declspec spelling currently ignore
|
||||
this flag and are handled by ``Parser::ParseMicrosoftDeclSpec``.
|
||||
|
||||
Custom accessors can be generated for an attribute based on the spelling list
|
||||
for that attribute. For instance, if an attribute has two different spellings:
|
||||
'Foo' and 'Bar', accessors can be created:
|
||||
``[Accessor<"isFoo", [GNU<"Foo">]>, Accessor<"isBar", [GNU<"Bar">]>]``
|
||||
These accessors will be generated on the semantic form of the attribute,
|
||||
accepting no arguments and returning a Boolean.
|
||||
Note that setting this member to 1 will opt out of common attribute semantic
|
||||
handling, requiring extra implementation efforts to ensure the attribute
|
||||
appertains to the appropriate subject, etc.
|
||||
|
||||
Attributes which do not require an AST node should set the ``ASTNode`` field to
|
||||
``0`` to avoid polluting the AST. Note that anything inheriting from
|
||||
``TypeAttr`` or ``IgnoredAttr`` automatically do not generate an AST node. All
|
||||
other attributes generate an AST node by default. The AST node is the semantic
|
||||
If the attribute should not be propagated from from a template declaration to an
|
||||
instantiation of the template, set the ``Clone`` member to 0. By default, all
|
||||
attributes will be cloned to template instantiations.
|
||||
|
||||
Attributes that do not require an AST node should set the ``ASTNode`` field to
|
||||
``0`` to avoid polluting the AST. Note that anything inheriting from
|
||||
``TypeAttr`` or ``IgnoredAttr`` automatically do not generate an AST node. All
|
||||
other attributes generate an AST node by default. The AST node is the semantic
|
||||
representation of the attribute.
|
||||
|
||||
Attributes which do not require custom semantic handling should set the
|
||||
``SemaHandler`` field to ``0``. Note that anything inheriting from
|
||||
``IgnoredAttr`` automatically do not get a semantic handler. All other
|
||||
attributes are assumed to use a semantic handler by default. Attributes
|
||||
without a semantic handler are not given a parsed attribute Kind enumeration.
|
||||
The ``LangOpts`` field specifies a list of language options required by the
|
||||
attribute. For instance, all of the CUDA-specific attributes specify ``[CUDA]``
|
||||
for the ``LangOpts`` field, and when the CUDA language option is not enabled, an
|
||||
"attribute ignored" warning diagnostic is emitted. Since language options are
|
||||
not table generated nodes, new language options must be created manually and
|
||||
should specify the spelling used by ``LangOptions`` class.
|
||||
|
||||
The ``LangOpts`` field can be used to specify a list of language options
|
||||
required by the attribute. For instance, all of the CUDA-specific attributes
|
||||
specify ``[CUDA]`` for the ``LangOpts`` field, and when the CUDA language
|
||||
option is not enabled, an "attribute ignored" warning diagnostic is emitted.
|
||||
Since language options are not table generated nodes, new language options must
|
||||
be created manually and should specify the spelling used by ``LangOptions`` class.
|
||||
Custom accessors can be generated for an attribute based on the spelling list
|
||||
for that attribute. For instance, if an attribute has two different spellings:
|
||||
'Foo' and 'Bar', accessors can be created:
|
||||
``[Accessor<"isFoo", [GNU<"Foo">]>, Accessor<"isBar", [GNU<"Bar">]>]``
|
||||
These accessors will be generated on the semantic form of the attribute,
|
||||
accepting no arguments and returning a ``bool``.
|
||||
|
||||
Target-specific attribute sometimes share a spelling with other attributes in
|
||||
different targets. For instance, the ARM and MSP430 targets both have an
|
||||
attribute spelled ``GNU<"interrupt">``, but with different parsing and semantic
|
||||
requirements. To support this feature, an attribute inheriting from
|
||||
``TargetSpecificAttribute`` make specify a ``ParseKind`` field. This field
|
||||
should be the same value between all arguments sharing a spelling, and
|
||||
corresponds to the parsed attribute's Kind enumeration. This allows attributes
|
||||
to share a parsed attribute kind, but have distinct semantic attribute classes.
|
||||
For instance, ``AttributeList::AT_Interrupt`` is the shared parsed attribute
|
||||
kind, but ARMInterruptAttr and MSP430InterruptAttr are the semantic attributes
|
||||
generated.
|
||||
Attributes that do not require custom semantic handling should set the
|
||||
``SemaHandler`` field to ``0``. Note that anything inheriting from
|
||||
``IgnoredAttr`` automatically do not get a semantic handler. All other
|
||||
attributes are assumed to use a semantic handler by default. Attributes
|
||||
without a semantic handler are not given a parsed attribute ``Kind`` enumerator.
|
||||
|
||||
By default, when declarations are merging attributes, an attribute will not be
|
||||
duplicated. However, if an attribute can be duplicated during this merging
|
||||
stage, set ``DuplicatesAllowedWhileMerging`` to ``1``, and the attribute will
|
||||
Target-specific attributes may share a spelling with other attributes in
|
||||
different targets. For instance, the ARM and MSP430 targets both have an
|
||||
attribute spelled ``GNU<"interrupt">``, but with different parsing and semantic
|
||||
requirements. To support this feature, an attribute inheriting from
|
||||
``TargetSpecificAttribute`` may specify a ``ParseKind`` field. This field
|
||||
should be the same value between all arguments sharing a spelling, and
|
||||
corresponds to the parsed attribute's ``Kind`` enumerator. This allows
|
||||
attributes to share a parsed attribute kind, but have distinct semantic
|
||||
attribute classes. For instance, ``AttributeList::AT_Interrupt`` is the shared
|
||||
parsed attribute kind, but ARMInterruptAttr and MSP430InterruptAttr are the
|
||||
semantic attributes generated.
|
||||
|
||||
By default, when declarations are merging attributes, an attribute will not be
|
||||
duplicated. However, if an attribute can be duplicated during this merging
|
||||
stage, set ``DuplicatesAllowedWhileMerging`` to ``1``, and the attribute will
|
||||
be merged.
|
||||
|
||||
By default, attribute arguments are parsed in an evaluated context. If the
|
||||
arguments for an attribute should be parsed in an unevaluated context (akin to
|
||||
the way the argument to a ``sizeof`` expression is parsed), you can set
|
||||
By default, attribute arguments are parsed in an evaluated context. If the
|
||||
arguments for an attribute should be parsed in an unevaluated context (akin to
|
||||
the way the argument to a ``sizeof`` expression is parsed), set
|
||||
``ParseArgumentsAsUnevaluated`` to ``1``.
|
||||
|
||||
If additional functionality is desired for the semantic form of the attribute,
|
||||
the ``AdditionalMembers`` field specifies code to be copied verbatim into the
|
||||
semantic attribute class object.
|
||||
|
||||
All attributes must have one or more form of documentation, which is provided
|
||||
in the ``Documentation`` list. Generally, the documentation for an attribute
|
||||
is a stand-alone definition in `include/clang/Basic/AttrDocs.td
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttdDocs.td?view=markup>`_
|
||||
that is named after the attribute being documented. Each documentation element
|
||||
is given a ``Category`` (variable, function, or type) and ``Content``. A single
|
||||
attribute may contain multiple documentation elements for distinct categories.
|
||||
For instance, an attribute which can appertain to both function and types (such
|
||||
as a calling convention attribute), should contain two documentation elements.
|
||||
The ``Content`` for an attribute uses reStructuredText (RST) syntax.
|
||||
|
||||
If an attribute is used internally by the compiler, but is not written by users
|
||||
(such as attributes with an empty spelling list), it can use the
|
||||
``Undocumented`` documentation element.
|
||||
If additional functionality is desired for the semantic form of the attribute,
|
||||
the ``AdditionalMembers`` field specifies code to be copied verbatim into the
|
||||
semantic attribute class object, with ``public`` access.
|
||||
|
||||
Boilerplate
|
||||
^^^^^^^^^^^
|
||||
|
||||
All semantic processing of declaration attributes happens in `lib/Sema/SemaDeclAttr.cpp
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?view=markup>`_,
|
||||
and generally starts in the ``ProcessDeclAttribute`` function. If your
|
||||
attribute is a "simple" attribute -- meaning that it requires no custom
|
||||
semantic processing aside from what is automatically provided for you, you can
|
||||
add a call to ``handleSimpleAttribute<YourAttr>(S, D, Attr);`` to the switch
|
||||
statement. Otherwise, write a new ``handleYourAttr()`` function, and add that
|
||||
to the switch statement.
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?view=markup>`_,
|
||||
and generally starts in the ``ProcessDeclAttribute()`` function. If the
|
||||
attribute is a "simple" attribute -- meaning that it requires no custom semantic
|
||||
processing aside from what is automatically provided, add a call to
|
||||
``handleSimpleAttribute<YourAttr>(S, D, Attr);`` to the switch statement.
|
||||
Otherwise, write a new ``handleYourAttr()`` function, and add that to the switch
|
||||
statement. Please do not implement handling logic directly in the ``case`` for
|
||||
the attribute.
|
||||
|
||||
If your attribute causes extra warnings to fire, define a ``DiagGroup`` in
|
||||
Unless otherwise specified by the attribute definition, common semantic checking
|
||||
of the parsed attribute is handled automatically. This includes diagnosing
|
||||
parsed attributes that do not appertain to the given ``Decl``, ensuring the
|
||||
correct minimum number of arguments are passed, etc.
|
||||
|
||||
If the attribute adds additional warnings, define a ``DiagGroup`` in
|
||||
`include/clang/Basic/DiagnosticGroups.td
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?view=markup>`_
|
||||
named after the attribute's ``Spelling`` with "_"s replaced by "-"s. If you're
|
||||
only defining one diagnostic, you can skip ``DiagnosticGroups.td`` and use
|
||||
``InGroup<DiagGroup<"your-attribute">>`` directly in `DiagnosticSemaKinds.td
|
||||
named after the attribute's ``Spelling`` with "_"s replaced by "-"s. If there
|
||||
is only a single diagnostic, it is permissible to use ``InGroup<DiagGroup<"your-attribute">>``
|
||||
directly in `DiagnosticSemaKinds.td
|
||||
<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?view=markup>`_
|
||||
|
||||
All semantic diagnostics generated for your attribute, including automatically-
|
||||
generated ones (such as subjects and argument counts), should have a
|
||||
generated ones (such as subjects and argument counts), should have a
|
||||
corresponding test case.
|
||||
|
||||
The meat of your attribute
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Semantic handling
|
||||
^^^^^^^^^^^^^^^^^
|
||||
Most attributes are implemented to have some effect on the compiler. For
|
||||
instance, to modify the way code is generated, or to add extra semantic checks
|
||||
for an analysis pass, etc. Having added the attribute definition and conversion
|
||||
to the semantic representation for the attribute, what remains is to implement
|
||||
the custom logic requiring use of the attribute.
|
||||
|
||||
Find an appropriate place in Clang to do whatever your attribute needs to do.
|
||||
Check for the attribute's presence using ``Decl::getAttr<YourAttr>()``.
|
||||
|
||||
Update the :doc:`LanguageExtensions` document to describe your new attribute.
|
||||
The ``clang::Decl`` object can be queried for the presence or absence of an
|
||||
attribute using ``hasAttr<T>()``. To obtain a pointer to the semantic
|
||||
representation of the attribute, ``getAttr<T>`` may be used.
|
||||
|
||||
How to add an expression or statement
|
||||
-------------------------------------
|
||||
|
@ -935,6 +935,14 @@ C11 ``_Thread_local``
|
||||
Use ``__has_feature(c_thread_local)`` or ``__has_extension(c_thread_local)``
|
||||
to determine if support for ``_Thread_local`` variables is enabled.
|
||||
|
||||
Modules
|
||||
-------
|
||||
|
||||
Use ``__has_feature(modules)`` to determine if Modules have been enabled.
|
||||
For example, compiling code with ``-fmodules`` enables the use of Modules.
|
||||
|
||||
More information could be found `here <http://clang.llvm.org/docs/Modules.html>`_.
|
||||
|
||||
Checks for Type Trait Primitives
|
||||
================================
|
||||
|
||||
|
@ -307,6 +307,19 @@ Example matches X, Z
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('translationUnitDecl0')"><a name="translationUnitDecl0Anchor">translationUnitDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html">TranslationUnitDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="translationUnitDecl0"><pre>Matches the top declaration context.
|
||||
|
||||
Given
|
||||
int X;
|
||||
namespace NS {
|
||||
int Y;
|
||||
} namespace NS
|
||||
decl(hasDeclContext(translationUnitDecl()))
|
||||
matches "int X", but not "int Y".
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('typedefDecl0')"><a name="typedefDecl0Anchor">typedefDecl</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefDecl.html">TypedefDecl</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="typedefDecl0"><pre>Matches typedef declarations.
|
||||
|
||||
@ -1525,7 +1538,7 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOpe
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>StringRef BaseName</td></tr>
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isDerivedFrom1"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)).
|
||||
</pre></td></tr>
|
||||
|
||||
@ -1544,7 +1557,7 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Functi
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>StringRef BaseName</td></tr>
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>std::string BaseName</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom1"><pre>Overloaded method as shortcut for
|
||||
isSameOrDerivedFrom(hasName(...)).
|
||||
</pre></td></tr>
|
||||
@ -1721,19 +1734,6 @@ by the compiler (eg. implicit defaultcopy constructors).
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isInstantiated0')"><a name="isInstantiated0Anchor">isInstantiated</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isInstantiated0"><pre>Matches declarations that are template instantiations or are inside
|
||||
template instantiations.
|
||||
|
||||
Given
|
||||
template<typename T> void A(T t) { T i; }
|
||||
A(0);
|
||||
A(0U);
|
||||
functionDecl(isInstantiated())
|
||||
matches 'A(int) {...};' and 'A(unsigned) {...}'.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isPrivate0')"><a name="isPrivate0Anchor">isPrivate</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isPrivate0"><pre>Matches private C++ declarations.
|
||||
|
||||
@ -2093,22 +2093,6 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.h
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isInTemplateInstantiation0')"><a name="isInTemplateInstantiation0Anchor">isInTemplateInstantiation</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isInTemplateInstantiation0"><pre>Matches statements inside of a template instantiation.
|
||||
|
||||
Given
|
||||
int j;
|
||||
template<typename T> void A(T t) { T i; j += 42;}
|
||||
A(0);
|
||||
A(0U);
|
||||
declStmt(isInTemplateInstantiation())
|
||||
matches 'int i;' and 'unsigned i'.
|
||||
unless(stmt(isInTemplateInstantiation()))
|
||||
will NOT match j += 42; as it's shared between the template definition and
|
||||
instantiation.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
|
||||
|
||||
@ -2229,6 +2213,16 @@ and reference to that variable declaration within a compound statement.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('voidType0')"><a name="voidType0Anchor">voidType</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="voidType0"><pre>Matches type void.
|
||||
|
||||
Given
|
||||
struct S { void func(); };
|
||||
functionDecl(returns(voidType()))
|
||||
matches "void func();"
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>></td><td class="name" onclick="toggle('ofKind0')"><a name="ofKind0Anchor">ofKind</a></td><td>UnaryExprOrTypeTrait Kind</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="ofKind0"><pre>Matches unary expressions of a certain kind.
|
||||
|
||||
@ -2323,6 +2317,35 @@ recordDecl(hasName("::X"), isTemplateInstantiation())
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>></td><td class="name" onclick="toggle('isInstantiated0')"><a name="isInstantiated0Anchor">isInstantiated</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isInstantiated0"><pre>Matches declarations that are template instantiations or are inside
|
||||
template instantiations.
|
||||
|
||||
Given
|
||||
template<typename T> void A(T t) { T i; }
|
||||
A(0);
|
||||
A(0U);
|
||||
functionDecl(isInstantiated())
|
||||
matches 'A(int) {...};' and 'A(unsigned) {...}'.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<internal::Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>></td><td class="name" onclick="toggle('isInTemplateInstantiation0')"><a name="isInTemplateInstantiation0Anchor">isInTemplateInstantiation</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isInTemplateInstantiation0"><pre>Matches statements inside of a template instantiation.
|
||||
|
||||
Given
|
||||
int j;
|
||||
template<typename T> void A(T t) { T i; j += 42;}
|
||||
A(0);
|
||||
A(0U);
|
||||
declStmt(isInTemplateInstantiation())
|
||||
matches 'int i;' and 'unsigned i'.
|
||||
unless(stmt(isInTemplateInstantiation()))
|
||||
will NOT match j += 42; as it's shared between the template definition and
|
||||
instantiation.
|
||||
</pre></td></tr>
|
||||
|
||||
<!--END_NARROWING_MATCHERS -->
|
||||
</table>
|
||||
|
||||
|
@ -84,14 +84,23 @@ The status of major ABI-impacting C++ features:
|
||||
* RTTI: :good:`Complete`. Generation of RTTI data structures has been
|
||||
finished, along with support for the ``/GR`` flag.
|
||||
|
||||
* Exceptions and SEH: :partial:`Minimal`. Clang can parse both constructs, but
|
||||
does not know how to emit compatible handlers. Clang cannot throw exceptions
|
||||
but it can rethrow them.
|
||||
* Exceptions and SEH: :partial:`Partial`.
|
||||
C++ exceptions (``try`` / ``catch`` / ``throw``) and
|
||||
structured exceptions (``__try`` / ``__except`` / ``__finally``) mostly
|
||||
work on x64. 32-bit exception handling support is being worked on. LLVM does
|
||||
not model asynchronous exceptions, so it is currently impossible to catch an
|
||||
asynchronous exception generated in the same frame as the catching ``__try``.
|
||||
C++ exception specifications are ignored, but this is `consistent with Visual
|
||||
C++`_.
|
||||
|
||||
* Thread-safe initialization of local statics: :none:`Unstarted`. We are ABI
|
||||
compatible with MSVC 2013, which does not support thread-safe local statics.
|
||||
MSVC "14" changed the ABI to make initialization of local statics thread safe,
|
||||
and we have not yet implemented this.
|
||||
.. _consistent with Visual C++:
|
||||
https://msdn.microsoft.com/en-us/library/wfa0edys.aspx
|
||||
|
||||
* Thread-safe initialization of local statics: :good:`Complete`. MSVC 2015
|
||||
added support for thread-safe initialization of such variables by taking an
|
||||
ABI break.
|
||||
We are ABI compatible with both the MSVC 2013 and 2015 ABI for static local
|
||||
variables.
|
||||
|
||||
* Lambdas: :good:`Mostly complete`. Clang is compatible with Microsoft's
|
||||
implementation of lambdas except for providing overloads for conversion to
|
||||
@ -112,7 +121,7 @@ time. By default on Windows, Clang attempts to follow suit. This behavior is
|
||||
controlled by the ``-fdelayed-template-parsing`` flag. While Clang delays
|
||||
parsing of method bodies, it still parses the bodies *before* template argument
|
||||
substitution, which is not what MSVC does. The following compatibility tweaks
|
||||
are necessary to parse the the template in those cases.
|
||||
are necessary to parse the template in those cases.
|
||||
|
||||
MSVC allows some name lookup into dependent base classes. Even on other
|
||||
platforms, this has been a `frequently asked question`_ for Clang users. A
|
||||
|
@ -16,15 +16,22 @@ DOXYGEN = doxygen
|
||||
|
||||
$(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
|
||||
cat $< | sed \
|
||||
-e 's/@abs_srcdir@/./g' \
|
||||
-e 's/@DOT@/dot/g' \
|
||||
-e 's/@PACKAGE_VERSION@/mainline/' \
|
||||
-e 's/@abs_builddir@/./g' \
|
||||
-e 's/@enable_searchengine@/NO/g' \
|
||||
-e 's/@searchengine_url@//g' \
|
||||
-e 's/@enable_server_based_search@/NO/g' \
|
||||
-e 's/@abs_srcdir@/./g' \
|
||||
-e 's/@clang_doxygen_generate_qhp@/NO/g' \
|
||||
-e 's/@clang_doxygen_qch_filename@//g' \
|
||||
-e 's/@clang_doxygen_qhelpgenerator_path@//g' \
|
||||
-e 's/@clang_doxygen_qhp_cust_filter_attrs@//g' \
|
||||
-e 's/@clang_doxygen_qhp_cust_filter_name@//g' \
|
||||
-e 's/@clang_doxygen_qhp_namespace@//g' \
|
||||
-e 's/@enable_external_search@/NO/g' \
|
||||
-e 's/@extra_search_mappings@//g' > $@
|
||||
-e 's/@enable_searchengine@/NO/g' \
|
||||
-e 's/@enable_server_based_search@/NO/g' \
|
||||
-e 's/@extra_search_mappings@//g' \
|
||||
-e 's/@searchengine_url@//g' \
|
||||
> $@
|
||||
endif
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
@ -32,9 +39,7 @@ include $(CLANG_LEVEL)/Makefile
|
||||
HTML := $(wildcard $(PROJ_SRC_DIR)/*.html) \
|
||||
$(wildcard $(PROJ_SRC_DIR)/*.css)
|
||||
#IMAGES := $(wildcard $(PROJ_SRC_DIR)/img/*.*)
|
||||
DOXYFILES := doxygen.cfg.in doxygen.css doxygen.footer doxygen.header \
|
||||
doxygen.intro
|
||||
EXTRA_DIST := $(HTML) $(DOXYFILES) llvm.css CommandGuide img
|
||||
DOXYFILES := doxygen.cfg.in doxygen.intro
|
||||
|
||||
.PHONY: install-html install-doxygen doxygen generated
|
||||
|
||||
@ -68,11 +73,14 @@ $(PROJ_OBJ_DIR)/html.tar.gz: $(HTML)
|
||||
|
||||
install-doxygen: doxygen
|
||||
$(Echo) Installing doxygen documentation
|
||||
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_docsdir)/html/doxygen
|
||||
$(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(DESTDIR)$(PROJ_docsdir)
|
||||
$(Verb) cd $(PROJ_OBJ_DIR)/doxygen && \
|
||||
$(FIND) . -type f -exec \
|
||||
$(DataInstall) {} $(DESTDIR)$(PROJ_docsdir)/html/doxygen \;
|
||||
$(Verb) cd $(PROJ_OBJ_DIR)/doxygen/html && \
|
||||
for DIR in $$($(FIND) . -type d); do \
|
||||
DESTSUB="$(DESTDIR)$(PROJ_docsdir)/html/doxygen/$$(echo $$DIR | cut -c 3-)"; \
|
||||
$(MKDIR) $$DESTSUB && \
|
||||
$(FIND) $$DIR -maxdepth 1 -type f -exec $(DataInstall) {} $$DESTSUB \; ; \
|
||||
if [ $$? != 0 ]; then exit 1; fi \
|
||||
done
|
||||
|
||||
doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
|
||||
|
||||
|
@ -16,8 +16,7 @@ Typical slowdown introduced by MemorySanitizer is **3x**.
|
||||
How to build
|
||||
============
|
||||
|
||||
Follow the `clang build instructions <../get_started.html>`_. CMake
|
||||
build is supported.
|
||||
Build LLVM/Clang with `CMake <http://llvm.org/docs/CMake.html>`_.
|
||||
|
||||
Usage
|
||||
=====
|
||||
@ -111,30 +110,10 @@ Origin Tracking
|
||||
|
||||
MemorySanitizer can track origins of unitialized values, similar to
|
||||
Valgrind's --track-origins option. This feature is enabled by
|
||||
``-fsanitize-memory-track-origins`` Clang option. With the code from
|
||||
``-fsanitize-memory-track-origins=2`` (or simply
|
||||
``-fsanitize-memory-track-origins``) Clang option. With the code from
|
||||
the example above,
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O2 umr.cc
|
||||
% ./a.out
|
||||
WARNING: MemorySanitizer: use-of-uninitialized-value
|
||||
#0 0x7f7893912f0b in main umr2.cc:6
|
||||
#1 0x7f789249b76c in __libc_start_main libc-start.c:226
|
||||
|
||||
Uninitialized value was created by a heap allocation
|
||||
#0 0x7f7893901cbd in operator new[](unsigned long) msan_new_delete.cc:44
|
||||
#1 0x7f7893912e06 in main umr2.cc:4
|
||||
|
||||
Origin tracking has proved to be very useful for debugging MemorySanitizer
|
||||
reports. It slows down program execution by a factor of 1.5x-2x on top
|
||||
of the usual MemorySanitizer slowdown.
|
||||
|
||||
MemorySanitizer can provide even more information with
|
||||
``-fsanitize-memory-track-origins=2`` flag. In this mode reports
|
||||
include information about intermediate stores the uninitialized value went
|
||||
through.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% cat umr2.cc
|
||||
@ -163,6 +142,15 @@ through.
|
||||
#0 0x7f7893901cbd in operator new[](unsigned long) msan_new_delete.cc:44
|
||||
#1 0x7f7893912e06 in main umr2.cc:4
|
||||
|
||||
By default, MemorySanitizer collects both allocation points and all
|
||||
intermediate stores the uninitialized value went through. Origin
|
||||
tracking has proved to be very useful for debugging MemorySanitizer
|
||||
reports. It slows down program execution by a factor of 1.5x-2x on top
|
||||
of the usual MemorySanitizer slowdown.
|
||||
|
||||
Clang option ``-fsanitize-memory-track-origins=1`` enabled a slightly
|
||||
faster mode when MemorySanitizer collects only allocation points but
|
||||
not intermediate stores.
|
||||
|
||||
Handling external code
|
||||
============================
|
||||
@ -177,15 +165,7 @@ interceptors for the most common libc functions. They make it possible
|
||||
to run MemorySanitizer-instrumented programs linked with
|
||||
uninstrumented libc. For example, the authors were able to bootstrap
|
||||
MemorySanitizer-instrumented Clang compiler by linking it with
|
||||
self-built instrumented libcxx (as a replacement for libstdc++).
|
||||
|
||||
In the case when rebuilding all program dependencies with
|
||||
MemorySanitizer is problematic, an experimental MSanDR tool can be
|
||||
used. It is a DynamoRio-based tool that uses dynamic instrumentation
|
||||
to avoid false positives due to uninstrumented code. The tool simply
|
||||
marks memory from instrumented libraries as fully initialized. See
|
||||
`http://code.google.com/p/memory-sanitizer/wiki/Running#Running_with_the_dynamic_tool`
|
||||
for more information.
|
||||
self-built instrumented libc++ (as a replacement for libstdc++).
|
||||
|
||||
Supported Platforms
|
||||
===================
|
||||
|
@ -210,6 +210,12 @@ Command-line parameters
|
||||
``-fno-modules-implicit-maps``
|
||||
Suppresses the implicit search for files called ``module.modulemap`` and similar. Instead, module files need to be explicitly specified via ``-fmodule-map-file`` or transitively used.
|
||||
|
||||
``-fno-implicit-modules``
|
||||
All modules used by the build must be specified with ``-fmodule-file``.
|
||||
|
||||
``-fmodule-file=<file>``
|
||||
Load the given precompiled module file.
|
||||
|
||||
Module Semantics
|
||||
================
|
||||
|
||||
@ -423,7 +429,7 @@ tls
|
||||
A specific target feature (e.g., ``sse4``, ``avx``, ``neon``) is available.
|
||||
|
||||
|
||||
**Example**: The ``std`` module can be extended to also include C++ and C++11 headers using a *requires-declaration*:
|
||||
**Example:** The ``std`` module can be extended to also include C++ and C++11 headers using a *requires-declaration*:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
@ -464,11 +470,16 @@ A header with the ``umbrella`` specifier is called an umbrella header. An umbrel
|
||||
|
||||
A header with the ``private`` specifier may not be included from outside the module itself.
|
||||
|
||||
A header with the ``textual`` specifier will not be included when the module is built, and will be textually included if it is named by a ``#include`` directive. However, it is considered to be part of the module for the purpose of checking *use-declaration*\s.
|
||||
A header with the ``textual`` specifier will not be compiled when the module is
|
||||
built, and will be textually included if it is named by a ``#include``
|
||||
directive. However, it is considered to be part of the module for the purpose
|
||||
of checking *use-declaration*\s, and must still be a lexically-valid header
|
||||
file. In the future, we intend to pre-tokenize such headers and include the
|
||||
token sequence within the prebuilt module representation.
|
||||
|
||||
A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module, even if an ``umbrella`` header or directory would otherwise make it part of the module.
|
||||
|
||||
**Example**: The C header ``assert.h`` is an excellent candidate for a textual header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings). However, declarations within it should typically be split into a separate modular header.
|
||||
**Example:** The C header ``assert.h`` is an excellent candidate for a textual header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings). However, declarations within it should typically be split into a separate modular header.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
@ -530,7 +541,7 @@ For each header included by the umbrella header or in the umbrella directory tha
|
||||
* Contain a single *header-declaration* naming that header
|
||||
* Contain a single *export-declaration* ``export *``, if the \ *inferred-submodule-declaration* contains the \ *inferred-submodule-member* ``export *``
|
||||
|
||||
**Example**: If the subdirectory "MyLib" contains the headers ``A.h`` and ``B.h``, then the following module map:
|
||||
**Example:** If the subdirectory "MyLib" contains the headers ``A.h`` and ``B.h``, then the following module map:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
@ -573,7 +584,7 @@ An *export-declaration* specifies which imported modules will automatically be r
|
||||
|
||||
The *export-declaration* names a module or a set of modules that will be re-exported to any translation unit that imports the enclosing module. Each imported module that matches the *wildcard-module-id* up to, but not including, the first ``*`` will be re-exported.
|
||||
|
||||
**Example**:: In the following example, importing ``MyLib.Derived`` also provides the API for ``MyLib.Base``:
|
||||
**Example:** In the following example, importing ``MyLib.Derived`` also provides the API for ``MyLib.Base``:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
@ -617,14 +628,16 @@ Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard e
|
||||
|
||||
Use declaration
|
||||
~~~~~~~~~~~~~~~
|
||||
A *use-declaration* specifies one of the other modules that the module is allowed to use. An import or include not matching one of these is rejected when the option *-fmodules-decluse*.
|
||||
A *use-declaration* specifies another module that the current top-level module
|
||||
intends to use. When the option *-fmodules-decluse* is specified, a module can
|
||||
only use other modules that are explicitly specified in this way.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
*use-declaration*:
|
||||
``use`` *module-id*
|
||||
|
||||
**Example**:: In the following example, use of A from C is not declared, so will trigger a warning.
|
||||
**Example:** In the following example, use of A from C is not declared, so will trigger a warning.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
@ -641,7 +654,9 @@ A *use-declaration* specifies one of the other modules that the module is allowe
|
||||
use B
|
||||
}
|
||||
|
||||
When compiling a source file that implements a module, use the option ``-fmodule-name=module-id`` to indicate that the source file is logically part of that module.
|
||||
When compiling a source file that implements a module, use the option
|
||||
``-fmodule-name=module-id`` to indicate that the source file is logically part
|
||||
of that module.
|
||||
|
||||
The compiler at present only applies restrictions to the module directly being built.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
=======================
|
||||
Clang 3.6 Release Notes
|
||||
=======================
|
||||
=====================================
|
||||
Clang 3.7 (In-Progress) Release Notes
|
||||
=====================================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@ -8,16 +8,22 @@ Clang 3.6 Release Notes
|
||||
|
||||
Written by the `LLVM Team <http://llvm.org/>`_
|
||||
|
||||
.. warning::
|
||||
|
||||
These are in-progress notes for the upcoming Clang 3.7 release. You may
|
||||
prefer the `Clang 3.6 Release Notes
|
||||
<http://llvm.org/releases/3.6.0/tools/clang/docs/ReleaseNotes.html>`_.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document contains the release notes for the Clang C/C++/Objective-C
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.6. Here we
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.7. Here we
|
||||
describe the status of Clang in some detail, including major
|
||||
improvements from the previous release and new feature work. For the
|
||||
general LLVM release notes, see `the LLVM
|
||||
documentation <http://llvm.org/releases/3.6.0/docs/ReleaseNotes.html>`_.
|
||||
All LLVM releases may be downloaded from the `LLVM releases web
|
||||
documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
|
||||
releases may be downloaded from the `LLVM releases web
|
||||
site <http://llvm.org/releases/>`_.
|
||||
|
||||
For more information about Clang or LLVM, including information about
|
||||
@ -25,7 +31,12 @@ the latest release, please check out the main please see the `Clang Web
|
||||
Site <http://clang.llvm.org>`_ or the `LLVM Web
|
||||
Site <http://llvm.org>`_.
|
||||
|
||||
What's New in Clang 3.6?
|
||||
Note that if you are reading this file from a Subversion checkout or the
|
||||
main Clang web page, this document applies to the *next* release, not
|
||||
the current one. To see the release notes for a specific release, please
|
||||
see the `releases page <http://llvm.org/releases/>`_.
|
||||
|
||||
What's New in Clang 3.7?
|
||||
========================
|
||||
|
||||
Some of the major new features and improvements to Clang are listed
|
||||
@ -36,171 +47,116 @@ sections with improvements to Clang's support for those languages.
|
||||
Major New Features
|
||||
------------------
|
||||
|
||||
- The __has_attribute built-in macro no longer queries for attributes across
|
||||
multiple attribute syntaxes (GNU, C++11, __declspec, etc). Instead, it only
|
||||
queries GNU-style attributes. With the addition of __has_cpp_attribute and
|
||||
__has_declspec_attribute, this allows for more precise coverage of attribute
|
||||
syntax querying.
|
||||
|
||||
- clang-format now supports formatting Java code.
|
||||
|
||||
- Use of the ``__declspec`` language extension for declaration attributes now
|
||||
requires passing the -fms-extensions or -fborland compiler flag. This language
|
||||
extension is also enabled when compiling CUDA code, but its use should be
|
||||
viewed as an implementation detail that is subject to change.
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
-----------------------------------
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Clang's diagnostics are constantly being improved to catch more issues,
|
||||
explain them more clearly, and provide more accurate source information
|
||||
about them. The improvements since the 3.5 release include:
|
||||
|
||||
- Smarter typo correction. Clang now tries a bit harder to give a usable
|
||||
suggestion in more cases, and can now successfully recover in more
|
||||
situations where the suggestion changes how an expression is parsed.
|
||||
|
||||
- ...
|
||||
|
||||
New Compiler Flags
|
||||
------------------
|
||||
|
||||
The ``-fpic`` option now uses small pic on PowerPC.
|
||||
The sized deallocation feature of C++14 is now controlled by the
|
||||
``-fsized-deallocation`` flag. This feature relies on library support that
|
||||
isn't yet widely deployed, so the user must supply an extra flag to get the
|
||||
extra functionality.
|
||||
|
||||
|
||||
The __EXCEPTIONS macro
|
||||
----------------------
|
||||
``__EXCEPTIONS`` is now defined when landing pads are emitted, not when
|
||||
C++ exceptions are enabled. The two can be different in Objective-C files:
|
||||
If C++ exceptions are disabled but Objective-C exceptions are enabled,
|
||||
landing pads will be emitted. Clang 3.6 is switching the behavior of
|
||||
``__EXCEPTIONS``. Clang 3.5 confusingly changed the behavior of
|
||||
``has_feature(cxx_exceptions)``, which used to be set if landing pads were
|
||||
emitted, but is now set if C++ exceptions are enabled. So there are 3 cases:
|
||||
|
||||
Clang before 3.5:
|
||||
``__EXCEPTIONS`` is set if C++ exceptions are enabled, ``cxx_exceptions``
|
||||
enabled if C++ or ObjC exceptions are enabled
|
||||
|
||||
Clang 3.5:
|
||||
``__EXCEPTIONS`` is set if C++ exceptions are enabled, ``cxx_exceptions``
|
||||
enabled if C++ exceptions are enabled
|
||||
|
||||
Clang 3.6:
|
||||
``__EXCEPTIONS`` is set if C++ or ObjC exceptions are enabled,
|
||||
``cxx_exceptions`` enabled if C++ exceptions are enabled
|
||||
|
||||
To reliably test if C++ exceptions are enabled, use
|
||||
``__EXCEPTIONS && __has_feature(cxx_exceptions)``, else things won't work in
|
||||
all versions of Clang in Objective-C++ files.
|
||||
The option ....
|
||||
|
||||
|
||||
New Pragmas in Clang
|
||||
-----------------------
|
||||
|
||||
Clang now supports the `#pragma unroll` and `#pragma nounroll` directives to
|
||||
specify loop unrolling optimization hints. Placed just prior to the desired
|
||||
loop, `#pragma unroll` directs the loop unroller to attempt to fully unroll the
|
||||
loop. The pragma may also be specified with a positive integer parameter
|
||||
indicating the desired unroll count: `#pragma unroll _value_`. The unroll count
|
||||
parameter can be optionally enclosed in parentheses. The directive `#pragma
|
||||
nounroll` indicates that the loop should not be unrolled. These unrolling hints
|
||||
may also be expressed using the `#pragma clang loop` directive. See the Clang
|
||||
`language extensions
|
||||
<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
|
||||
for details.
|
||||
Clang now supports the ...
|
||||
|
||||
Windows Support
|
||||
---------------
|
||||
|
||||
- Many, many bug fixes.
|
||||
|
||||
- Clang can now self-host using the ``msvc`` environment on x86 and x64
|
||||
Windows. This means that Microsoft C++ ABI is more or less feature-complete,
|
||||
minus exception support.
|
||||
|
||||
- Added more MSVC compatibility hacks, such as allowing more lookup into
|
||||
dependent bases of class templates when there is a known template pattern.
|
||||
As a result, applications using Active Template Library (ATL) or Windows
|
||||
Runtime Library (WRL) headers should compile correctly.
|
||||
|
||||
- Added support for the Visual C++ ``__super`` keyword.
|
||||
|
||||
- Added support for MSVC's ``__vectorcall`` calling convention, which is used
|
||||
in the upcoming Visual Studio 2015 STL.
|
||||
|
||||
- Added basic support for DWARF debug information in COFF files.
|
||||
Clang's support for building native Windows programs ...
|
||||
|
||||
|
||||
C Language Changes in Clang
|
||||
---------------------------
|
||||
|
||||
- The default language mode for C compilations with Clang has been changed from
|
||||
C99 with GNU extensions to C11 with GNU extensions. C11 is largely
|
||||
backwards-compatible with C99, but if you want to restore the former behavior
|
||||
you can do so with the `-std=gnu99` flag.
|
||||
...
|
||||
|
||||
C11 Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Clang now provides an implementation of the standard C11 header `<stdatomic.h>`.
|
||||
...
|
||||
|
||||
C++ Language Changes in Clang
|
||||
-----------------------------
|
||||
|
||||
- An `upcoming change to C++ <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html>_`
|
||||
changes the semantics of certain deductions of `auto` from a braced initializer
|
||||
list. Following the intent of the C++ committee, this change will be applied to
|
||||
our C++11 and C++14 modes as well as our experimental C++17 mode. Clang 3.6
|
||||
does not yet implement this change, but to provide a transition period, it
|
||||
warns on constructs whose meaning will change. The fix in all cases is to
|
||||
add an `=` prior to the left brace.
|
||||
- ...
|
||||
|
||||
- Clang now supports putting identical constructors and destructors in
|
||||
the C5/D5 comdat, reducing code duplication.
|
||||
|
||||
- Clang will put individual ``.init_array/.ctors`` sections in
|
||||
comdats, reducing code duplication and speeding up startup.
|
||||
|
||||
|
||||
C++17 Feature Support
|
||||
C++11 Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Clang has experimental support for some proposed C++1z (tentatively, C++17)
|
||||
features. This support can be enabled using the `-std=c++1z` flag.
|
||||
...
|
||||
|
||||
New in Clang 3.6 is support for:
|
||||
Objective-C Language Changes in Clang
|
||||
-------------------------------------
|
||||
|
||||
- Fold expressions
|
||||
...
|
||||
|
||||
- `u8` character literals
|
||||
OpenCL C Language Changes in Clang
|
||||
----------------------------------
|
||||
|
||||
- Nested namespace definitions: `namespace A::B { ... }` as a shorthand for
|
||||
`namespace A { namespace B { ... } }`
|
||||
...
|
||||
|
||||
- Attributes for namespaces and enumerators
|
||||
Internal API Changes
|
||||
--------------------
|
||||
|
||||
- Constant evaluation for all non-type template arguments
|
||||
These are major API changes that have happened since the 3.6 release of
|
||||
Clang. If upgrading an external codebase that uses Clang as a library,
|
||||
this section should help get you past the largest hurdles of upgrading.
|
||||
|
||||
Note that these features may be changed or removed in future Clang releases
|
||||
without notice.
|
||||
- Some of the `PPCallbacks` interface now deals in `MacroDefinition`
|
||||
objects instead of `MacroDirective` objects. This allows preserving
|
||||
full information on macros imported from modules.
|
||||
|
||||
Support for `for (identifier : range)` as a synonym for
|
||||
`for (auto &&identifier : range)` has been removed as it is no longer currently
|
||||
considered for C++17.
|
||||
- `clang-c/Index.h` no longer `#include`\s `clang-c/Documentation.h`.
|
||||
You now need to explicitly `#include "clang-c/Documentation.h"` if
|
||||
you use the libclang documentation API.
|
||||
|
||||
For more details on C++ feature support, see
|
||||
`the C++ status page <http://clang.llvm.org/cxx_status.html>`_.
|
||||
libclang
|
||||
--------
|
||||
|
||||
...
|
||||
|
||||
OpenMP Language Changes in Clang
|
||||
--------------------------------
|
||||
Static Analyzer
|
||||
---------------
|
||||
|
||||
Clang 3.6 contains codegen for many individual OpenMP pragmas, but combinations are not completed yet.
|
||||
We plan to continue codegen code drop aiming for completion in 3.7. Please see this link for up-to-date
|
||||
`status <https://github.com/clang-omp/clang/wiki/Status-of-supported-OpenMP-constructs>_`.
|
||||
LLVM's OpenMP runtime library, originally developed by Intel, has been modified to work on ARM, PowerPC,
|
||||
as well as X86. The Runtime Library's compatibility with GCC 4.9 is improved
|
||||
- missed entry points added, barrier and fork/join code improved, one more type of barrier enabled.
|
||||
Support for ppc64le architecture is now available and automatically detected when using cmake system.
|
||||
Using makefile the new "ppc64le" arch type is available.
|
||||
Contributors to this work include AMD, Argonne National Lab., IBM, Intel, Texas Instruments, University of Houston and many others.
|
||||
...
|
||||
|
||||
Core Analysis Improvements
|
||||
==========================
|
||||
|
||||
- ...
|
||||
|
||||
New Issues Found
|
||||
================
|
||||
|
||||
- ...
|
||||
|
||||
Python Binding Changes
|
||||
----------------------
|
||||
|
||||
The following methods have been added:
|
||||
|
||||
- ...
|
||||
|
||||
Significant Known Problems
|
||||
==========================
|
||||
|
||||
Additional Information
|
||||
======================
|
||||
|
355
docs/SanitizerCoverage.rst
Normal file
355
docs/SanitizerCoverage.rst
Normal file
@ -0,0 +1,355 @@
|
||||
=================
|
||||
SanitizerCoverage
|
||||
=================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Sanitizer tools have a very simple code coverage tool built in. It allows to
|
||||
get function-level, basic-block-level, and edge-level coverage at a very low
|
||||
cost.
|
||||
|
||||
How to build and run
|
||||
====================
|
||||
|
||||
SanitizerCoverage can be used with :doc:`AddressSanitizer`,
|
||||
:doc:`LeakSanitizer`, :doc:`MemorySanitizer`, and UndefinedBehaviorSanitizer.
|
||||
In addition to ``-fsanitize=``, pass one of the following compile-time flags:
|
||||
|
||||
* ``-fsanitize-coverage=func`` for function-level coverage (very fast).
|
||||
* ``-fsanitize-coverage=bb`` for basic-block-level coverage (may add up to 30%
|
||||
**extra** slowdown).
|
||||
* ``-fsanitize-coverage=edge`` for edge-level coverage (up to 40% slowdown).
|
||||
|
||||
You may also specify ``-fsanitize-coverage=indirect-calls`` for
|
||||
additional `caller-callee coverage`_.
|
||||
|
||||
At run time, pass ``coverage=1`` in ``ASAN_OPTIONS``, ``LSAN_OPTIONS``,
|
||||
``MSAN_OPTIONS`` or ``UBSAN_OPTIONS``, as appropriate.
|
||||
|
||||
To get `Coverage counters`_, add ``-fsanitize-coverage=8bit-counters``
|
||||
to one of the above compile-time flags. At runtime, use
|
||||
``*SAN_OPTIONS=coverage=1:coverage_counters=1``.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% cat -n cov.cc
|
||||
1 #include <stdio.h>
|
||||
2 __attribute__((noinline))
|
||||
3 void foo() { printf("foo\n"); }
|
||||
4
|
||||
5 int main(int argc, char **argv) {
|
||||
6 if (argc == 2)
|
||||
7 foo();
|
||||
8 printf("main\n");
|
||||
9 }
|
||||
% clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=func
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out; ls -l *sancov
|
||||
main
|
||||
-rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out foo ; ls -l *sancov
|
||||
foo
|
||||
main
|
||||
-rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
|
||||
-rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
|
||||
|
||||
Every time you run an executable instrumented with SanitizerCoverage
|
||||
one ``*.sancov`` file is created during the process shutdown.
|
||||
If the executable is dynamically linked against instrumented DSOs,
|
||||
one ``*.sancov`` file will be also created for every DSO.
|
||||
|
||||
Postprocessing
|
||||
==============
|
||||
|
||||
The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic,
|
||||
one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the
|
||||
magic defines the size of the following offsets. The rest of the data is the
|
||||
offsets in the corresponding binary/DSO that were executed during the run.
|
||||
|
||||
A simple script
|
||||
``$LLVM/projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py`` is
|
||||
provided to dump these offsets.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% sancov.py print a.out.22679.sancov a.out.22673.sancov
|
||||
sancov.py: read 2 PCs from a.out.22679.sancov
|
||||
sancov.py: read 1 PCs from a.out.22673.sancov
|
||||
sancov.py: 2 files merged; 2 PCs total
|
||||
0x465250
|
||||
0x4652a0
|
||||
|
||||
You can then filter the output of ``sancov.py`` through ``addr2line --exe
|
||||
ObjectFile`` or ``llvm-symbolizer --obj ObjectFile`` to get file names and line
|
||||
numbers:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% sancov.py print a.out.22679.sancov a.out.22673.sancov 2> /dev/null | llvm-symbolizer --obj a.out
|
||||
cov.cc:3
|
||||
cov.cc:5
|
||||
|
||||
How good is the coverage?
|
||||
=========================
|
||||
|
||||
It is possible to find out which PCs are not covered, by subtracting the covered
|
||||
set from the set of all instrumented PCs. The latter can be obtained by listing
|
||||
all callsites of ``__sanitizer_cov()`` in the binary. On Linux, ``sancov.py``
|
||||
can do this for you. Just supply the path to binary and a list of covered PCs:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% sancov.py print a.out.12345.sancov > covered.txt
|
||||
sancov.py: read 2 64-bit PCs from a.out.12345.sancov
|
||||
sancov.py: 1 file merged; 2 PCs total
|
||||
% sancov.py missing a.out < covered.txt
|
||||
sancov.py: found 3 instrumented PCs in a.out
|
||||
sancov.py: read 2 PCs from stdin
|
||||
sancov.py: 1 PCs missing from coverage
|
||||
0x4cc61c
|
||||
|
||||
Edge coverage
|
||||
=============
|
||||
|
||||
Consider this code:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void foo(int *a) {
|
||||
if (a)
|
||||
*a = 0;
|
||||
}
|
||||
|
||||
It contains 3 basic blocks, let's name them A, B, C:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
A
|
||||
|\
|
||||
| \
|
||||
| B
|
||||
| /
|
||||
|/
|
||||
C
|
||||
|
||||
If blocks A, B, and C are all covered we know for certain that the edges A=>B
|
||||
and B=>C were executed, but we still don't know if the edge A=>C was executed.
|
||||
Such edges of control flow graph are called
|
||||
`critical <http://en.wikipedia.org/wiki/Control_flow_graph#Special_edges>`_. The
|
||||
edge-level coverage (``-fsanitize-coverage=edge``) simply splits all critical
|
||||
edges by introducing new dummy blocks and then instruments those blocks:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
A
|
||||
|\
|
||||
| \
|
||||
D B
|
||||
| /
|
||||
|/
|
||||
C
|
||||
|
||||
Bitset
|
||||
======
|
||||
|
||||
When ``coverage_bitset=1`` run-time flag is given, the coverage will also be
|
||||
dumped as a bitset (text file with 1 for blocks that have been executed and 0
|
||||
for blocks that were not).
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -fsanitize=address -fsanitize-coverage=edge cov.cc
|
||||
% ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out
|
||||
main
|
||||
% ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out 1
|
||||
foo
|
||||
main
|
||||
% head *bitset*
|
||||
==> a.out.38214.bitset-sancov <==
|
||||
01101
|
||||
==> a.out.6128.bitset-sancov <==
|
||||
11011%
|
||||
|
||||
For a given executable the length of the bitset is always the same (well,
|
||||
unless dlopen/dlclose come into play), so the bitset coverage can be
|
||||
easily used for bitset-based corpus distillation.
|
||||
|
||||
Caller-callee coverage
|
||||
======================
|
||||
|
||||
(Experimental!)
|
||||
Every indirect function call is instrumented with a run-time function call that
|
||||
captures caller and callee. At the shutdown time the process dumps a separate
|
||||
file called ``caller-callee.PID.sancov`` which contains caller/callee pairs as
|
||||
pairs of lines (odd lines are callers, even lines are callees)
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
a.out 0x4a2e0c
|
||||
a.out 0x4a6510
|
||||
a.out 0x4a2e0c
|
||||
a.out 0x4a87f0
|
||||
|
||||
Current limitations:
|
||||
|
||||
* Only the first 14 callees for every caller are recorded, the rest are silently
|
||||
ignored.
|
||||
* The output format is not very compact since caller and callee may reside in
|
||||
different modules and we need to spell out the module names.
|
||||
* The routine that dumps the output is not optimized for speed
|
||||
* Only Linux x86_64 is tested so far.
|
||||
* Sandboxes are not supported.
|
||||
|
||||
Coverage counters
|
||||
=================
|
||||
|
||||
This experimental feature is inspired by
|
||||
`AFL <http://lcamtuf.coredump.cx/afl/technical_details.txt>`_'s coverage
|
||||
instrumentation. With additional compile-time and run-time flags you can get
|
||||
more sensitive coverage information. In addition to boolean values assigned to
|
||||
every basic block (edge) the instrumentation will collect imprecise counters.
|
||||
On exit, every counter will be mapped to a 8-bit bitset representing counter
|
||||
ranges: ``1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+`` and those 8-bit bitsets will
|
||||
be dumped to disk.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=edge,8bit-counters
|
||||
% ASAN_OPTIONS="coverage=1:coverage_counters=1" ./a.out
|
||||
% ls -l *counters-sancov
|
||||
... a.out.17110.counters-sancov
|
||||
% xxd *counters-sancov
|
||||
0000000: 0001 0100 01
|
||||
|
||||
These counters may also be used for in-process coverage-guided fuzzers. See
|
||||
``include/sanitizer/coverage_interface.h``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// The coverage instrumentation may optionally provide imprecise counters.
|
||||
// Rather than exposing the counter values to the user we instead map
|
||||
// the counters to a bitset.
|
||||
// Every counter is associated with 8 bits in the bitset.
|
||||
// We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+
|
||||
// The i-th bit is set to 1 if the counter value is in the i-th range.
|
||||
// This counter-based coverage implementation is *not* thread-safe.
|
||||
|
||||
// Returns the number of registered coverage counters.
|
||||
uintptr_t __sanitizer_get_number_of_counters();
|
||||
// Updates the counter 'bitset', clears the counters and returns the number of
|
||||
// new bits in 'bitset'.
|
||||
// If 'bitset' is nullptr, only clears the counters.
|
||||
// Otherwise 'bitset' should be at least
|
||||
// __sanitizer_get_number_of_counters bytes long and 8-aligned.
|
||||
uintptr_t
|
||||
__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
|
||||
|
||||
Output directory
|
||||
================
|
||||
|
||||
By default, .sancov files are created in the current working directory.
|
||||
This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% ASAN_OPTIONS="coverage=1:coverage_dir=/tmp/cov" ./a.out foo
|
||||
% ls -l /tmp/cov/*sancov
|
||||
-rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
|
||||
-rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
|
||||
|
||||
Sudden death
|
||||
============
|
||||
|
||||
Normally, coverage data is collected in memory and saved to disk when the
|
||||
program exits (with an ``atexit()`` handler), when a SIGSEGV is caught, or when
|
||||
``__sanitizer_cov_dump()`` is called.
|
||||
|
||||
If the program ends with a signal that ASan does not handle (or can not handle
|
||||
at all, like SIGKILL), coverage data will be lost. This is a big problem on
|
||||
Android, where SIGKILL is a normal way of evicting applications from memory.
|
||||
|
||||
With ``ASAN_OPTIONS=coverage=1:coverage_direct=1`` coverage data is written to a
|
||||
memory-mapped file as soon as it collected.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% ASAN_OPTIONS="coverage=1:coverage_direct=1" ./a.out
|
||||
main
|
||||
% ls
|
||||
7036.sancov.map 7036.sancov.raw a.out
|
||||
% sancov.py rawunpack 7036.sancov.raw
|
||||
sancov.py: reading map 7036.sancov.map
|
||||
sancov.py: unpacking 7036.sancov.raw
|
||||
writing 1 PCs to a.out.7036.sancov
|
||||
% sancov.py print a.out.7036.sancov
|
||||
sancov.py: read 1 PCs from a.out.7036.sancov
|
||||
sancov.py: 1 files merged; 1 PCs total
|
||||
0x4b2bae
|
||||
|
||||
Note that on 64-bit platforms, this method writes 2x more data than the default,
|
||||
because it stores full PC values instead of 32-bit offsets.
|
||||
|
||||
In-process fuzzing
|
||||
==================
|
||||
|
||||
Coverage data could be useful for fuzzers and sometimes it is preferable to run
|
||||
a fuzzer in the same process as the code being fuzzed (in-process fuzzer).
|
||||
|
||||
You can use ``__sanitizer_get_total_unique_coverage()`` from
|
||||
``<sanitizer/coverage_interface.h>`` which returns the number of currently
|
||||
covered entities in the program. This will tell the fuzzer if the coverage has
|
||||
increased after testing every new input.
|
||||
|
||||
If a fuzzer finds a bug in the ASan run, you will need to save the reproducer
|
||||
before exiting the process. Use ``__asan_set_death_callback`` from
|
||||
``<sanitizer/asan_interface.h>`` to do that.
|
||||
|
||||
An example of such fuzzer can be found in `the LLVM tree
|
||||
<http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/README.txt?view=markup>`_.
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
This coverage implementation is **fast**. With function-level coverage
|
||||
(``-fsanitize-coverage=func``) the overhead is not measurable. With
|
||||
basic-block-level coverage (``-fsanitize-coverage=bb``) the overhead varies
|
||||
between 0 and 25%.
|
||||
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
benchmark cov0 cov1 diff 0-1 cov2 diff 0-2 diff 1-2
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
400.perlbench 1296.00 1307.00 1.01 1465.00 1.13 1.12
|
||||
401.bzip2 858.00 854.00 1.00 1010.00 1.18 1.18
|
||||
403.gcc 613.00 617.00 1.01 683.00 1.11 1.11
|
||||
429.mcf 605.00 582.00 0.96 610.00 1.01 1.05
|
||||
445.gobmk 896.00 880.00 0.98 1050.00 1.17 1.19
|
||||
456.hmmer 892.00 892.00 1.00 918.00 1.03 1.03
|
||||
458.sjeng 995.00 1009.00 1.01 1217.00 1.22 1.21
|
||||
462.libquantum 497.00 492.00 0.99 534.00 1.07 1.09
|
||||
464.h264ref 1461.00 1467.00 1.00 1543.00 1.06 1.05
|
||||
471.omnetpp 575.00 590.00 1.03 660.00 1.15 1.12
|
||||
473.astar 658.00 652.00 0.99 715.00 1.09 1.10
|
||||
483.xalancbmk 471.00 491.00 1.04 582.00 1.24 1.19
|
||||
433.milc 616.00 627.00 1.02 627.00 1.02 1.00
|
||||
444.namd 602.00 601.00 1.00 654.00 1.09 1.09
|
||||
447.dealII 630.00 634.00 1.01 653.00 1.04 1.03
|
||||
450.soplex 365.00 368.00 1.01 395.00 1.08 1.07
|
||||
453.povray 427.00 434.00 1.02 495.00 1.16 1.14
|
||||
470.lbm 357.00 375.00 1.05 370.00 1.04 0.99
|
||||
482.sphinx3 927.00 928.00 1.00 1000.00 1.08 1.08
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
|
||||
Why another coverage?
|
||||
=====================
|
||||
|
||||
Why did we implement yet another code coverage?
|
||||
* We needed something that is lightning fast, plays well with
|
||||
AddressSanitizer, and does not significantly increase the binary size.
|
||||
* Traditional coverage implementations based in global counters
|
||||
`suffer from contention on counters
|
||||
<https://groups.google.com/forum/#!topic/llvm-dev/cDqYgnxNEhY>`_.
|
@ -857,6 +857,9 @@ implementation.
|
||||
|
||||
// Assert that is mutex is currently held for read operations.
|
||||
void AssertReaderHeld() ASSERT_SHARED_CAPABILITY(this);
|
||||
|
||||
// For negative capabilities.
|
||||
const Mutex& operator!() const { return *this; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -12,8 +12,7 @@ ThreadSanitizer is about **5x-10x**.
|
||||
How to build
|
||||
------------
|
||||
|
||||
Follow the `Clang build instructions <../get_started.html>`_. CMake build is
|
||||
supported.
|
||||
Build LLVM/Clang with `CMake <http://llvm.org/docs/CMake.html>`_.
|
||||
|
||||
Supported Platforms
|
||||
-------------------
|
||||
|
@ -589,6 +589,25 @@ Current limitations
|
||||
translated from debug annotations. That translation can be lossy,
|
||||
which results in some remarks having no location information.
|
||||
|
||||
Other Options
|
||||
-------------
|
||||
Clang options that that don't fit neatly into other categories.
|
||||
|
||||
.. option:: -MV
|
||||
|
||||
When emitting a dependency file, use formatting conventions appropriate
|
||||
for NMake or Jom. Ignored unless another option causes Clang to emit a
|
||||
dependency file.
|
||||
|
||||
When Clang emits a dependency file (e.g., you supplied the -M option)
|
||||
most filenames can be written to the file without any special formatting.
|
||||
Different Make tools will treat different sets of characters as "special"
|
||||
and use different conventions for telling the Make tool that the character
|
||||
is actually part of the filename. Normally Clang uses backslash to "escape"
|
||||
a special character, which is the convention used by GNU Make. The -MV
|
||||
option tells Clang to put double-quotes around the entire filename, which
|
||||
is the convention used by NMake and Jom.
|
||||
|
||||
|
||||
Language and Target-Independent Features
|
||||
========================================
|
||||
@ -637,7 +656,7 @@ Diagnostics <cl_diag_formatting>`.
|
||||
Diagnostic Mappings
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
All diagnostics are mapped into one of these 5 classes:
|
||||
All diagnostics are mapped into one of these 6 classes:
|
||||
|
||||
- Ignored
|
||||
- Note
|
||||
@ -911,6 +930,8 @@ number of cases where the compilation environment is tightly controlled
|
||||
and the precompiled header cannot be generated after headers have been
|
||||
installed.
|
||||
|
||||
.. _controlling-code-generation:
|
||||
|
||||
Controlling Code Generation
|
||||
---------------------------
|
||||
|
||||
@ -957,6 +978,8 @@ are listed below.
|
||||
``unsigned-integer-overflow`` and ``vptr``.
|
||||
- ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
|
||||
flow analysis.
|
||||
- ``-fsanitize=cfi``: :doc:`control flow integrity <ControlFlowIntegrity>`
|
||||
checks. Implies ``-flto``.
|
||||
|
||||
The following more fine-grained checks are also available:
|
||||
|
||||
@ -966,6 +989,16 @@ are listed below.
|
||||
``true`` nor ``false``.
|
||||
- ``-fsanitize=bounds``: Out of bounds array indexing, in cases
|
||||
where the array bound can be statically determined.
|
||||
- ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
|
||||
<cfi-strictness>`.
|
||||
- ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
|
||||
dynamic type. Implies ``-flto``.
|
||||
- ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
|
||||
unrelated type to the wrong dynamic type. Implies ``-flto``.
|
||||
- ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
|
||||
the wrong dynamic type. Implies ``-flto``.
|
||||
- ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
|
||||
wrong dynamic type. Implies ``-flto``.
|
||||
- ``-fsanitize=enum``: Load of a value of an enumerated type which
|
||||
is not in the range of representable values for that enumerated
|
||||
type.
|
||||
@ -994,7 +1027,9 @@ are listed below.
|
||||
greater or equal to the promoted bit-width of the left hand side
|
||||
or less than zero, or where the left hand side is negative. For a
|
||||
signed left shift, also checks for signed overflow in C, and for
|
||||
unsigned overflow in C++.
|
||||
unsigned overflow in C++. You can use ``-fsanitize=shift-base`` or
|
||||
``-fsanitize=shift-exponent`` to check only left-hand side or
|
||||
right-hand side of shift operation, respectively.
|
||||
- ``-fsanitize=signed-integer-overflow``: Signed integer overflow,
|
||||
including all the checks added by ``-ftrapv``, and checking for
|
||||
overflow in signed division (``INT_MIN / -1``).
|
||||
@ -1026,10 +1061,11 @@ are listed below.
|
||||
uninitialized bits came from. Slows down execution by additional
|
||||
1.5x-2x.
|
||||
|
||||
Possible values for level are 0 (off), 1 (default), 2. Level 2 adds more
|
||||
sections to MemorySanitizer reports describing the order of memory stores
|
||||
the uninitialized value went through. Beware, this mode may use a lot of
|
||||
extra memory.
|
||||
Possible values for level are 0 (off), 1, 2 (default). Level 2
|
||||
adds more sections to MemorySanitizer reports describing the
|
||||
order of memory stores the uninitialized value went
|
||||
through. This mode may use extra memory in programs that copy
|
||||
uninitialized memory a lot.
|
||||
|
||||
Extra features of UndefinedBehaviorSanitizer:
|
||||
|
||||
@ -1049,8 +1085,8 @@ are listed below.
|
||||
|
||||
It is not possible to combine more than one of the ``-fsanitize=address``,
|
||||
``-fsanitize=thread``, and ``-fsanitize=memory`` checkers in the same
|
||||
program. The ``-fsanitize=undefined`` checks can be combined with other
|
||||
sanitizers.
|
||||
program. The ``-fsanitize=undefined`` checks can only be combined with
|
||||
``-fsanitize=address``.
|
||||
|
||||
**-f[no-]sanitize-recover=check1,check2,...**
|
||||
|
||||
@ -1063,6 +1099,11 @@ are listed below.
|
||||
sanitizers (e.g. :doc:`AddressSanitizer`) may not support recovery,
|
||||
and always crash the program after the issue is detected.
|
||||
|
||||
**-f[no-]sanitize-coverage=[type,features,...]**
|
||||
|
||||
Enable simple code coverage in addition to certain sanitizers.
|
||||
See :doc:`SanitizerCoverage` for more details.
|
||||
|
||||
.. option:: -fno-assume-sane-operator-new
|
||||
|
||||
Don't assume that the C++'s new operator is sane.
|
||||
@ -1249,6 +1290,10 @@ If you are not using Linux Perf to collect profiles, you will need to
|
||||
write a conversion tool from your profiler to LLVM's format. This section
|
||||
explains the file format expected by the backend.
|
||||
|
||||
NOTE: This format is not intended to be used for code coverage. For that,
|
||||
you need to use Clang's instrumentation based profiling
|
||||
(``-fprofile-instr-generate``).
|
||||
|
||||
Sample profiles are written as ASCII text. The file is divided into sections,
|
||||
which correspond to each of the functions executed at runtime. Each
|
||||
section has the following format (taken from
|
||||
|
@ -48,9 +48,9 @@
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '3.6'
|
||||
version = '3.7'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '3.6'
|
||||
release = '3.7'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
2937
docs/doxygen.cfg.in
2937
docs/doxygen.cfg.in
File diff suppressed because it is too large
Load Diff
408
docs/doxygen.css
408
docs/doxygen.css
@ -1,408 +0,0 @@
|
||||
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
|
||||
font-family: Verdana,Geneva,Arial,Helvetica,sans-serif;
|
||||
}
|
||||
BODY,TD {
|
||||
font-size: 90%;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
CAPTION { font-weight: bold }
|
||||
DIV.qindex {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.nav {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.navtab {
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
TD.navtab {
|
||||
font-size: 70%;
|
||||
}
|
||||
A.qindex {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D;
|
||||
}
|
||||
A.qindex:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D
|
||||
}
|
||||
A.qindex:hover {
|
||||
text-decoration: none;
|
||||
background-color: #ddddff;
|
||||
}
|
||||
A.qindexHL {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
border: 1px double #9295C2;
|
||||
}
|
||||
A.qindexHL:hover {
|
||||
text-decoration: none;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
}
|
||||
A.qindexHL:visited {
|
||||
text-decoration: none; background-color: #6666cc; color: #ffffff }
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.codeRef:link { font-weight: normal; color: #0000FF}
|
||||
A.codeRef:visited { font-weight: normal; color: #0000FF}
|
||||
A:hover { text-decoration: none; background-color: #f2f2ff }
|
||||
DL.el { margin-left: -1cm }
|
||||
.fragment {
|
||||
font-family: Fixed, monospace;
|
||||
font-size: 95%;
|
||||
}
|
||||
PRE.fragment {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
|
||||
TD.md { background-color: #F4F4FB; font-weight: bold; }
|
||||
TD.mdPrefix {
|
||||
background-color: #F4F4FB;
|
||||
color: #606060;
|
||||
font-size: 80%;
|
||||
}
|
||||
TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
|
||||
TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
|
||||
DIV.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
|
||||
BODY {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
TD.indexkey {
|
||||
background-color: #eeeeff;
|
||||
font-weight: bold;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TD.indexvalue {
|
||||
background-color: #eeeeff;
|
||||
font-style: italic;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TR.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
P.formulaDsp { text-align: center; }
|
||||
IMG.formulaDsp { }
|
||||
IMG.formulaInl { vertical-align: middle; }
|
||||
SPAN.keyword { color: #008000 }
|
||||
SPAN.keywordtype { color: #604020 }
|
||||
SPAN.keywordflow { color: #e08000 }
|
||||
SPAN.comment { color: #800000 }
|
||||
SPAN.preprocessor { color: #806020 }
|
||||
SPAN.stringliteral { color: #002080 }
|
||||
SPAN.charliteral { color: #008080 }
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #F4F4FB;
|
||||
}
|
||||
.mdRow {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
.mdescLeft {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.mdescRight {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.memItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplParams {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
color: #606060;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.search { color: #003399;
|
||||
font-weight: bold;
|
||||
}
|
||||
FORM.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
INPUT.search { font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
TD.tiny { font-size: 75%;
|
||||
}
|
||||
a {
|
||||
color: #252E78;
|
||||
}
|
||||
a:visited {
|
||||
color: #3D2185;
|
||||
}
|
||||
.dirtab { padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #b0b0b0;
|
||||
}
|
||||
TH.dirtab { background: #eeeeff;
|
||||
font-weight: bold;
|
||||
}
|
||||
HR { height: 1px;
|
||||
border: none;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
/*
|
||||
* LLVM Modifications.
|
||||
* Note: Everything above here is generated with "doxygen -w htlm" command. See
|
||||
* "doxygen --help" for details. What follows are CSS overrides for LLVM
|
||||
* specific formatting. We want to keep the above so it can be replaced with
|
||||
* subsequent doxygen upgrades.
|
||||
*/
|
||||
|
||||
.footer {
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.title {
|
||||
font-size: 25pt;
|
||||
color: black; background: url("http://llvm.org/img/lines.gif");
|
||||
font-weight: bold;
|
||||
border-width: 1px;
|
||||
border-style: solid none solid none;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding-left: 8pt;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 2px
|
||||
}
|
||||
A:link {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:visited {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:active {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
font-style: italic;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
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;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<hr>
|
||||
<p class="footer">
|
||||
Generated on $datetime for r$LatestRev$ by <a href="http://www.doxygen.org">Doxygen
|
||||
$doxygenversion</a>.</p>
|
||||
|
||||
<p class="footer">
|
||||
See the <a href="http://clang.llvm.org">Main Clang Web Page</a> for more
|
||||
information.</p>
|
||||
</body>
|
||||
</html>
|
@ -1,9 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
|
||||
<meta name="keywords" content="clang,LLVM,Low Level Virtual Machine,C,C++,doxygen,API,frontend,documentation"/>
|
||||
<meta name="description" content="C++ source code API documentation for clang."/>
|
||||
<title>clang: $title</title>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
|
||||
</head><body>
|
||||
<p class="title">clang API Documentation</p>
|
@ -26,7 +26,9 @@ Using Clang as a Compiler
|
||||
MemorySanitizer
|
||||
DataFlowSanitizer
|
||||
LeakSanitizer
|
||||
SanitizerCoverage
|
||||
SanitizerSpecialCaseList
|
||||
ControlFlowIntegrity
|
||||
Modules
|
||||
MSVCCompatibility
|
||||
FAQ
|
||||
|
@ -163,7 +163,7 @@ def act_on_decl(declaration, comment, allowed_types):
|
||||
m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
|
||||
\s*([^\s,]+\s*),
|
||||
\s*(?:[^\s,]+\s*),
|
||||
\s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
|
||||
\s*AST_POLYMORPHIC_SUPPORTED_TYPES\(([^)]*)\)
|
||||
\)\s*;\s*$""", declaration, flags=re.X)
|
||||
if m:
|
||||
loc, name, n_results, results = m.groups()[0:4]
|
||||
@ -182,7 +182,7 @@ def act_on_decl(declaration, comment, allowed_types):
|
||||
|
||||
m = re.match(r"""^\s*AST_POLYMORPHIC_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
|
||||
\s*([^\s,]+)\s*,
|
||||
\s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
|
||||
\s*AST_POLYMORPHIC_SUPPORTED_TYPES\(([^)]*)\)
|
||||
(?:,\s*([^\s,]+)\s*
|
||||
,\s*([^\s,]+)\s*)?
|
||||
(?:,\s*([^\s,]+)\s*
|
||||
|
@ -15,15 +15,24 @@
|
||||
#include "clang/Frontend/FrontendPluginRegistry.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
class PrintFunctionsConsumer : public ASTConsumer {
|
||||
CompilerInstance &Instance;
|
||||
std::set<std::string> ParsedTemplates;
|
||||
|
||||
public:
|
||||
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
|
||||
PrintFunctionsConsumer(CompilerInstance &Instance,
|
||||
std::set<std::string> ParsedTemplates)
|
||||
: Instance(Instance), ParsedTemplates(ParsedTemplates) {}
|
||||
|
||||
bool HandleTopLevelDecl(DeclGroupRef DG) override {
|
||||
for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
|
||||
const Decl *D = *i;
|
||||
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
|
||||
@ -32,30 +41,72 @@ class PrintFunctionsConsumer : public ASTConsumer {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandleTranslationUnit(ASTContext& context) override {
|
||||
if (!Instance.getLangOpts().DelayedTemplateParsing)
|
||||
return;
|
||||
|
||||
// This demonstrates how to force instantiation of some templates in
|
||||
// -fdelayed-template-parsing mode. (Note: Doing this unconditionally for
|
||||
// all templates is similar to not using -fdelayed-template-parsig in the
|
||||
// first place.)
|
||||
// The advantage of doing this in HandleTranslationUnit() is that all
|
||||
// codegen (when using -add-plugin) is completely finished and this can't
|
||||
// affect the compiler output.
|
||||
struct Visitor : public RecursiveASTVisitor<Visitor> {
|
||||
const std::set<std::string> &ParsedTemplates;
|
||||
Visitor(const std::set<std::string> &ParsedTemplates)
|
||||
: ParsedTemplates(ParsedTemplates) {}
|
||||
bool VisitFunctionDecl(FunctionDecl *FD) {
|
||||
if (FD->isLateTemplateParsed() &&
|
||||
ParsedTemplates.count(FD->getNameAsString()))
|
||||
LateParsedDecls.insert(FD);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::set<FunctionDecl*> LateParsedDecls;
|
||||
} v(ParsedTemplates);
|
||||
v.TraverseDecl(context.getTranslationUnitDecl());
|
||||
clang::Sema &sema = Instance.getSema();
|
||||
for (const FunctionDecl *FD : v.LateParsedDecls) {
|
||||
clang::LateParsedTemplate* LPT = sema.LateParsedTemplateMap.lookup(FD);
|
||||
sema.LateTemplateParser(sema.OpaqueParser, *LPT);
|
||||
llvm::errs() << "late-parsed-decl: \"" << FD->getNameAsString() << "\"\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PrintFunctionNamesAction : public PluginASTAction {
|
||||
std::set<std::string> ParsedTemplates;
|
||||
protected:
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
llvm::StringRef) {
|
||||
return llvm::make_unique<PrintFunctionsConsumer>();
|
||||
llvm::StringRef) override {
|
||||
return llvm::make_unique<PrintFunctionsConsumer>(CI, ParsedTemplates);
|
||||
}
|
||||
|
||||
bool ParseArgs(const CompilerInstance &CI,
|
||||
const std::vector<std::string>& args) {
|
||||
const std::vector<std::string> &args) override {
|
||||
for (unsigned i = 0, e = args.size(); i != e; ++i) {
|
||||
llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";
|
||||
|
||||
// Example error handling.
|
||||
DiagnosticsEngine &D = CI.getDiagnostics();
|
||||
if (args[i] == "-an-error") {
|
||||
DiagnosticsEngine &D = CI.getDiagnostics();
|
||||
unsigned DiagID = D.getCustomDiagID(DiagnosticsEngine::Error,
|
||||
"invalid argument '%0'");
|
||||
D.Report(DiagID) << args[i];
|
||||
return false;
|
||||
} else if (args[i] == "-parse-template") {
|
||||
if (i + 1 >= e) {
|
||||
D.Report(D.getCustomDiagID(DiagnosticsEngine::Error,
|
||||
"missing -parse-template argument"));
|
||||
return false;
|
||||
}
|
||||
++i;
|
||||
ParsedTemplates.insert(args[i]);
|
||||
}
|
||||
}
|
||||
if (args.size() && args[0] == "help")
|
||||
if (!args.empty() && args[0] == "help")
|
||||
PrintHelp(llvm::errs());
|
||||
|
||||
return true;
|
||||
|
@ -32,7 +32,7 @@
|
||||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||
*/
|
||||
#define CINDEX_VERSION_MAJOR 0
|
||||
#define CINDEX_VERSION_MINOR 29
|
||||
#define CINDEX_VERSION_MINOR 30
|
||||
|
||||
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
||||
((major) * 10000) \
|
||||
@ -2276,7 +2276,12 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_ModuleImportDecl = 600,
|
||||
CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
|
||||
CXCursor_LastExtraDecl = CXCursor_ModuleImportDecl
|
||||
CXCursor_LastExtraDecl = CXCursor_ModuleImportDecl,
|
||||
|
||||
/**
|
||||
* \brief A code completion overload candidate.
|
||||
*/
|
||||
CXCursor_OverloadCandidate = 700
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2849,7 +2854,7 @@ enum CXCallingConv {
|
||||
CXCallingConv_X86Pascal = 5,
|
||||
CXCallingConv_AAPCS = 6,
|
||||
CXCallingConv_AAPCS_VFP = 7,
|
||||
CXCallingConv_PnaclCall = 8,
|
||||
/* Value 8 was PnaclCall, but it was never used, so it could safely be re-used. */
|
||||
CXCallingConv_IntelOclBicc = 9,
|
||||
CXCallingConv_X86_64Win64 = 10,
|
||||
CXCallingConv_X86_64SysV = 11,
|
||||
@ -3276,6 +3281,28 @@ CINDEX_LINKAGE long long clang_Type_getSizeOf(CXType T);
|
||||
*/
|
||||
CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S);
|
||||
|
||||
/**
|
||||
* \brief Return the offset of the field represented by the Cursor.
|
||||
*
|
||||
* If the cursor is not a field declaration, -1 is returned.
|
||||
* If the cursor semantic parent is not a record field declaration,
|
||||
* CXTypeLayoutError_Invalid is returned.
|
||||
* If the field's type declaration is an incomplete type,
|
||||
* CXTypeLayoutError_Incomplete is returned.
|
||||
* If the field's type declaration is a dependent type,
|
||||
* CXTypeLayoutError_Dependent is returned.
|
||||
* If the field's name S is not found,
|
||||
* CXTypeLayoutError_InvalidFieldName is returned.
|
||||
*/
|
||||
CINDEX_LINKAGE long long clang_Cursor_getOffsetOfField(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Determine whether the given cursor represents an anonymous record
|
||||
* declaration.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Cursor_isAnonymous(CXCursor C);
|
||||
|
||||
|
||||
enum CXRefQualifierKind {
|
||||
/** \brief No ref-qualifier was provided. */
|
||||
CXRefQualifier_None = 0,
|
||||
@ -5663,6 +5690,44 @@ CINDEX_LINKAGE void clang_indexLoc_getFileLocation(CXIdxLoc loc,
|
||||
CINDEX_LINKAGE
|
||||
CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc);
|
||||
|
||||
/**
|
||||
* \brief Visitor invoked for each field found by a traversal.
|
||||
*
|
||||
* This visitor function will be invoked for each field found by
|
||||
* \c clang_Type_visitFields. Its first argument is the cursor being
|
||||
* visited, its second argument is the client data provided to
|
||||
* \c clang_Type_visitFields.
|
||||
*
|
||||
* The visitor should return one of the \c CXVisitorResult values
|
||||
* to direct \c clang_Type_visitFields.
|
||||
*/
|
||||
typedef enum CXVisitorResult (*CXFieldVisitor)(CXCursor C,
|
||||
CXClientData client_data);
|
||||
|
||||
/**
|
||||
* \brief Visit the fields of a particular type.
|
||||
*
|
||||
* This function visits all the direct fields of the given cursor,
|
||||
* invoking the given \p visitor function with the cursors of each
|
||||
* visited field. The traversal may be ended prematurely, if
|
||||
* the visitor returns \c CXFieldVisit_Break.
|
||||
*
|
||||
* \param T the record type whose field may be visited.
|
||||
*
|
||||
* \param visitor the visitor function that will be invoked for each
|
||||
* field of \p T.
|
||||
*
|
||||
* \param client_data pointer data supplied by the client, which will
|
||||
* be passed to the visitor each time it is invoked.
|
||||
*
|
||||
* \returns a non-zero value if the traversal was terminated
|
||||
* prematurely by the visitor returning \c CXFieldVisit_Break.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T,
|
||||
CXFieldVisitor visitor,
|
||||
CXClientData client_data);
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -5671,9 +5736,6 @@ CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc);
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Include the comment API for compatibility. This will eventually go away. */
|
||||
#include "clang-c/Documentation.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -129,11 +129,7 @@ class ASTConsumer {
|
||||
/// required.
|
||||
///
|
||||
/// \param RD The class whose vtable was used.
|
||||
///
|
||||
/// \param DefinitionRequired Whether a definition of this vtable is
|
||||
/// required in this translation unit; otherwise, it is only needed if
|
||||
/// it was actually used.
|
||||
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
|
||||
virtual void HandleVTable(CXXRecordDecl *RD) {}
|
||||
|
||||
/// \brief If the consumer is interested in entities getting modified after
|
||||
/// their initial creation, it should return a pointer to
|
||||
|
@ -284,6 +284,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// merged into.
|
||||
llvm::DenseMap<Decl*, Decl*> MergedDecls;
|
||||
|
||||
/// \brief A mapping from a defining declaration to a list of modules (other
|
||||
/// than the owning module of the declaration) that contain merged
|
||||
/// definitions of that entity.
|
||||
llvm::DenseMap<NamedDecl*, llvm::TinyPtrVector<Module*>> MergedDefModules;
|
||||
|
||||
public:
|
||||
/// \brief A type synonym for the TemplateOrInstantiation mapping.
|
||||
typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *>
|
||||
@ -383,6 +388,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
ImportDecl *LastLocalImport;
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
mutable ExternCContextDecl *ExternCContext;
|
||||
|
||||
/// \brief The associated SourceManager object.a
|
||||
SourceManager &SourceMgr;
|
||||
@ -780,8 +786,26 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
MergedDecls[D] = Primary;
|
||||
}
|
||||
|
||||
/// \brief Note that the definition \p ND has been merged into module \p M,
|
||||
/// and should be visible whenever \p M is visible.
|
||||
void mergeDefinitionIntoModule(NamedDecl *ND, Module *M,
|
||||
bool NotifyListeners = true);
|
||||
/// \brief Clean up the merged definition list. Call this if you might have
|
||||
/// added duplicates into the list.
|
||||
void deduplicateMergedDefinitonsFor(NamedDecl *ND);
|
||||
|
||||
/// \brief Get the additional modules in which the definition \p Def has
|
||||
/// been merged.
|
||||
ArrayRef<Module*> getModulesWithMergedDefinition(NamedDecl *Def) {
|
||||
auto MergedIt = MergedDefModules.find(Def);
|
||||
if (MergedIt == MergedDefModules.end())
|
||||
return None;
|
||||
return MergedIt->second;
|
||||
}
|
||||
|
||||
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
|
||||
|
||||
ExternCContextDecl *getExternCContextDecl() const;
|
||||
|
||||
// Builtin Types.
|
||||
CanQualType VoidTy;
|
||||
@ -1689,6 +1713,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// beneficial for performance to overalign a data type.
|
||||
unsigned getPreferredTypeAlign(const Type *T) const;
|
||||
|
||||
/// \brief Return the default alignment for __attribute__((aligned)) on
|
||||
/// this target, to be used if no alignment value is specified.
|
||||
unsigned getTargetDefaultAlignForAttributeAligned(void) const;
|
||||
|
||||
/// \brief Return the alignment in bits that should be given to a
|
||||
/// global variable with type \p T.
|
||||
unsigned getAlignOfGlobalVar(QualType T) const;
|
||||
@ -1936,6 +1964,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// cv-qualifiers.
|
||||
QualType getSignatureParameterType(QualType T) const;
|
||||
|
||||
QualType getExceptionObjectType(QualType T) const;
|
||||
|
||||
/// \brief Return the properly qualified result of decaying the specified
|
||||
/// array type to a pointer.
|
||||
///
|
||||
@ -2191,6 +2221,18 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// it is not used.
|
||||
bool DeclMustBeEmitted(const Decl *D);
|
||||
|
||||
const CXXConstructorDecl *
|
||||
getCopyConstructorForExceptionObject(CXXRecordDecl *RD);
|
||||
|
||||
void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
|
||||
CXXConstructorDecl *CD);
|
||||
|
||||
void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx, Expr *DAE);
|
||||
|
||||
Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx);
|
||||
|
||||
void setManglingNumber(const NamedDecl *ND, unsigned Number);
|
||||
unsigned getManglingNumber(const NamedDecl *ND) const;
|
||||
|
||||
@ -2263,8 +2305,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
static unsigned NumImplicitDestructorsDeclared;
|
||||
|
||||
private:
|
||||
ASTContext(const ASTContext &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ASTContext &) LLVM_DELETED_FUNCTION;
|
||||
ASTContext(const ASTContext &) = delete;
|
||||
void operator=(const ASTContext &) = delete;
|
||||
|
||||
public:
|
||||
/// \brief Initialize built-in types.
|
||||
|
@ -121,6 +121,11 @@ namespace clang {
|
||||
/// if an error occurred.
|
||||
Decl *Import(Decl *FromD);
|
||||
|
||||
/// \brief Return the copy of the given declaration in the "to" context if
|
||||
/// it has already been imported from the "from" context. Otherwise return
|
||||
/// NULL.
|
||||
Decl *GetAlreadyImportedOrNull(Decl *FromD);
|
||||
|
||||
/// \brief Import the given declaration context from the "from"
|
||||
/// AST context into the "to" AST context.
|
||||
///
|
||||
|
@ -13,16 +13,17 @@
|
||||
#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
|
||||
namespace clang {
|
||||
class CXXRecordDecl;
|
||||
class ClassTemplateDecl;
|
||||
class ClassTemplateSpecializationDecl;
|
||||
class CXXDestructorDecl;
|
||||
class CXXRecordDecl;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class FunctionDecl;
|
||||
class FunctionTemplateDecl;
|
||||
class Module;
|
||||
class NamedDecl;
|
||||
class ObjCCategoryDecl;
|
||||
class ObjCContainerDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
@ -72,6 +73,10 @@ class ASTMutationListener {
|
||||
/// \brief A function's return type has been deduced.
|
||||
virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
|
||||
|
||||
/// \brief A virtual destructor's operator delete has been resolved.
|
||||
virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
|
||||
const FunctionDecl *Delete) {}
|
||||
|
||||
/// \brief An implicit member got a definition.
|
||||
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
|
||||
|
||||
@ -108,6 +113,13 @@ class ASTMutationListener {
|
||||
/// \param D the declaration marked OpenMP threadprivate.
|
||||
virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {}
|
||||
|
||||
/// \brief A definition has been made visible by being redefined locally.
|
||||
///
|
||||
/// \param D The definition that was previously not visible.
|
||||
/// \param M The containing module in which the definition was made visible,
|
||||
/// if any.
|
||||
virtual void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {}
|
||||
|
||||
// NOTE: If new methods are added they should also be added to
|
||||
// MultiplexASTMutationListener.
|
||||
};
|
||||
|
@ -76,7 +76,7 @@ class ASTUnresolvedSet {
|
||||
}
|
||||
|
||||
void append(ASTContext &C, iterator I, iterator E) {
|
||||
Decls.append(C, I.ir, E.ir);
|
||||
Decls.append(C, I.I, E.I);
|
||||
}
|
||||
|
||||
DeclAccessPair &operator[](unsigned I) { return Decls[I]; }
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/Sanitizers.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
@ -52,8 +53,8 @@ class Attr {
|
||||
bool Inherited : 1;
|
||||
bool IsPackExpansion : 1;
|
||||
bool Implicit : 1;
|
||||
|
||||
virtual ~Attr();
|
||||
bool IsLateParsed : 1;
|
||||
bool DuplicatesAllowed : 1;
|
||||
|
||||
void* operator new(size_t bytes) throw() {
|
||||
llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
|
||||
@ -65,7 +66,7 @@ class Attr {
|
||||
public:
|
||||
// Forward so that the regular new and delete do not hide global ones.
|
||||
void* operator new(size_t Bytes, ASTContext &C,
|
||||
size_t Alignment = 16) throw() {
|
||||
size_t Alignment = 8) throw() {
|
||||
return ::operator new(Bytes, C, Alignment);
|
||||
}
|
||||
void operator delete(void *Ptr, ASTContext &C,
|
||||
@ -74,9 +75,11 @@ class Attr {
|
||||
}
|
||||
|
||||
protected:
|
||||
Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
|
||||
Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
|
||||
bool IsLateParsed, bool DuplicatesAllowed)
|
||||
: Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex),
|
||||
Inherited(false), IsPackExpansion(false), Implicit(false) {}
|
||||
Inherited(false), IsPackExpansion(false), Implicit(false),
|
||||
IsLateParsed(IsLateParsed), DuplicatesAllowed(DuplicatesAllowed) {}
|
||||
|
||||
public:
|
||||
|
||||
@ -85,7 +88,7 @@ class Attr {
|
||||
}
|
||||
|
||||
unsigned getSpellingListIndex() const { return SpellingListIndex; }
|
||||
virtual const char *getSpelling() const = 0;
|
||||
const char *getSpelling() const;
|
||||
|
||||
SourceLocation getLocation() const { return Range.getBegin(); }
|
||||
SourceRange getRange() const { return Range; }
|
||||
@ -102,25 +105,24 @@ class Attr {
|
||||
bool isPackExpansion() const { return IsPackExpansion; }
|
||||
|
||||
// Clone this attribute.
|
||||
virtual Attr *clone(ASTContext &C) const = 0;
|
||||
Attr *clone(ASTContext &C) const;
|
||||
|
||||
virtual bool isLateParsed() const { return false; }
|
||||
bool isLateParsed() const { return IsLateParsed; }
|
||||
|
||||
// Pretty print this attribute.
|
||||
virtual void printPretty(raw_ostream &OS,
|
||||
const PrintingPolicy &Policy) const = 0;
|
||||
void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
|
||||
|
||||
/// \brief By default, attributes cannot be duplicated when being merged;
|
||||
/// however, an attribute can override this. Returns true if the attribute
|
||||
/// can be duplicated when merging.
|
||||
virtual bool duplicatesAllowed() const { return false; }
|
||||
bool duplicatesAllowed() const { return DuplicatesAllowed; }
|
||||
};
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
|
||||
: Attr(AK, R, SpellingListIndex) {}
|
||||
InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
|
||||
bool IsLateParsed, bool DuplicatesAllowed)
|
||||
: Attr(AK, R, SpellingListIndex, IsLateParsed, DuplicatesAllowed) {}
|
||||
|
||||
public:
|
||||
void setInherited(bool I) { Inherited = I; }
|
||||
@ -132,11 +134,11 @@ class InheritableAttr : public Attr {
|
||||
};
|
||||
|
||||
class InheritableParamAttr : public InheritableAttr {
|
||||
void anchor() override;
|
||||
protected:
|
||||
InheritableParamAttr(attr::Kind AK, SourceRange R,
|
||||
unsigned SpellingListIndex = 0)
|
||||
: InheritableAttr(AK, R, SpellingListIndex) {}
|
||||
InheritableParamAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
|
||||
bool IsLateParsed, bool DuplicatesAllowed)
|
||||
: InheritableAttr(AK, R, SpellingListIndex, IsLateParsed,
|
||||
DuplicatesAllowed) {}
|
||||
|
||||
public:
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
@ -24,7 +24,7 @@ namespace clang {
|
||||
|
||||
// Defined in ASTContext.h
|
||||
void *operator new(size_t Bytes, const clang::ASTContext &C,
|
||||
size_t Alignment = 16);
|
||||
size_t Alignment = 8);
|
||||
// FIXME: Being forced to not have a default argument here due to redeclaration
|
||||
// rules on default arguments sucks
|
||||
void *operator new[](size_t Bytes, const clang::ASTContext &C,
|
||||
|
@ -333,12 +333,12 @@ class OverridingMethods {
|
||||
/// struct D : B, C { };
|
||||
/// \endcode
|
||||
///
|
||||
/// This data structure contaings a mapping from every virtual
|
||||
/// This data structure contains a mapping from every virtual
|
||||
/// function *that does not override an existing virtual function* and
|
||||
/// in every subobject where that virtual function occurs to the set
|
||||
/// of virtual functions that override it. Thus, the same virtual
|
||||
/// function \c A::f can actually occur in multiple subobjects of type
|
||||
/// \c A due to multiple inheritance, and may be overriden by
|
||||
/// \c A due to multiple inheritance, and may be overridden by
|
||||
/// different virtual functions in each, as in the following example:
|
||||
///
|
||||
/// \code
|
||||
@ -354,7 +354,7 @@ class OverridingMethods {
|
||||
/// \c A::f but in *different* subobjects of type A. This is
|
||||
/// represented by numbering the subobjects in which the overridden
|
||||
/// and the overriding virtual member functions are located. Subobject
|
||||
/// 0 represents the virtua base class subobject of that type, while
|
||||
/// 0 represents the virtual base class subobject of that type, while
|
||||
/// subobject numbers greater than 0 refer to non-virtual base class
|
||||
/// subobjects of that type.
|
||||
class CXXFinalOverriderMap
|
||||
|
@ -16,8 +16,8 @@
|
||||
#define LLVM_CLANG_AST_CANONICALTYPE_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include <iterator>
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -80,7 +80,7 @@ class CanQual {
|
||||
operator QualType() const { return Stored; }
|
||||
|
||||
/// \brief Implicit conversion to bool.
|
||||
LLVM_EXPLICIT operator bool() const { return !isNull(); }
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
bool isNull() const {
|
||||
return Stored.isNull();
|
||||
@ -381,93 +381,20 @@ namespace clang {
|
||||
|
||||
/// \brief Iterator adaptor that turns an iterator over canonical QualTypes
|
||||
/// into an iterator over CanQualTypes.
|
||||
template<typename InputIterator>
|
||||
class CanTypeIterator {
|
||||
InputIterator Iter;
|
||||
template <typename InputIterator>
|
||||
struct CanTypeIterator
|
||||
: llvm::iterator_adaptor_base<
|
||||
CanTypeIterator<InputIterator>, InputIterator,
|
||||
typename std::iterator_traits<InputIterator>::iterator_category,
|
||||
CanQualType,
|
||||
typename std::iterator_traits<InputIterator>::difference_type,
|
||||
CanProxy<Type>, CanQualType> {
|
||||
CanTypeIterator() {}
|
||||
explicit CanTypeIterator(InputIterator Iter)
|
||||
: CanTypeIterator::iterator_adaptor_base(std::move(Iter)) {}
|
||||
|
||||
public:
|
||||
typedef CanQualType value_type;
|
||||
typedef value_type reference;
|
||||
typedef CanProxy<Type> pointer;
|
||||
typedef typename std::iterator_traits<InputIterator>::difference_type
|
||||
difference_type;
|
||||
typedef typename std::iterator_traits<InputIterator>::iterator_category
|
||||
iterator_category;
|
||||
|
||||
CanTypeIterator() : Iter() { }
|
||||
explicit CanTypeIterator(InputIterator Iter) : Iter(Iter) { }
|
||||
|
||||
// Input iterator
|
||||
reference operator*() const {
|
||||
return CanQualType::CreateUnsafe(*Iter);
|
||||
}
|
||||
|
||||
pointer operator->() const;
|
||||
|
||||
CanTypeIterator &operator++() {
|
||||
++Iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CanTypeIterator operator++(int) {
|
||||
CanTypeIterator Tmp(*this);
|
||||
++Iter;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(const CanTypeIterator& X, const CanTypeIterator &Y) {
|
||||
return X.Iter == Y.Iter;
|
||||
}
|
||||
friend bool operator!=(const CanTypeIterator& X, const CanTypeIterator &Y) {
|
||||
return X.Iter != Y.Iter;
|
||||
}
|
||||
|
||||
// Bidirectional iterator
|
||||
CanTypeIterator &operator--() {
|
||||
--Iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CanTypeIterator operator--(int) {
|
||||
CanTypeIterator Tmp(*this);
|
||||
--Iter;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
// Random access iterator
|
||||
reference operator[](difference_type n) const {
|
||||
return CanQualType::CreateUnsafe(Iter[n]);
|
||||
}
|
||||
|
||||
CanTypeIterator &operator+=(difference_type n) {
|
||||
Iter += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CanTypeIterator &operator-=(difference_type n) {
|
||||
Iter -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CanTypeIterator operator+(CanTypeIterator X, difference_type n) {
|
||||
X += n;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend CanTypeIterator operator+(difference_type n, CanTypeIterator X) {
|
||||
X += n;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend CanTypeIterator operator-(CanTypeIterator X, difference_type n) {
|
||||
X -= n;
|
||||
return X;
|
||||
}
|
||||
|
||||
friend difference_type operator-(const CanTypeIterator &X,
|
||||
const CanTypeIterator &Y) {
|
||||
return X - Y;
|
||||
}
|
||||
CanQualType operator*() const { return CanQualType::CreateUnsafe(*this->I); }
|
||||
CanProxy<Type> operator->() const;
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -727,9 +654,8 @@ CanProxy<T> CanQual<T>::operator->() const {
|
||||
return CanProxy<T>(*this);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
typename CanTypeIterator<InputIterator>::pointer
|
||||
CanTypeIterator<InputIterator>::operator->() const {
|
||||
template <typename InputIterator>
|
||||
CanProxy<Type> CanTypeIterator<InputIterator>::operator->() const {
|
||||
return CanProxy<Type>(*this);
|
||||
}
|
||||
|
||||
|
@ -166,8 +166,8 @@ class CommandTraits {
|
||||
static const CommandInfo *getBuiltinCommandInfo(unsigned CommandID);
|
||||
|
||||
private:
|
||||
CommandTraits(const CommandTraits &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const CommandTraits &) LLVM_DELETED_FUNCTION;
|
||||
CommandTraits(const CommandTraits &) = delete;
|
||||
void operator=(const CommandTraits &) = delete;
|
||||
|
||||
const CommandInfo *getRegisteredCommandInfo(StringRef Name) const;
|
||||
const CommandInfo *getRegisteredCommandInfo(unsigned CommandID) const;
|
||||
|
@ -221,8 +221,8 @@ class Token {
|
||||
/// \brief Comment lexer.
|
||||
class Lexer {
|
||||
private:
|
||||
Lexer(const Lexer &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Lexer &) LLVM_DELETED_FUNCTION;
|
||||
Lexer(const Lexer &) = delete;
|
||||
void operator=(const Lexer &) = delete;
|
||||
|
||||
/// Allocator for strings that are semantic values of tokens and have to be
|
||||
/// computed (for example, resolved decimal character references).
|
||||
|
@ -28,8 +28,8 @@ class CommandTraits;
|
||||
|
||||
/// Doxygen comment parser.
|
||||
class Parser {
|
||||
Parser(const Parser &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Parser &) LLVM_DELETED_FUNCTION;
|
||||
Parser(const Parser &) = delete;
|
||||
void operator=(const Parser &) = delete;
|
||||
|
||||
friend class TextTokenRetokenizer;
|
||||
|
||||
|
@ -31,8 +31,8 @@ namespace comments {
|
||||
class CommandTraits;
|
||||
|
||||
class Sema {
|
||||
Sema(const Sema &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Sema &) LLVM_DELETED_FUNCTION;
|
||||
Sema(const Sema &) = delete;
|
||||
void operator=(const Sema &) = delete;
|
||||
|
||||
/// Allocator for AST nodes.
|
||||
llvm::BumpPtrAllocator &Allocator;
|
||||
|
@ -791,7 +791,7 @@ template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE,
|
||||
const LambdaCapture *C) {
|
||||
if (C->isInitCapture())
|
||||
if (LE->isInitCapture(C))
|
||||
TRY_TO(TraverseDecl(C->getCapturedVar()));
|
||||
return true;
|
||||
}
|
||||
@ -1284,6 +1284,8 @@ DEF_TRAVERSE_DECL(
|
||||
// D->getAnonymousNamespace().
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ExternCContextDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
|
||||
// We shouldn't traverse an aliased namespace, since it will be
|
||||
// defined (and, therefore, traversed) somewhere else.
|
||||
@ -2433,6 +2435,7 @@ template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getChunkSize()));
|
||||
TRY_TO(TraverseStmt(C->getHelperChunkSize()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2517,6 +2520,18 @@ template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
|
||||
OMPLastprivateClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->private_copies()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->source_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->destination_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->assignment_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2529,7 +2544,17 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getStep()));
|
||||
TRY_TO(TraverseStmt(C->getCalcStep()));
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->inits()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->updates()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->finals()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2543,6 +2568,15 @@ bool RecursiveASTVisitor<Derived>::VisitOMPAlignedClause(OMPAlignedClause *C) {
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->source_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->destination_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->assignment_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2550,6 +2584,15 @@ template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
|
||||
OMPCopyprivateClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->source_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->destination_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->assignment_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2559,6 +2602,15 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->lhs_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->rhs_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->reduction_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ class LabelStmt;
|
||||
class MemberSpecializationInfo;
|
||||
class Module;
|
||||
class NestedNameSpecifier;
|
||||
class ParmVarDecl;
|
||||
class Stmt;
|
||||
class StringLiteral;
|
||||
class TemplateArgumentList;
|
||||
@ -82,10 +83,7 @@ class TranslationUnitDecl : public Decl, public DeclContext {
|
||||
/// translation unit, if one has been created.
|
||||
NamespaceDecl *AnonymousNamespace;
|
||||
|
||||
explicit TranslationUnitDecl(ASTContext &ctx)
|
||||
: Decl(TranslationUnit, nullptr, SourceLocation()),
|
||||
DeclContext(TranslationUnit),
|
||||
Ctx(ctx), AnonymousNamespace(nullptr) {}
|
||||
explicit TranslationUnitDecl(ASTContext &ctx);
|
||||
public:
|
||||
ASTContext &getASTContext() const { return Ctx; }
|
||||
|
||||
@ -104,6 +102,43 @@ class TranslationUnitDecl : public Decl, public DeclContext {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Declaration context for names declared as extern "C" in C++. This
|
||||
/// is neither the semantic nor lexical context for such declarations, but is
|
||||
/// used to check for conflicts with other extern "C" declarations. Example:
|
||||
///
|
||||
/// \code
|
||||
/// namespace N { extern "C" void f(); } // #1
|
||||
/// void N::f() {} // #2
|
||||
/// namespace M { extern "C" void f(); } // #3
|
||||
/// \endcode
|
||||
///
|
||||
/// The semantic context of #1 is namespace N and its lexical context is the
|
||||
/// LinkageSpecDecl; the semantic context of #2 is namespace N and its lexical
|
||||
/// context is the TU. However, both declarations are also visible in the
|
||||
/// extern "C" context.
|
||||
///
|
||||
/// The declaration at #3 finds it is a redeclaration of \c N::f through
|
||||
/// lookup in the extern "C" context.
|
||||
class ExternCContextDecl : public Decl, public DeclContext {
|
||||
virtual void anchor();
|
||||
|
||||
explicit ExternCContextDecl(TranslationUnitDecl *TU)
|
||||
: Decl(ExternCContext, TU, SourceLocation()),
|
||||
DeclContext(ExternCContext) {}
|
||||
public:
|
||||
static ExternCContextDecl *Create(const ASTContext &C,
|
||||
TranslationUnitDecl *TU);
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ExternCContext; }
|
||||
static DeclContext *castToDeclContext(const ExternCContextDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<ExternCContextDecl*>(D));
|
||||
}
|
||||
static ExternCContextDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<ExternCContextDecl *>(const_cast<DeclContext*>(DC));
|
||||
}
|
||||
};
|
||||
|
||||
/// NamedDecl - This represents a decl with a name. Many decls have names such
|
||||
/// as ObjCMethodDecl, but not \@class, etc.
|
||||
class NamedDecl : public Decl {
|
||||
@ -179,14 +214,17 @@ class NamedDecl : public Decl {
|
||||
const PrintingPolicy &Policy,
|
||||
bool Qualified) const;
|
||||
|
||||
/// declarationReplaces - Determine whether this declaration, if
|
||||
/// \brief Determine whether this declaration, if
|
||||
/// known to be well-formed within its context, will replace the
|
||||
/// declaration OldD if introduced into scope. A declaration will
|
||||
/// replace another declaration if, for example, it is a
|
||||
/// redeclaration of the same variable or function, but not if it is
|
||||
/// a declaration of a different kind (function vs. class) or an
|
||||
/// overloaded function.
|
||||
bool declarationReplaces(NamedDecl *OldD) const;
|
||||
///
|
||||
/// \param IsKnownNewer \c true if this declaration is known to be newer
|
||||
/// than \p OldD (for instance, if this declaration is newly-created).
|
||||
bool declarationReplaces(NamedDecl *OldD, bool IsKnownNewer = true) const;
|
||||
|
||||
/// \brief Determine whether this declaration has linkage.
|
||||
bool hasLinkage() const;
|
||||
@ -535,8 +573,8 @@ struct QualifierInfo {
|
||||
|
||||
private:
|
||||
// Copy constructor and copy assignment are disabled.
|
||||
QualifierInfo(const QualifierInfo&) LLVM_DELETED_FUNCTION;
|
||||
QualifierInfo& operator=(const QualifierInfo&) LLVM_DELETED_FUNCTION;
|
||||
QualifierInfo(const QualifierInfo&) = delete;
|
||||
QualifierInfo& operator=(const QualifierInfo&) = delete;
|
||||
};
|
||||
|
||||
/// \brief Represents a ValueDecl that came out of a declarator.
|
||||
@ -710,37 +748,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
unsigned SClass : 3;
|
||||
unsigned TSCSpec : 2;
|
||||
unsigned InitStyle : 2;
|
||||
|
||||
/// \brief Whether this variable is the exception variable in a C++ catch
|
||||
/// or an Objective-C @catch statement.
|
||||
unsigned ExceptionVar : 1;
|
||||
|
||||
/// \brief Whether this local variable could be allocated in the return
|
||||
/// slot of its function, enabling the named return value optimization
|
||||
/// (NRVO).
|
||||
unsigned NRVOVariable : 1;
|
||||
|
||||
/// \brief Whether this variable is the for-range-declaration in a C++0x
|
||||
/// for-range statement.
|
||||
unsigned CXXForRangeDecl : 1;
|
||||
|
||||
/// \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;
|
||||
|
||||
/// \brief Whether this variable is the implicit variable for a lambda
|
||||
/// init-capture.
|
||||
unsigned IsInitCapture : 1;
|
||||
|
||||
/// \brief Whether this local extern variable's previous declaration was
|
||||
/// declared in the same block scope. This controls whether we should merge
|
||||
/// the type of this declaration with its previous declaration.
|
||||
unsigned PreviousDeclInSameBlockScope : 1;
|
||||
};
|
||||
enum { NumVarDeclBits = 14 };
|
||||
enum { NumVarDeclBits = 7 };
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class StmtIteratorBase;
|
||||
@ -776,10 +785,47 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
unsigned ParameterIndex : NumParameterIndexBits;
|
||||
};
|
||||
|
||||
class NonParmVarDeclBitfields {
|
||||
friend class VarDecl;
|
||||
friend class ASTDeclReader;
|
||||
|
||||
unsigned : NumVarDeclBits;
|
||||
|
||||
/// \brief Whether this variable is the exception variable in a C++ catch
|
||||
/// or an Objective-C @catch statement.
|
||||
unsigned ExceptionVar : 1;
|
||||
|
||||
/// \brief Whether this local variable could be allocated in the return
|
||||
/// slot of its function, enabling the named return value optimization
|
||||
/// (NRVO).
|
||||
unsigned NRVOVariable : 1;
|
||||
|
||||
/// \brief Whether this variable is the for-range-declaration in a C++0x
|
||||
/// for-range statement.
|
||||
unsigned CXXForRangeDecl : 1;
|
||||
|
||||
/// \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;
|
||||
|
||||
/// \brief Whether this variable is the implicit variable for a lambda
|
||||
/// init-capture.
|
||||
unsigned IsInitCapture : 1;
|
||||
|
||||
/// \brief Whether this local extern variable's previous declaration was
|
||||
/// declared in the same block scope. This controls whether we should merge
|
||||
/// the type of this declaration with its previous declaration.
|
||||
unsigned PreviousDeclInSameBlockScope : 1;
|
||||
};
|
||||
|
||||
union {
|
||||
unsigned AllBits;
|
||||
VarDeclBitfields VarDeclBits;
|
||||
ParmVarDeclBitfields ParmVarDeclBits;
|
||||
NonParmVarDeclBitfields NonParmVarDeclBits;
|
||||
};
|
||||
|
||||
VarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
|
||||
@ -840,7 +886,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
|
||||
|
||||
// Global Named Register (GNU extension)
|
||||
if (getStorageClass() == SC_Register && !isLocalVarDecl())
|
||||
if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm())
|
||||
return false;
|
||||
|
||||
// Return true for: Auto, Register.
|
||||
@ -1132,9 +1178,12 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// \brief Determine whether this variable is the exception variable in a
|
||||
/// C++ catch statememt or an Objective-C \@catch statement.
|
||||
bool isExceptionVariable() const {
|
||||
return VarDeclBits.ExceptionVar;
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.ExceptionVar;
|
||||
}
|
||||
void setExceptionVariable(bool EV) {
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.ExceptionVar = EV;
|
||||
}
|
||||
void setExceptionVariable(bool EV) { VarDeclBits.ExceptionVar = EV; }
|
||||
|
||||
/// \brief Determine whether this local variable can be used with the named
|
||||
/// return value optimization (NRVO).
|
||||
@ -1146,36 +1195,64 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
/// return slot when returning from the function. Within the function body,
|
||||
/// each return that returns the NRVO object will have this variable as its
|
||||
/// NRVO candidate.
|
||||
bool isNRVOVariable() const { return VarDeclBits.NRVOVariable; }
|
||||
void setNRVOVariable(bool NRVO) { VarDeclBits.NRVOVariable = NRVO; }
|
||||
bool isNRVOVariable() const {
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.NRVOVariable;
|
||||
}
|
||||
void setNRVOVariable(bool NRVO) {
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.NRVOVariable = NRVO;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this variable is the for-range-declaration in
|
||||
/// a C++0x for-range statement.
|
||||
bool isCXXForRangeDecl() const { return VarDeclBits.CXXForRangeDecl; }
|
||||
void setCXXForRangeDecl(bool FRD) { VarDeclBits.CXXForRangeDecl = FRD; }
|
||||
bool isCXXForRangeDecl() const {
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.CXXForRangeDecl;
|
||||
}
|
||||
void setCXXForRangeDecl(bool FRD) {
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.CXXForRangeDecl = FRD;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this variable is an ARC pseudo-__strong
|
||||
/// variable. A pseudo-__strong variable has a __strong-qualified
|
||||
/// type but does not actually retain the object written into it.
|
||||
/// Generally such variables are also 'const' for safety.
|
||||
bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; }
|
||||
void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; }
|
||||
bool isARCPseudoStrong() const {
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.ARCPseudoStrong;
|
||||
}
|
||||
void setARCPseudoStrong(bool ps) {
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.ARCPseudoStrong = ps;
|
||||
}
|
||||
|
||||
/// Whether this variable is (C++11) constexpr.
|
||||
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
|
||||
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
|
||||
bool isConstexpr() const {
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsConstexpr;
|
||||
}
|
||||
void setConstexpr(bool IC) {
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.IsConstexpr = IC;
|
||||
}
|
||||
|
||||
/// Whether this variable is the implicit variable for a lambda init-capture.
|
||||
bool isInitCapture() const { return VarDeclBits.IsInitCapture; }
|
||||
void setInitCapture(bool IC) { VarDeclBits.IsInitCapture = IC; }
|
||||
bool isInitCapture() const {
|
||||
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsInitCapture;
|
||||
}
|
||||
void setInitCapture(bool IC) {
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.IsInitCapture = IC;
|
||||
}
|
||||
|
||||
/// Whether this local extern variable declaration's previous declaration
|
||||
/// was declared in the same block scope. Only correct in C++.
|
||||
bool isPreviousDeclInSameBlockScope() const {
|
||||
return VarDeclBits.PreviousDeclInSameBlockScope;
|
||||
return isa<ParmVarDecl>(this)
|
||||
? false
|
||||
: NonParmVarDeclBits.PreviousDeclInSameBlockScope;
|
||||
}
|
||||
void setPreviousDeclInSameBlockScope(bool Same) {
|
||||
VarDeclBits.PreviousDeclInSameBlockScope = Same;
|
||||
assert(!isa<ParmVarDecl>(this));
|
||||
NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same;
|
||||
}
|
||||
|
||||
/// \brief If this variable is an instantiated static data member of a
|
||||
@ -1482,6 +1559,9 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool IsLateTemplateParsed : 1;
|
||||
bool IsConstexpr : 1;
|
||||
|
||||
/// \brief Indicates if the function uses __try.
|
||||
bool UsesSEHTry : 1;
|
||||
|
||||
/// \brief Indicates if the function was a definition but its body was
|
||||
/// skipped.
|
||||
unsigned HasSkippedBody : 1;
|
||||
@ -1570,8 +1650,8 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
|
||||
IsDefaulted(false), IsExplicitlyDefaulted(false),
|
||||
HasImplicitReturnZero(false), IsLateTemplateParsed(false),
|
||||
IsConstexpr(isConstexprSpecified), HasSkippedBody(false),
|
||||
EndRangeLoc(NameInfo.getEndLoc()),
|
||||
IsConstexpr(isConstexprSpecified), UsesSEHTry(false),
|
||||
HasSkippedBody(false), EndRangeLoc(NameInfo.getEndLoc()),
|
||||
TemplateOrSpecialization(),
|
||||
DNLoc(NameInfo.getInfo()) {}
|
||||
|
||||
@ -1751,6 +1831,10 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool isConstexpr() const { return IsConstexpr; }
|
||||
void setConstexpr(bool IC) { IsConstexpr = IC; }
|
||||
|
||||
/// Whether this is a (C++11) constexpr function or constexpr constructor.
|
||||
bool usesSEHTry() const { return UsesSEHTry; }
|
||||
void setUsesSEHTry(bool UST) { UsesSEHTry = UST; }
|
||||
|
||||
/// \brief Whether this function has been deleted.
|
||||
///
|
||||
/// A function that is "deleted" (via the C++0x "= delete" syntax)
|
||||
@ -1814,11 +1898,6 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
/// allocation function. [...]
|
||||
bool isReplaceableGlobalAllocationFunction() const;
|
||||
|
||||
/// \brief Determine whether this function is a sized global deallocation
|
||||
/// function in C++1y. If so, find and return the corresponding unsized
|
||||
/// deallocation function.
|
||||
FunctionDecl *getCorrespondingUnsizedGlobalDeallocationFunction() const;
|
||||
|
||||
/// Compute the language linkage.
|
||||
LanguageLinkage getLanguageLinkage() const;
|
||||
|
||||
@ -1847,8 +1926,10 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
|
||||
void setPreviousDeclaration(FunctionDecl * PrevDecl);
|
||||
|
||||
virtual const FunctionDecl *getCanonicalDecl() const;
|
||||
FunctionDecl *getCanonicalDecl() override;
|
||||
const FunctionDecl *getCanonicalDecl() const {
|
||||
return const_cast<FunctionDecl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
unsigned getBuiltinID() const;
|
||||
|
||||
@ -1923,6 +2004,13 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
|
||||
}
|
||||
|
||||
/// \brief Returns true if this function or its return type has the
|
||||
/// warn_unused_result attribute. If the return type has the attribute and
|
||||
/// this function is a method of the return type's class, then false will be
|
||||
/// returned to avoid spurious warnings on member methods such as assignment
|
||||
/// operators.
|
||||
bool hasUnusedResultAttr() const;
|
||||
|
||||
/// \brief Returns the storage class as written in the source. For the
|
||||
/// computed linkage of symbol, see getLinkage.
|
||||
StorageClass getStorageClass() const { return StorageClass(SClass); }
|
||||
@ -2537,6 +2625,13 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
||||
TypedefNameDecl *getCanonicalDecl() override { return getFirstDecl(); }
|
||||
const TypedefNameDecl *getCanonicalDecl() const { return getFirstDecl(); }
|
||||
|
||||
/// Retrieves the tag declaration for which this is the typedef name for
|
||||
/// linkage purposes, if any.
|
||||
///
|
||||
/// \param AnyRedecl Look for the tag declaration in any redeclaration of
|
||||
/// this typedef declaration.
|
||||
TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) {
|
||||
@ -3696,8 +3791,6 @@ void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) {
|
||||
assert(RedeclLink.NextIsLatest() &&
|
||||
"setPreviousDecl on a decl already in a redeclaration chain");
|
||||
|
||||
decl_type *First;
|
||||
|
||||
if (PrevDecl) {
|
||||
// Point to previous. Make sure that this is actually the most recent
|
||||
// redeclaration, or we can build invalid chains. If the most recent
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
@ -316,7 +317,7 @@ class Decl {
|
||||
: NextInContextAndBits(), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||
Access(AS_none), FromASTFile(0), Hidden(DC && cast<Decl>(DC)->Hidden),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0)
|
||||
{
|
||||
@ -638,13 +639,28 @@ class Decl {
|
||||
Module *getOwningModuleSlow() const;
|
||||
|
||||
public:
|
||||
Module *getOwningModule() const {
|
||||
/// \brief Get the imported owning module, if this decl is from an imported
|
||||
/// (non-local) module.
|
||||
Module *getImportedOwningModule() const {
|
||||
if (!isFromASTFile())
|
||||
return nullptr;
|
||||
|
||||
return getOwningModuleSlow();
|
||||
}
|
||||
|
||||
/// \brief Get the local owning module, if known. Returns nullptr if owner is
|
||||
/// not yet known or declaration is not from a module.
|
||||
Module *getLocalOwningModule() const {
|
||||
if (isFromASTFile() || !Hidden)
|
||||
return nullptr;
|
||||
return reinterpret_cast<Module *const *>(this)[-1];
|
||||
}
|
||||
void setLocalOwningModule(Module *M) {
|
||||
assert(!isFromASTFile() && Hidden &&
|
||||
"should not have a cached owning module");
|
||||
reinterpret_cast<Module **>(this)[-1] = M;
|
||||
}
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
@ -1005,9 +1021,62 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
|
||||
void print(raw_ostream &OS) const override;
|
||||
};
|
||||
|
||||
typedef MutableArrayRef<NamedDecl *> DeclContextLookupResult;
|
||||
/// \brief The results of name lookup within a DeclContext. This is either a
|
||||
/// single result (with no stable storage) or a collection of results (with
|
||||
/// stable storage provided by the lookup table).
|
||||
class DeclContextLookupResult {
|
||||
typedef ArrayRef<NamedDecl *> ResultTy;
|
||||
ResultTy Result;
|
||||
// If there is only one lookup result, it would be invalidated by
|
||||
// reallocations of the name table, so store it separately.
|
||||
NamedDecl *Single;
|
||||
|
||||
typedef ArrayRef<NamedDecl *> DeclContextLookupConstResult;
|
||||
static NamedDecl *const SingleElementDummyList;
|
||||
|
||||
public:
|
||||
DeclContextLookupResult() : Result(), Single() {}
|
||||
DeclContextLookupResult(ArrayRef<NamedDecl *> Result)
|
||||
: Result(Result), Single() {}
|
||||
DeclContextLookupResult(NamedDecl *Single)
|
||||
: Result(SingleElementDummyList), Single(Single) {}
|
||||
|
||||
class iterator;
|
||||
typedef llvm::iterator_adaptor_base<iterator, ResultTy::iterator,
|
||||
std::random_access_iterator_tag,
|
||||
NamedDecl *const> IteratorBase;
|
||||
class iterator : public IteratorBase {
|
||||
value_type SingleElement;
|
||||
|
||||
public:
|
||||
iterator() : IteratorBase(), SingleElement() {}
|
||||
explicit iterator(pointer Pos, value_type Single = nullptr)
|
||||
: IteratorBase(Pos), SingleElement(Single) {}
|
||||
|
||||
reference operator*() const {
|
||||
return SingleElement ? SingleElement : IteratorBase::operator*();
|
||||
}
|
||||
};
|
||||
typedef iterator const_iterator;
|
||||
typedef iterator::pointer pointer;
|
||||
typedef iterator::reference reference;
|
||||
|
||||
iterator begin() const { return iterator(Result.begin(), Single); }
|
||||
iterator end() const { return iterator(Result.end(), Single); }
|
||||
|
||||
bool empty() const { return Result.empty(); }
|
||||
pointer data() const { return Single ? &Single : Result.data(); }
|
||||
size_t size() const { return Single ? 1 : Result.size(); }
|
||||
reference front() const { return Single ? Single : Result.front(); }
|
||||
reference back() const { return Single ? Single : Result.back(); }
|
||||
reference operator[](size_t N) const { return Single ? Single : Result[N]; }
|
||||
|
||||
// FIXME: Remove this from the interface
|
||||
DeclContextLookupResult slice(size_t N) const {
|
||||
DeclContextLookupResult Sliced = Result.slice(N);
|
||||
Sliced.Single = Single;
|
||||
return Sliced;
|
||||
}
|
||||
};
|
||||
|
||||
/// DeclContext - This is used only as base class of specific decl types that
|
||||
/// can act as declaration contexts. These decls are (only the top classes
|
||||
@ -1042,14 +1111,21 @@ class DeclContext {
|
||||
/// another lookup.
|
||||
mutable bool NeedToReconcileExternalVisibleStorage : 1;
|
||||
|
||||
/// \brief If \c true, this context may have local lexical declarations
|
||||
/// that are missing from the lookup table.
|
||||
mutable bool HasLazyLocalLexicalLookups : 1;
|
||||
|
||||
/// \brief If \c true, the external source may have lexical declarations
|
||||
/// that are missing from the lookup table.
|
||||
mutable bool HasLazyExternalLexicalLookups : 1;
|
||||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context (or a DependentStoredDeclsMap if this is a
|
||||
/// dependent context), and a bool indicating whether we have lazily
|
||||
/// omitted any declarations from the map. We maintain the invariant
|
||||
/// that, if the map contains an entry for a DeclarationName (and we
|
||||
/// haven't lazily omitted anything), then it contains all relevant
|
||||
/// entries for that name.
|
||||
mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr;
|
||||
/// dependent context). We maintain the invariant that, if the map
|
||||
/// contains an entry for a DeclarationName (and we haven't lazily
|
||||
/// omitted anything), then it contains all relevant entries for that
|
||||
/// name (modulo the hasExternalDecls() flag).
|
||||
mutable StoredDeclsMap *LookupPtr;
|
||||
|
||||
protected:
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
@ -1075,8 +1151,9 @@ class DeclContext {
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false),
|
||||
NeedToReconcileExternalVisibleStorage(false), LookupPtr(nullptr, false),
|
||||
FirstDecl(nullptr), LastDecl(nullptr) {}
|
||||
NeedToReconcileExternalVisibleStorage(false),
|
||||
HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false),
|
||||
LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {}
|
||||
|
||||
public:
|
||||
~DeclContext();
|
||||
@ -1147,6 +1224,11 @@ class DeclContext {
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Test whether the context supports looking up names.
|
||||
bool isLookupContext() const {
|
||||
return !isFunctionOrMethod() && DeclKind != Decl::LinkageSpec;
|
||||
}
|
||||
|
||||
bool isFileContext() const {
|
||||
return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace;
|
||||
}
|
||||
@ -1520,26 +1602,15 @@ class DeclContext {
|
||||
/// @brief Checks whether a declaration is in this context.
|
||||
bool containsDecl(Decl *D) const;
|
||||
|
||||
/// lookup_iterator - An iterator that provides access to the results
|
||||
/// of looking up a name within this context.
|
||||
typedef NamedDecl **lookup_iterator;
|
||||
|
||||
/// lookup_const_iterator - An iterator that provides non-mutable
|
||||
/// access to the results of lookup up a name within this context.
|
||||
typedef NamedDecl * const * lookup_const_iterator;
|
||||
|
||||
typedef DeclContextLookupResult lookup_result;
|
||||
typedef DeclContextLookupConstResult lookup_const_result;
|
||||
typedef lookup_result::iterator lookup_iterator;
|
||||
|
||||
/// lookup - Find the declarations (if any) with the given Name in
|
||||
/// this context. Returns a range of iterators that contains all of
|
||||
/// the declarations with this name, with object, function, member,
|
||||
/// and enumerator names preceding any tag name. Note that this
|
||||
/// routine will not look into parent contexts.
|
||||
lookup_result lookup(DeclarationName Name);
|
||||
lookup_const_result lookup(DeclarationName Name) const {
|
||||
return const_cast<DeclContext*>(this)->lookup(Name);
|
||||
}
|
||||
lookup_result lookup(DeclarationName Name) const;
|
||||
|
||||
/// \brief Find the declarations with the given name that are visible
|
||||
/// within this context; don't attempt to retrieve anything from an
|
||||
@ -1593,7 +1664,16 @@ class DeclContext {
|
||||
all_lookups_iterator noload_lookups_begin() const;
|
||||
all_lookups_iterator noload_lookups_end() const;
|
||||
|
||||
typedef llvm::iterator_range<UsingDirectiveDecl * const *> udir_range;
|
||||
struct udir_iterator;
|
||||
typedef llvm::iterator_adaptor_base<udir_iterator, lookup_iterator,
|
||||
std::random_access_iterator_tag,
|
||||
UsingDirectiveDecl *> udir_iterator_base;
|
||||
struct udir_iterator : udir_iterator_base {
|
||||
udir_iterator(lookup_iterator I) : udir_iterator_base(I) {}
|
||||
UsingDirectiveDecl *operator*() const;
|
||||
};
|
||||
|
||||
typedef llvm::iterator_range<udir_iterator> udir_range;
|
||||
|
||||
udir_range using_directives() const;
|
||||
|
||||
@ -1604,17 +1684,22 @@ class DeclContext {
|
||||
inline ddiag_range ddiags() const;
|
||||
|
||||
// Low-level accessors
|
||||
|
||||
/// \brief Mark the lookup table as needing to be built. This should be
|
||||
/// used only if setHasExternalLexicalStorage() has been called on any
|
||||
/// decl context for which this is the primary context.
|
||||
|
||||
/// \brief Mark that there are external lexical declarations that we need
|
||||
/// to include in our lookup table (and that are not available as external
|
||||
/// visible lookups). These extra lookup results will be found by walking
|
||||
/// the lexical declarations of this context. This should be used only if
|
||||
/// setHasExternalLexicalStorage() has been called on any decl context for
|
||||
/// which this is the primary context.
|
||||
void setMustBuildLookupTable() {
|
||||
LookupPtr.setInt(true);
|
||||
assert(this == getPrimaryContext() &&
|
||||
"should only be called on primary context");
|
||||
HasLazyExternalLexicalLookups = true;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the internal representation of the lookup structure.
|
||||
/// This may omit some names if we are lazily building the structure.
|
||||
StoredDeclsMap *getLookupPtr() const { return LookupPtr.getPointer(); }
|
||||
StoredDeclsMap *getLookupPtr() const { return LookupPtr; }
|
||||
|
||||
/// \brief Ensure the lookup structure is fully-built and return it.
|
||||
StoredDeclsMap *buildLookup();
|
||||
@ -1637,7 +1722,7 @@ class DeclContext {
|
||||
/// declarations visible in this context.
|
||||
void setHasExternalVisibleStorage(bool ES = true) {
|
||||
ExternalVisibleStorage = ES;
|
||||
if (ES && LookupPtr.getPointer())
|
||||
if (ES && LookupPtr)
|
||||
NeedToReconcileExternalVisibleStorage = true;
|
||||
}
|
||||
|
||||
@ -1657,7 +1742,7 @@ class DeclContext {
|
||||
|
||||
private:
|
||||
void reconcileExternalVisibleStorage() const;
|
||||
void LoadLexicalDeclsFromExternalStorage() const;
|
||||
bool LoadLexicalDeclsFromExternalStorage() const;
|
||||
|
||||
/// @brief Makes a declaration visible within this context, but
|
||||
/// suppresses searches for external declarations with the same
|
||||
@ -1670,9 +1755,7 @@ class DeclContext {
|
||||
friend class DependentDiagnostic;
|
||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||
|
||||
template<decl_iterator (DeclContext::*Begin)() const,
|
||||
decl_iterator (DeclContext::*End)() const>
|
||||
void buildLookupImpl(DeclContext *DCtx);
|
||||
void buildLookupImpl(DeclContext *DCtx, bool Internal);
|
||||
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||
bool Rediscoverable);
|
||||
void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal);
|
||||
|
@ -651,8 +651,8 @@ class CXXRecordDecl : public RecordDecl {
|
||||
CXXRecordDecl *getCanonicalDecl() override {
|
||||
return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl());
|
||||
}
|
||||
virtual const CXXRecordDecl *getCanonicalDecl() const {
|
||||
return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl());
|
||||
const CXXRecordDecl *getCanonicalDecl() const {
|
||||
return const_cast<CXXRecordDecl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
CXXRecordDecl *getPreviousDecl() {
|
||||
@ -1093,8 +1093,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
/// \brief Get all conversion functions visible in current class,
|
||||
/// including conversion function templates.
|
||||
std::pair<conversion_iterator, conversion_iterator>
|
||||
getVisibleConversionFunctions();
|
||||
llvm::iterator_range<conversion_iterator> getVisibleConversionFunctions();
|
||||
|
||||
/// Determine whether this class is an aggregate (C++ [dcl.init.aggr]),
|
||||
/// which is a class with no user-declared constructors, no private
|
||||
@ -1782,7 +1781,7 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
CXXMethodDecl *getCanonicalDecl() override {
|
||||
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
const CXXMethodDecl *getCanonicalDecl() const override {
|
||||
const CXXMethodDecl *getCanonicalDecl() const {
|
||||
return const_cast<CXXMethodDecl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
@ -2085,7 +2084,7 @@ class CXXCtorInitializer {
|
||||
/// This can only be called once for each initializer; it cannot be called
|
||||
/// on an initializer having a positive number of (implicit) array indices.
|
||||
///
|
||||
/// This assumes that the initialzier was written in the source code, and
|
||||
/// This assumes that the initializer was written in the source code, and
|
||||
/// ensures that isWritten() returns true.
|
||||
void setSourceOrder(int pos) {
|
||||
assert(!IsWritten &&
|
||||
@ -2150,7 +2149,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
/// \name Support for base and member initializers.
|
||||
/// \{
|
||||
/// \brief The arguments used to initialize the base or member.
|
||||
CXXCtorInitializer **CtorInitializers;
|
||||
LazyCXXCtorInitializersPtr CtorInitializers;
|
||||
unsigned NumCtorInitializers;
|
||||
/// \}
|
||||
|
||||
@ -2189,7 +2188,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
typedef CXXCtorInitializer **init_iterator;
|
||||
|
||||
/// \brief Iterates through the member/base initializer list.
|
||||
typedef CXXCtorInitializer * const * init_const_iterator;
|
||||
typedef CXXCtorInitializer *const *init_const_iterator;
|
||||
|
||||
typedef llvm::iterator_range<init_iterator> init_range;
|
||||
typedef llvm::iterator_range<init_const_iterator> init_const_range;
|
||||
@ -2200,17 +2199,20 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
}
|
||||
|
||||
/// \brief Retrieve an iterator to the first initializer.
|
||||
init_iterator init_begin() { return CtorInitializers; }
|
||||
init_iterator init_begin() {
|
||||
const auto *ConstThis = this;
|
||||
return const_cast<init_iterator>(ConstThis->init_begin());
|
||||
}
|
||||
/// \brief Retrieve an iterator to the first initializer.
|
||||
init_const_iterator init_begin() const { return CtorInitializers; }
|
||||
init_const_iterator init_begin() const;
|
||||
|
||||
/// \brief Retrieve an iterator past the last initializer.
|
||||
init_iterator init_end() {
|
||||
return CtorInitializers + NumCtorInitializers;
|
||||
return init_begin() + NumCtorInitializers;
|
||||
}
|
||||
/// \brief Retrieve an iterator past the last initializer.
|
||||
init_const_iterator init_end() const {
|
||||
return CtorInitializers + NumCtorInitializers;
|
||||
return init_begin() + NumCtorInitializers;
|
||||
}
|
||||
|
||||
typedef std::reverse_iterator<init_iterator> init_reverse_iterator;
|
||||
@ -2241,14 +2243,14 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
NumCtorInitializers = numCtorInitializers;
|
||||
}
|
||||
|
||||
void setCtorInitializers(CXXCtorInitializer ** initializers) {
|
||||
CtorInitializers = initializers;
|
||||
void setCtorInitializers(CXXCtorInitializer **Initializers) {
|
||||
CtorInitializers = Initializers;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this constructor is a delegating constructor.
|
||||
bool isDelegatingConstructor() const {
|
||||
return (getNumCtorInitializers() == 1) &&
|
||||
CtorInitializers[0]->isDelegatingInitializer();
|
||||
init_begin()[0]->isDelegatingInitializer();
|
||||
}
|
||||
|
||||
/// \brief When this constructor delegates to another, retrieve the target.
|
||||
@ -2324,12 +2326,12 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
/// \brief Set the constructor that this inheriting constructor is based on.
|
||||
void setInheritedConstructor(const CXXConstructorDecl *BaseCtor);
|
||||
|
||||
const CXXConstructorDecl *getCanonicalDecl() const override {
|
||||
return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
CXXConstructorDecl *getCanonicalDecl() override {
|
||||
return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
const CXXConstructorDecl *getCanonicalDecl() const {
|
||||
return const_cast<CXXConstructorDecl*>(this)->getCanonicalDecl();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
@ -2373,9 +2375,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
||||
bool isImplicitlyDeclared);
|
||||
static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
|
||||
|
||||
void setOperatorDelete(FunctionDecl *OD) {
|
||||
cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete = OD;
|
||||
}
|
||||
void setOperatorDelete(FunctionDecl *OD);
|
||||
const FunctionDecl *getOperatorDelete() const {
|
||||
return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete;
|
||||
}
|
||||
|
@ -142,31 +142,29 @@ struct StoredDeclsList {
|
||||
/// represents.
|
||||
DeclContext::lookup_result getLookupResult() {
|
||||
if (isNull())
|
||||
return DeclContext::lookup_result(DeclContext::lookup_iterator(nullptr),
|
||||
DeclContext::lookup_iterator(nullptr));
|
||||
return DeclContext::lookup_result();
|
||||
|
||||
// If we have a single NamedDecl, return it.
|
||||
if (getAsDecl()) {
|
||||
if (NamedDecl *ND = getAsDecl()) {
|
||||
assert(!isNull() && "Empty list isn't allowed");
|
||||
|
||||
// Data is a raw pointer to a NamedDecl*, return it.
|
||||
void *Ptr = &Data;
|
||||
return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1);
|
||||
return DeclContext::lookup_result(ND);
|
||||
}
|
||||
|
||||
assert(getAsVector() && "Must have a vector at this point");
|
||||
DeclsTy &Vector = *getAsVector();
|
||||
|
||||
// Otherwise, we have a range result.
|
||||
return DeclContext::lookup_result(Vector.begin(), Vector.end());
|
||||
return DeclContext::lookup_result(Vector);
|
||||
}
|
||||
|
||||
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
|
||||
/// replace the old one with D and return true. Otherwise return false.
|
||||
bool HandleRedeclaration(NamedDecl *D) {
|
||||
bool HandleRedeclaration(NamedDecl *D, bool IsKnownNewer) {
|
||||
// Most decls only have one entry in their list, special case it.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
if (!D->declarationReplaces(OldD))
|
||||
if (!D->declarationReplaces(OldD, IsKnownNewer))
|
||||
return false;
|
||||
setOnlyValue(D);
|
||||
return true;
|
||||
@ -177,7 +175,7 @@ struct StoredDeclsList {
|
||||
for (DeclsTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
|
||||
OD != ODEnd; ++OD) {
|
||||
NamedDecl *OldD = *OD;
|
||||
if (D->declarationReplaces(OldD)) {
|
||||
if (D->declarationReplaces(OldD, IsKnownNewer)) {
|
||||
*OD = D;
|
||||
return true;
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ class ObjCPropertyImplDecl;
|
||||
class CXXCtorInitializer;
|
||||
|
||||
class ObjCListBase {
|
||||
ObjCListBase(const ObjCListBase &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ObjCListBase &) LLVM_DELETED_FUNCTION;
|
||||
ObjCListBase(const ObjCListBase &) = delete;
|
||||
void operator=(const ObjCListBase &) = delete;
|
||||
protected:
|
||||
/// List is an array of pointers to objects that are not owned by this object.
|
||||
void **List;
|
||||
@ -820,8 +820,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const;
|
||||
ObjCMethodDecl *getCategoryClassMethod(Selector Sel) const;
|
||||
ObjCMethodDecl *getCategoryMethod(Selector Sel, bool isInstance) const {
|
||||
return isInstance ? getInstanceMethod(Sel)
|
||||
: getClassMethod(Sel);
|
||||
return isInstance ? getCategoryInstanceMethod(Sel)
|
||||
: getCategoryClassMethod(Sel);
|
||||
}
|
||||
|
||||
typedef ObjCProtocolList::iterator protocol_iterator;
|
||||
@ -2002,8 +2002,8 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
SourceLocation IvarRBraceLoc;
|
||||
|
||||
/// Support for ivar initialization.
|
||||
/// IvarInitializers - The arguments used to initialize the ivars
|
||||
CXXCtorInitializer **IvarInitializers;
|
||||
/// \brief The arguments used to initialize the ivars
|
||||
LazyCXXCtorInitializersPtr IvarInitializers;
|
||||
unsigned NumIvarInitializers;
|
||||
|
||||
/// Do the ivars of this class require initialization other than
|
||||
@ -2052,17 +2052,20 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
}
|
||||
|
||||
/// init_begin() - Retrieve an iterator to the first initializer.
|
||||
init_iterator init_begin() { return IvarInitializers; }
|
||||
init_iterator init_begin() {
|
||||
const auto *ConstThis = this;
|
||||
return const_cast<init_iterator>(ConstThis->init_begin());
|
||||
}
|
||||
/// begin() - Retrieve an iterator to the first initializer.
|
||||
init_const_iterator init_begin() const { return IvarInitializers; }
|
||||
init_const_iterator init_begin() const;
|
||||
|
||||
/// init_end() - Retrieve an iterator past the last initializer.
|
||||
init_iterator init_end() {
|
||||
return IvarInitializers + NumIvarInitializers;
|
||||
return init_begin() + NumIvarInitializers;
|
||||
}
|
||||
/// end() - Retrieve an iterator past the last initializer.
|
||||
init_const_iterator init_end() const {
|
||||
return IvarInitializers + NumIvarInitializers;
|
||||
return init_begin() + NumIvarInitializers;
|
||||
}
|
||||
/// getNumArgs - Number of ivars which must be initialized.
|
||||
unsigned getNumIvarInitializers() const {
|
||||
|
@ -158,8 +158,8 @@ class TemplateArgumentList {
|
||||
/// argument list.
|
||||
unsigned NumArguments;
|
||||
|
||||
TemplateArgumentList(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
|
||||
TemplateArgumentList(const TemplateArgumentList &Other) = delete;
|
||||
void operator=(const TemplateArgumentList &Other) = delete;
|
||||
|
||||
TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs,
|
||||
bool Owned)
|
||||
@ -314,7 +314,7 @@ class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
|
||||
/// \brief The function template from which this function template
|
||||
/// specialization was generated.
|
||||
///
|
||||
/// The two bits are contain the top 4 values of TemplateSpecializationKind.
|
||||
/// The two bits contain the top 4 values of TemplateSpecializationKind.
|
||||
llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
|
||||
|
||||
/// \brief The template arguments used to produce the function template
|
||||
@ -545,47 +545,32 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
template <typename EntryType> struct SpecEntryTraits {
|
||||
typedef EntryType DeclType;
|
||||
|
||||
static DeclType *getMostRecentDecl(EntryType *D) {
|
||||
return D->getMostRecentDecl();
|
||||
static DeclType *getDecl(EntryType *D) {
|
||||
return D;
|
||||
}
|
||||
static ArrayRef<TemplateArgument> getTemplateArgs(EntryType *D) {
|
||||
return D->getTemplateArgs().asArray();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename EntryType,
|
||||
typename _SETraits = SpecEntryTraits<EntryType>,
|
||||
typename _DeclType = typename _SETraits::DeclType>
|
||||
class SpecIterator : public std::iterator<std::forward_iterator_tag,
|
||||
_DeclType*, ptrdiff_t,
|
||||
_DeclType*, _DeclType*> {
|
||||
typedef _SETraits SETraits;
|
||||
typedef _DeclType DeclType;
|
||||
|
||||
typedef typename llvm::FoldingSetVector<EntryType>::iterator
|
||||
SetIteratorType;
|
||||
|
||||
SetIteratorType SetIter;
|
||||
|
||||
public:
|
||||
SpecIterator() : SetIter() {}
|
||||
SpecIterator(SetIteratorType SetIter) : SetIter(SetIter) {}
|
||||
template <typename EntryType, typename SETraits = SpecEntryTraits<EntryType>,
|
||||
typename DeclType = typename SETraits::DeclType>
|
||||
struct SpecIterator
|
||||
: llvm::iterator_adaptor_base<
|
||||
SpecIterator<EntryType, SETraits, DeclType>,
|
||||
typename llvm::FoldingSetVector<EntryType>::iterator,
|
||||
typename std::iterator_traits<typename llvm::FoldingSetVector<
|
||||
EntryType>::iterator>::iterator_category,
|
||||
DeclType *, ptrdiff_t, DeclType *, DeclType *> {
|
||||
SpecIterator() {}
|
||||
explicit SpecIterator(
|
||||
typename llvm::FoldingSetVector<EntryType>::iterator SetIter)
|
||||
: SpecIterator::iterator_adaptor_base(std::move(SetIter)) {}
|
||||
|
||||
DeclType *operator*() const {
|
||||
return SETraits::getMostRecentDecl(&*SetIter);
|
||||
return SETraits::getDecl(&*this->I)->getMostRecentDecl();
|
||||
}
|
||||
DeclType *operator->() const { return **this; }
|
||||
|
||||
SpecIterator &operator++() { ++SetIter; return *this; }
|
||||
SpecIterator operator++(int) {
|
||||
SpecIterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(SpecIterator Other) const {
|
||||
return SetIter == Other.SetIter;
|
||||
}
|
||||
bool operator!=(SpecIterator Other) const {
|
||||
return SetIter != Other.SetIter;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename EntryType>
|
||||
@ -598,6 +583,10 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
|
||||
ArrayRef<TemplateArgument> Args, void *&InsertPos);
|
||||
|
||||
template <class Derived, class EntryType>
|
||||
void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
|
||||
EntryType *Entry, void *InsertPos);
|
||||
|
||||
struct CommonBase {
|
||||
CommonBase() : InstantiatedFromMember(nullptr, false) { }
|
||||
|
||||
@ -737,9 +726,12 @@ template <> struct RedeclarableTemplateDecl::
|
||||
SpecEntryTraits<FunctionTemplateSpecializationInfo> {
|
||||
typedef FunctionDecl DeclType;
|
||||
|
||||
static DeclType *
|
||||
getMostRecentDecl(FunctionTemplateSpecializationInfo *I) {
|
||||
return I->Function->getMostRecentDecl();
|
||||
static DeclType *getDecl(FunctionTemplateSpecializationInfo *I) {
|
||||
return I->Function;
|
||||
}
|
||||
static ArrayRef<TemplateArgument>
|
||||
getTemplateArgs(FunctionTemplateSpecializationInfo *I) {
|
||||
return I->TemplateArguments->asArray();
|
||||
}
|
||||
};
|
||||
|
||||
@ -788,9 +780,6 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
|
||||
friend class FunctionDecl;
|
||||
|
||||
/// \brief Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations() const;
|
||||
|
||||
/// \brief Retrieve the set of function template specializations of this
|
||||
/// function template.
|
||||
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
|
||||
@ -804,6 +793,9 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
void *InsertPos);
|
||||
|
||||
public:
|
||||
/// \brief Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations() const;
|
||||
|
||||
/// Get the underlying function declaration of the template.
|
||||
FunctionDecl *getTemplatedDecl() const {
|
||||
return static_cast<FunctionDecl*>(TemplatedDecl);
|
||||
@ -843,6 +835,15 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
FunctionTemplateDecl *getMostRecentDecl() {
|
||||
return cast<FunctionTemplateDecl>(
|
||||
static_cast<RedeclarableTemplateDecl *>(this)
|
||||
->getMostRecentDecl());
|
||||
}
|
||||
const FunctionTemplateDecl *getMostRecentDecl() const {
|
||||
return const_cast<FunctionTemplateDecl*>(this)->getMostRecentDecl();
|
||||
}
|
||||
|
||||
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
return cast_or_null<FunctionTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
|
||||
@ -903,7 +904,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
/// This class is inheritedly privately by different kinds of template
|
||||
/// parameters and is not part of the Decl hierarchy. Just a facility.
|
||||
class TemplateParmPosition {
|
||||
TemplateParmPosition() LLVM_DELETED_FUNCTION;
|
||||
TemplateParmPosition() = delete;
|
||||
|
||||
protected:
|
||||
TemplateParmPosition(unsigned D, unsigned P)
|
||||
@ -1827,9 +1828,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
uint32_t *LazySpecializations;
|
||||
};
|
||||
|
||||
/// \brief Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations() const;
|
||||
|
||||
/// \brief Retrieve the set of specializations of this class template.
|
||||
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
|
||||
getSpecializations() const;
|
||||
@ -1851,6 +1849,9 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations() const;
|
||||
|
||||
/// \brief Get the underlying class declarations of the template.
|
||||
CXXRecordDecl *getTemplatedDecl() const {
|
||||
return static_cast<CXXRecordDecl *>(TemplatedDecl);
|
||||
@ -2662,9 +2663,6 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
uint32_t *LazySpecializations;
|
||||
};
|
||||
|
||||
/// \brief Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations() const;
|
||||
|
||||
/// \brief Retrieve the set of specializations of this variable template.
|
||||
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
|
||||
getSpecializations() const;
|
||||
@ -2686,6 +2684,9 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations() const;
|
||||
|
||||
/// \brief Get the underlying variable declarations of the template.
|
||||
VarDecl *getTemplatedDecl() const {
|
||||
return static_cast<VarDecl *>(TemplatedDecl);
|
||||
@ -2739,6 +2740,14 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
|
||||
this)->getPreviousDecl());
|
||||
}
|
||||
|
||||
VarTemplateDecl *getMostRecentDecl() {
|
||||
return cast<VarTemplateDecl>(
|
||||
static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl());
|
||||
}
|
||||
const VarTemplateDecl *getMostRecentDecl() const {
|
||||
return const_cast<VarTemplateDecl *>(this)->getMostRecentDecl();
|
||||
}
|
||||
|
||||
VarTemplateDecl *getInstantiatedFromMemberTemplate() {
|
||||
return cast_or_null<VarTemplateDecl>(
|
||||
RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
|
||||
|
@ -184,7 +184,7 @@ class DeclarationName {
|
||||
|
||||
// operator bool() - Evaluates true when this declaration name is
|
||||
// non-empty.
|
||||
LLVM_EXPLICIT operator bool() const {
|
||||
explicit operator bool() const {
|
||||
return ((Ptr & PtrMask) != 0) ||
|
||||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
|
||||
}
|
||||
@ -344,8 +344,8 @@ class DeclarationNameTable {
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
|
||||
|
||||
DeclarationNameTable(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
|
||||
DeclarationNameTable(const DeclarationNameTable&) = delete;
|
||||
void operator=(const DeclarationNameTable&) = delete;
|
||||
|
||||
public:
|
||||
DeclarationNameTable(const ASTContext &C);
|
||||
|
@ -276,6 +276,7 @@ class Expr : public Stmt {
|
||||
MLV_LValueCast, // Specialized form of MLV_InvalidExpression.
|
||||
MLV_IncompleteType,
|
||||
MLV_ConstQualified,
|
||||
MLV_ConstAddrSpace,
|
||||
MLV_ArrayType,
|
||||
MLV_NoSetterProperty,
|
||||
MLV_MemberFunction,
|
||||
@ -324,6 +325,7 @@ class Expr : public Stmt {
|
||||
CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext
|
||||
CM_NoSetterProperty,// Implicit assignment to ObjC property without setter
|
||||
CM_ConstQualified,
|
||||
CM_ConstAddrSpace,
|
||||
CM_ArrayType,
|
||||
CM_IncompleteType
|
||||
};
|
||||
@ -1239,8 +1241,8 @@ class APNumericStorage {
|
||||
|
||||
bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; }
|
||||
|
||||
APNumericStorage(const APNumericStorage &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const APNumericStorage &) LLVM_DELETED_FUNCTION;
|
||||
APNumericStorage(const APNumericStorage &) = delete;
|
||||
void operator=(const APNumericStorage &) = delete;
|
||||
|
||||
protected:
|
||||
APNumericStorage() : VAL(0), BitWidth(0) { }
|
||||
@ -1997,18 +1999,7 @@ class UnaryExprOrTypeTraitExpr : public Expr {
|
||||
|
||||
UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, Expr *E,
|
||||
QualType resultType, SourceLocation op,
|
||||
SourceLocation rp) :
|
||||
Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary,
|
||||
false, // Never type-dependent (C++ [temp.dep.expr]p3).
|
||||
// Value-dependent if the argument is type-dependent.
|
||||
E->isTypeDependent(),
|
||||
E->isInstantiationDependent(),
|
||||
E->containsUnexpandedParameterPack()),
|
||||
OpLoc(op), RParenLoc(rp) {
|
||||
UnaryExprOrTypeTraitExprBits.Kind = ExprKind;
|
||||
UnaryExprOrTypeTraitExprBits.IsType = false;
|
||||
Argument.Ex = E;
|
||||
}
|
||||
SourceLocation rp);
|
||||
|
||||
/// \brief Construct an empty sizeof/alignof expression.
|
||||
explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty)
|
||||
@ -2287,7 +2278,7 @@ class CallExpr : public Expr {
|
||||
/// getCallReturnType - Get the return type of the call expr. This is not
|
||||
/// always the type of the expr itself, if the return type is a reference
|
||||
/// type.
|
||||
QualType getCallReturnType() const;
|
||||
QualType getCallReturnType(const ASTContext &Ctx) const;
|
||||
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
@ -2336,6 +2327,9 @@ class MemberExpr : public Expr {
|
||||
/// MemberLoc - This is the location of the member name.
|
||||
SourceLocation MemberLoc;
|
||||
|
||||
/// This is the location of the -> or . in the expression.
|
||||
SourceLocation OperatorLoc;
|
||||
|
||||
/// IsArrow - True if this is "X->F", false if this is "X.F".
|
||||
bool IsArrow : 1;
|
||||
|
||||
@ -2370,18 +2364,16 @@ class MemberExpr : public Expr {
|
||||
}
|
||||
|
||||
public:
|
||||
MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl,
|
||||
const DeclarationNameInfo &NameInfo, QualType ty,
|
||||
ExprValueKind VK, ExprObjectKind OK)
|
||||
: Expr(MemberExprClass, ty, VK, OK,
|
||||
base->isTypeDependent(),
|
||||
base->isValueDependent(),
|
||||
base->isInstantiationDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
Base(base), MemberDecl(memberdecl), MemberDNLoc(NameInfo.getInfo()),
|
||||
MemberLoc(NameInfo.getLoc()), IsArrow(isarrow),
|
||||
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
|
||||
HadMultipleCandidates(false) {
|
||||
MemberExpr(Expr *base, bool isarrow, SourceLocation operatorloc,
|
||||
ValueDecl *memberdecl, const DeclarationNameInfo &NameInfo,
|
||||
QualType ty, ExprValueKind VK, ExprObjectKind OK)
|
||||
: Expr(MemberExprClass, ty, VK, OK, base->isTypeDependent(),
|
||||
base->isValueDependent(), base->isInstantiationDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
Base(base), MemberDecl(memberdecl), MemberDNLoc(NameInfo.getInfo()),
|
||||
MemberLoc(NameInfo.getLoc()), OperatorLoc(operatorloc),
|
||||
IsArrow(isarrow), HasQualifierOrFoundDecl(false),
|
||||
HasTemplateKWAndArgsInfo(false), HadMultipleCandidates(false) {
|
||||
assert(memberdecl->getDeclName() == NameInfo.getName());
|
||||
}
|
||||
|
||||
@ -2389,25 +2381,25 @@ class MemberExpr : public Expr {
|
||||
// the member name can not provide additional syntactic info
|
||||
// (i.e., source locations for C++ operator names or type source info
|
||||
// for constructors, destructors and conversion operators).
|
||||
MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl,
|
||||
SourceLocation l, QualType ty,
|
||||
MemberExpr(Expr *base, bool isarrow, SourceLocation operatorloc,
|
||||
ValueDecl *memberdecl, SourceLocation l, QualType ty,
|
||||
ExprValueKind VK, ExprObjectKind OK)
|
||||
: Expr(MemberExprClass, ty, VK, OK,
|
||||
base->isTypeDependent(), base->isValueDependent(),
|
||||
base->isInstantiationDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l),
|
||||
IsArrow(isarrow),
|
||||
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
|
||||
HadMultipleCandidates(false) {}
|
||||
: Expr(MemberExprClass, ty, VK, OK, base->isTypeDependent(),
|
||||
base->isValueDependent(), base->isInstantiationDependent(),
|
||||
base->containsUnexpandedParameterPack()),
|
||||
Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l),
|
||||
OperatorLoc(operatorloc), IsArrow(isarrow),
|
||||
HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
|
||||
HadMultipleCandidates(false) {}
|
||||
|
||||
static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *memberdecl, DeclAccessPair founddecl,
|
||||
SourceLocation TemplateKWLoc, ValueDecl *memberdecl,
|
||||
DeclAccessPair founddecl,
|
||||
DeclarationNameInfo MemberNameInfo,
|
||||
const TemplateArgumentListInfo *targs,
|
||||
QualType ty, ExprValueKind VK, ExprObjectKind OK);
|
||||
const TemplateArgumentListInfo *targs, QualType ty,
|
||||
ExprValueKind VK, ExprObjectKind OK);
|
||||
|
||||
void setBase(Expr *E) { Base = E; }
|
||||
Expr *getBase() const { return cast<Expr>(Base); }
|
||||
@ -2551,6 +2543,8 @@ class MemberExpr : public Expr {
|
||||
MemberLoc, MemberDNLoc);
|
||||
}
|
||||
|
||||
SourceLocation getOperatorLoc() const LLVM_READONLY { return OperatorLoc; }
|
||||
|
||||
bool isArrow() const { return IsArrow; }
|
||||
void setArrow(bool A) { IsArrow = A; }
|
||||
|
||||
|
@ -86,6 +86,13 @@ class CXXOperatorCallExpr : public CallExpr {
|
||||
/// of the right bracket.
|
||||
SourceLocation getOperatorLoc() const { return getRParenLoc(); }
|
||||
|
||||
SourceLocation getExprLoc() const LLVM_READONLY {
|
||||
return (Operator < OO_Plus || Operator >= OO_Arrow ||
|
||||
Operator == OO_PlusPlus || Operator == OO_MinusMinus)
|
||||
? getLocStart()
|
||||
: getOperatorLoc();
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
|
||||
SourceRange getSourceRange() const { return Range; }
|
||||
@ -1127,7 +1134,7 @@ class CXXConstructExpr : public Expr {
|
||||
ConstructionKind ConstructKind,
|
||||
SourceRange ParenOrBraceRange);
|
||||
|
||||
CXXConstructorDecl* getConstructor() const { return Constructor; }
|
||||
CXXConstructorDecl *getConstructor() const { return Constructor; }
|
||||
void setConstructor(CXXConstructorDecl *C) { Constructor = C; }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
@ -1404,14 +1411,13 @@ class LambdaExpr : public Expr {
|
||||
unsigned *getArrayIndexStarts() const {
|
||||
return reinterpret_cast<unsigned *>(getStoredStmts() + NumCaptures + 1);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the complete set of array-index variables.
|
||||
VarDecl **getArrayIndexVars() const {
|
||||
unsigned ArrayIndexSize =
|
||||
llvm::RoundUpToAlignment(sizeof(unsigned) * (NumCaptures + 1),
|
||||
llvm::alignOf<VarDecl*>());
|
||||
unsigned ArrayIndexSize = llvm::RoundUpToAlignment(
|
||||
sizeof(unsigned) * (NumCaptures + 1), llvm::alignOf<VarDecl *>());
|
||||
return reinterpret_cast<VarDecl **>(
|
||||
reinterpret_cast<char*>(getArrayIndexStarts()) + ArrayIndexSize);
|
||||
reinterpret_cast<char *>(getArrayIndexStarts()) + ArrayIndexSize);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1446,6 +1452,9 @@ class LambdaExpr : public Expr {
|
||||
return CaptureDefaultLoc;
|
||||
}
|
||||
|
||||
/// \brief Determine whether one of this lambda's captures is an init-capture.
|
||||
bool isInitCapture(const LambdaCapture *Capture) const;
|
||||
|
||||
/// \brief An iterator that walks over the captures of the lambda,
|
||||
/// both implicit and explicit.
|
||||
typedef const Capture *capture_iterator;
|
||||
@ -1686,6 +1695,10 @@ class CXXNewExpr : public Expr {
|
||||
/// not be done, the deallocation function shall not be called,
|
||||
/// and the value of the new-expression shall be null.
|
||||
///
|
||||
/// C++ DR1748:
|
||||
/// If the allocation function is a reserved placement allocation
|
||||
/// function that returns null, the behavior is undefined.
|
||||
///
|
||||
/// An allocation function is not allowed to return null unless it
|
||||
/// has a non-throwing exception-specification. The '03 rule is
|
||||
/// identical except that the definition of a non-throwing
|
||||
|
@ -22,6 +22,7 @@ namespace clang {
|
||||
|
||||
class ASTConsumer;
|
||||
class CXXBaseSpecifier;
|
||||
class CXXCtorInitializer;
|
||||
class DeclarationName;
|
||||
class ExternalSemaSource; // layering violation required for downcasting
|
||||
class FieldDecl;
|
||||
@ -121,6 +122,12 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
|
||||
|
||||
/// \brief Resolve the offset of a set of C++ constructor initializers in
|
||||
/// the decl stream into an array of initializers.
|
||||
///
|
||||
/// The default implementation of this method is a no-op.
|
||||
virtual CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset);
|
||||
|
||||
/// \brief Resolve the offset of a set of C++ base specifiers in the decl
|
||||
/// stream into an array of specifiers.
|
||||
///
|
||||
@ -344,7 +351,7 @@ struct LazyOffsetPtr {
|
||||
/// \brief Whether this pointer is non-NULL.
|
||||
///
|
||||
/// This operation does not require the AST node to be deserialized.
|
||||
LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
|
||||
explicit operator bool() const { return Ptr != 0; }
|
||||
|
||||
/// \brief Whether this pointer is non-NULL.
|
||||
///
|
||||
@ -477,132 +484,42 @@ class LazyVector {
|
||||
SmallVector<T, LocalStorage> Local;
|
||||
|
||||
public:
|
||||
// Iteration over the elements in the vector.
|
||||
class iterator {
|
||||
/// Iteration over the elements in the vector.
|
||||
///
|
||||
/// In a complete iteration, the iterator 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.
|
||||
///
|
||||
/// We define this as a wrapping iterator around an int. The
|
||||
/// iterator_adaptor_base class forwards the iterator methods to basic integer
|
||||
/// arithmetic.
|
||||
class iterator : public llvm::iterator_adaptor_base<
|
||||
iterator, int, std::random_access_iterator_tag, T, int> {
|
||||
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;
|
||||
|
||||
|
||||
iterator(LazyVector *Self, int Position)
|
||||
: iterator::iterator_adaptor_base(Position), Self(Self) {}
|
||||
|
||||
bool isLoaded() const { return this->I < 0; }
|
||||
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;
|
||||
iterator() : iterator(nullptr, 0) {}
|
||||
|
||||
typename iterator::reference operator*() const {
|
||||
if (isLoaded())
|
||||
return Self->Loaded.end()[this->I];
|
||||
return Self->Local.begin()[this->I];
|
||||
}
|
||||
};
|
||||
friend class iterator;
|
||||
|
||||
|
||||
iterator begin(Source *source, bool LocalOnly = false) {
|
||||
if (LocalOnly)
|
||||
return iterator(this, 0);
|
||||
@ -621,17 +538,17 @@ class LazyVector {
|
||||
}
|
||||
|
||||
void erase(iterator From, iterator To) {
|
||||
if (From.Position < 0 && To.Position < 0) {
|
||||
Loaded.erase(Loaded.end() + From.Position, Loaded.end() + To.Position);
|
||||
if (From.isLoaded() && To.isLoaded()) {
|
||||
Loaded.erase(&*From, &*To);
|
||||
return;
|
||||
}
|
||||
|
||||
if (From.Position < 0) {
|
||||
Loaded.erase(Loaded.end() + From.Position, Loaded.end());
|
||||
|
||||
if (From.isLoaded()) {
|
||||
Loaded.erase(&*From, Loaded.end());
|
||||
From = begin(nullptr, true);
|
||||
}
|
||||
|
||||
Local.erase(Local.begin() + From.Position, Local.begin() + To.Position);
|
||||
|
||||
Local.erase(&*From, &*To);
|
||||
}
|
||||
};
|
||||
|
||||
@ -643,8 +560,13 @@ typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
|
||||
typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>
|
||||
LazyDeclPtr;
|
||||
|
||||
/// \brief A lazy pointer to a set of CXXCtorInitializers.
|
||||
typedef LazyOffsetPtr<CXXCtorInitializer *, uint64_t,
|
||||
&ExternalASTSource::GetExternalCXXCtorInitializers>
|
||||
LazyCXXCtorInitializersPtr;
|
||||
|
||||
/// \brief A lazy pointer to a set of CXXBaseSpecifiers.
|
||||
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
|
||||
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
|
||||
&ExternalASTSource::GetExternalCXXBaseSpecifiers>
|
||||
LazyCXXBaseSpecifiersPtr;
|
||||
|
||||
|
@ -85,11 +85,6 @@ class LambdaCapture {
|
||||
(DeclAndBits.getInt() & Capture_ByCopy);
|
||||
}
|
||||
|
||||
/// \brief Determine whether this is an init-capture.
|
||||
bool isInitCapture() const {
|
||||
return capturesVariable() && getCapturedVar()->isInitCapture();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the declaration of the local variable being
|
||||
/// captured.
|
||||
///
|
||||
|
@ -132,12 +132,21 @@ class MangleContext {
|
||||
virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
|
||||
raw_ostream &) = 0;
|
||||
|
||||
virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
|
||||
raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
|
||||
raw_ostream &Out) = 0;
|
||||
|
||||
/// Generates a unique string for an externally visible type for use with TBAA
|
||||
/// or type uniquing.
|
||||
/// TODO: Extend this to internal types by generating names that are unique
|
||||
/// across translation units so it can be used with LTO.
|
||||
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
|
||||
|
||||
virtual void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
|
||||
raw_ostream &) = 0;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
@ -188,9 +197,27 @@ class MicrosoftMangleContext : public MangleContext {
|
||||
ArrayRef<const CXXRecordDecl *> BasePath,
|
||||
raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleThreadSafeStaticGuardVariable(const VarDecl *VD,
|
||||
unsigned GuardNum,
|
||||
raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
|
||||
raw_ostream &) = 0;
|
||||
|
||||
virtual void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile,
|
||||
uint32_t NumEntries, raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
|
||||
raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
|
||||
CXXCtorType CT, uint32_t Size,
|
||||
uint32_t NVOffset, int32_t VBPtrOffset,
|
||||
uint32_t VBIndex, raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleCXXCatchHandlerType(QualType T, uint32_t Flags,
|
||||
raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleCXXRTTIBaseClassDescriptor(
|
||||
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
|
||||
uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) = 0;
|
||||
|
@ -33,9 +33,12 @@ class NSAPI {
|
||||
ClassId_NSMutableArray,
|
||||
ClassId_NSDictionary,
|
||||
ClassId_NSMutableDictionary,
|
||||
ClassId_NSNumber
|
||||
ClassId_NSNumber,
|
||||
ClassId_NSMutableSet,
|
||||
ClassId_NSCountedSet,
|
||||
ClassId_NSMutableOrderedSet,
|
||||
};
|
||||
static const unsigned NumClassIds = 7;
|
||||
static const unsigned NumClassIds = 10;
|
||||
|
||||
enum NSStringMethodKind {
|
||||
NSStr_stringWithString,
|
||||
@ -67,7 +70,8 @@ class NSAPI {
|
||||
return isObjCEnumerator(E, "NSASCIIStringEncoding",NSASCIIStringEncodingId);
|
||||
}
|
||||
|
||||
/// \brief Enumerates the NSArray methods used to generate literals.
|
||||
/// \brief Enumerates the NSArray/NSMutableArray methods used to generate
|
||||
/// literals and to apply some checks.
|
||||
enum NSArrayMethodKind {
|
||||
NSArr_array,
|
||||
NSArr_arrayWithArray,
|
||||
@ -77,9 +81,12 @@ class NSAPI {
|
||||
NSArr_initWithArray,
|
||||
NSArr_initWithObjects,
|
||||
NSArr_objectAtIndex,
|
||||
NSMutableArr_replaceObjectAtIndex
|
||||
NSMutableArr_replaceObjectAtIndex,
|
||||
NSMutableArr_addObject,
|
||||
NSMutableArr_insertObjectAtIndex,
|
||||
NSMutableArr_setObjectAtIndexedSubscript
|
||||
};
|
||||
static const unsigned NumNSArrayMethods = 9;
|
||||
static const unsigned NumNSArrayMethods = 12;
|
||||
|
||||
/// \brief The Objective-C NSArray selectors.
|
||||
Selector getNSArraySelector(NSArrayMethodKind MK) const;
|
||||
@ -87,7 +94,8 @@ class NSAPI {
|
||||
/// \brief Return NSArrayMethodKind if \p Sel is such a selector.
|
||||
Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
|
||||
|
||||
/// \brief Enumerates the NSDictionary methods used to generate literals.
|
||||
/// \brief Enumerates the NSDictionary/NSMutableDictionary methods used
|
||||
/// to generate literals and to apply some checks.
|
||||
enum NSDictionaryMethodKind {
|
||||
NSDict_dictionary,
|
||||
NSDict_dictionaryWithDictionary,
|
||||
@ -99,9 +107,11 @@ class NSAPI {
|
||||
NSDict_initWithObjectsAndKeys,
|
||||
NSDict_initWithObjectsForKeys,
|
||||
NSDict_objectForKey,
|
||||
NSMutableDict_setObjectForKey
|
||||
NSMutableDict_setObjectForKey,
|
||||
NSMutableDict_setObjectForKeyedSubscript,
|
||||
NSMutableDict_setValueForKey
|
||||
};
|
||||
static const unsigned NumNSDictionaryMethods = 12;
|
||||
static const unsigned NumNSDictionaryMethods = 14;
|
||||
|
||||
/// \brief The Objective-C NSDictionary selectors.
|
||||
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
|
||||
@ -109,6 +119,23 @@ class NSAPI {
|
||||
/// \brief Return NSDictionaryMethodKind if \p Sel is such a selector.
|
||||
Optional<NSDictionaryMethodKind> getNSDictionaryMethodKind(Selector Sel);
|
||||
|
||||
/// \brief Enumerates the NSMutableSet/NSOrderedSet methods used
|
||||
/// to apply some checks.
|
||||
enum NSSetMethodKind {
|
||||
NSMutableSet_addObject,
|
||||
NSOrderedSet_insertObjectAtIndex,
|
||||
NSOrderedSet_setObjectAtIndex,
|
||||
NSOrderedSet_setObjectAtIndexedSubscript,
|
||||
NSOrderedSet_replaceObjectAtIndexWithObject
|
||||
};
|
||||
static const unsigned NumNSSetMethods = 5;
|
||||
|
||||
/// \brief The Objective-C NSSet selectors.
|
||||
Selector getNSSetSelector(NSSetMethodKind MK) const;
|
||||
|
||||
/// \brief Return NSSetMethodKind if \p Sel is such a selector.
|
||||
Optional<NSSetMethodKind> getNSSetMethodKind(Selector Sel);
|
||||
|
||||
/// \brief Returns selector for "objectForKeyedSubscript:".
|
||||
Selector getObjectForKeyedSubscriptSelector() const {
|
||||
return getOrInitSelector(StringRef("objectForKeyedSubscript"),
|
||||
@ -189,6 +216,9 @@ class NSAPI {
|
||||
/// of that name in objective-c.
|
||||
StringRef GetNSIntegralKind(QualType T) const;
|
||||
|
||||
/// \brief Returns \c true if \p Id is currently defined as a macro.
|
||||
bool isMacroDefined(StringRef Id) const;
|
||||
|
||||
private:
|
||||
bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const;
|
||||
bool isObjCEnumerator(const Expr *E,
|
||||
@ -207,6 +237,9 @@ class NSAPI {
|
||||
/// \brief The selectors for Objective-C NSDictionary methods.
|
||||
mutable Selector NSDictionarySelectors[NumNSDictionaryMethods];
|
||||
|
||||
/// \brief The selectors for Objective-C NSSet methods.
|
||||
mutable Selector NSSetSelectors[NumNSSetMethods];
|
||||
|
||||
/// \brief The Objective-C NSNumber selectors used to create NSNumber literals.
|
||||
mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods];
|
||||
mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];
|
||||
|
@ -102,7 +102,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
Specifier(Other.Specifier) {
|
||||
}
|
||||
|
||||
void operator=(const NestedNameSpecifier &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const NestedNameSpecifier &) = delete;
|
||||
|
||||
/// \brief Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
@ -245,7 +245,7 @@ class NestedNameSpecifierLoc {
|
||||
|
||||
/// \brief Evalutes true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
LLVM_EXPLICIT operator bool() const { return Qualifier; }
|
||||
explicit operator bool() const { return Qualifier; }
|
||||
|
||||
/// \brief Evalutes true when this nested-name-specifier location is
|
||||
/// empty.
|
||||
|
@ -573,8 +573,10 @@ class OMPScheduleClause : public OMPClause {
|
||||
SourceLocation KindLoc;
|
||||
/// \brief Location of ',' (if any).
|
||||
SourceLocation CommaLoc;
|
||||
/// \brief Chunk size.
|
||||
Stmt *ChunkSize;
|
||||
/// \brief Chunk size and a reference to pseudo variable for combined
|
||||
/// directives.
|
||||
enum { CHUNK_SIZE, HELPER_CHUNK_SIZE, NUM_EXPRS };
|
||||
Stmt *ChunkSizes[NUM_EXPRS];
|
||||
|
||||
/// \brief Set schedule kind.
|
||||
///
|
||||
@ -600,7 +602,12 @@ class OMPScheduleClause : public OMPClause {
|
||||
///
|
||||
/// \param E Chunk size.
|
||||
///
|
||||
void setChunkSize(Expr *E) { ChunkSize = E; }
|
||||
void setChunkSize(Expr *E) { ChunkSizes[CHUNK_SIZE] = E; }
|
||||
/// \brief Set helper chunk size.
|
||||
///
|
||||
/// \param E Helper chunk size.
|
||||
///
|
||||
void setHelperChunkSize(Expr *E) { ChunkSizes[HELPER_CHUNK_SIZE] = E; }
|
||||
|
||||
public:
|
||||
/// \brief Build 'schedule' clause with schedule kind \a Kind and chunk size
|
||||
@ -613,19 +620,26 @@ class OMPScheduleClause : public OMPClause {
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param Kind Schedule kind.
|
||||
/// \param ChunkSize Chunk size.
|
||||
/// \param HelperChunkSize Helper chunk size for combined directives.
|
||||
///
|
||||
OMPScheduleClause(SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation KLoc, SourceLocation CommaLoc,
|
||||
SourceLocation EndLoc, OpenMPScheduleClauseKind Kind,
|
||||
Expr *ChunkSize)
|
||||
Expr *ChunkSize, Expr *HelperChunkSize)
|
||||
: OMPClause(OMPC_schedule, StartLoc, EndLoc), LParenLoc(LParenLoc),
|
||||
Kind(Kind), KindLoc(KLoc), CommaLoc(CommaLoc), ChunkSize(ChunkSize) {}
|
||||
Kind(Kind), KindLoc(KLoc), CommaLoc(CommaLoc) {
|
||||
ChunkSizes[CHUNK_SIZE] = ChunkSize;
|
||||
ChunkSizes[HELPER_CHUNK_SIZE] = HelperChunkSize;
|
||||
}
|
||||
|
||||
/// \brief Build an empty clause.
|
||||
///
|
||||
explicit OMPScheduleClause()
|
||||
: OMPClause(OMPC_schedule, SourceLocation(), SourceLocation()),
|
||||
Kind(OMPC_SCHEDULE_unknown), ChunkSize(nullptr) {}
|
||||
Kind(OMPC_SCHEDULE_unknown) {
|
||||
ChunkSizes[CHUNK_SIZE] = nullptr;
|
||||
ChunkSizes[HELPER_CHUNK_SIZE] = nullptr;
|
||||
}
|
||||
|
||||
/// \brief Get kind of the clause.
|
||||
///
|
||||
@ -641,16 +655,30 @@ class OMPScheduleClause : public OMPClause {
|
||||
SourceLocation getCommaLoc() { return CommaLoc; }
|
||||
/// \brief Get chunk size.
|
||||
///
|
||||
Expr *getChunkSize() { return dyn_cast_or_null<Expr>(ChunkSize); }
|
||||
Expr *getChunkSize() { return dyn_cast_or_null<Expr>(ChunkSizes[CHUNK_SIZE]); }
|
||||
/// \brief Get chunk size.
|
||||
///
|
||||
Expr *getChunkSize() const { return dyn_cast_or_null<Expr>(ChunkSize); }
|
||||
Expr *getChunkSize() const {
|
||||
return dyn_cast_or_null<Expr>(ChunkSizes[CHUNK_SIZE]);
|
||||
}
|
||||
/// \brief Get helper chunk size.
|
||||
///
|
||||
Expr *getHelperChunkSize() {
|
||||
return dyn_cast_or_null<Expr>(ChunkSizes[HELPER_CHUNK_SIZE]);
|
||||
}
|
||||
/// \brief Get helper chunk size.
|
||||
///
|
||||
Expr *getHelperChunkSize() const {
|
||||
return dyn_cast_or_null<Expr>(ChunkSizes[HELPER_CHUNK_SIZE]);
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
return T->getClauseKind() == OMPC_schedule;
|
||||
}
|
||||
|
||||
StmtRange children() { return StmtRange(&ChunkSize, &ChunkSize + 1); }
|
||||
StmtRange children() {
|
||||
return StmtRange(&ChunkSizes[CHUNK_SIZE], &ChunkSizes[CHUNK_SIZE] + 1);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This represents 'ordered' clause in the '#pragma omp ...' directive.
|
||||
@ -1137,8 +1165,26 @@ class OMPFirstprivateClause : public OMPVarListClause<OMPFirstprivateClause> {
|
||||
/// \endcode
|
||||
/// In this example directive '#pragma omp simd' has clause 'lastprivate'
|
||||
/// with the variables 'a' and 'b'.
|
||||
///
|
||||
class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
|
||||
// There are 4 additional tail-allocated arrays at the end of the class:
|
||||
// 1. Contains list of pseudo variables with the default initialization for
|
||||
// each non-firstprivate variables. Used in codegen for initialization of
|
||||
// lastprivate copies.
|
||||
// 2. List of helper expressions for proper generation of assignment operation
|
||||
// required for lastprivate clause. This list represents private variables
|
||||
// (for arrays, single array element).
|
||||
// 3. List of helper expressions for proper generation of assignment operation
|
||||
// required for lastprivate clause. This list represents original variables
|
||||
// (for arrays, single array element).
|
||||
// 4. List of helper expressions that represents assignment operation:
|
||||
// \code
|
||||
// DstExprs = SrcExprs;
|
||||
// \endcode
|
||||
// Required for proper codegen of final assignment performed by the
|
||||
// lastprivate clause.
|
||||
//
|
||||
friend class OMPClauseReader;
|
||||
|
||||
/// \brief Build clause with number of variables \a N.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
@ -1160,6 +1206,56 @@ class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
|
||||
OMPC_lastprivate, SourceLocation(), SourceLocation(),
|
||||
SourceLocation(), N) {}
|
||||
|
||||
/// \brief Get the list of helper expressions for initialization of private
|
||||
/// copies for lastprivate variables.
|
||||
MutableArrayRef<Expr *> getPrivateCopies() {
|
||||
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getPrivateCopies() const {
|
||||
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent private variables (for arrays, single
|
||||
/// array element) in the final assignment statement performed by the
|
||||
/// lastprivate clause.
|
||||
void setSourceExprs(ArrayRef<Expr *> SrcExprs);
|
||||
|
||||
/// \brief Get the list of helper source expressions.
|
||||
MutableArrayRef<Expr *> getSourceExprs() {
|
||||
return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getSourceExprs() const {
|
||||
return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent original variables (for arrays, single
|
||||
/// array element) in the final assignment statement performed by the
|
||||
/// lastprivate clause.
|
||||
void setDestinationExprs(ArrayRef<Expr *> DstExprs);
|
||||
|
||||
/// \brief Get the list of helper destination expressions.
|
||||
MutableArrayRef<Expr *> getDestinationExprs() {
|
||||
return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getDestinationExprs() const {
|
||||
return llvm::makeArrayRef(getSourceExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper assignment expressions, required for proper
|
||||
/// codegen of the clause. These expressions are assignment expressions that
|
||||
/// assign private copy of the variable to original variable.
|
||||
void setAssignmentOps(ArrayRef<Expr *> AssignmentOps);
|
||||
|
||||
/// \brief Get the list of helper assignment expressions.
|
||||
MutableArrayRef<Expr *> getAssignmentOps() {
|
||||
return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getAssignmentOps() const {
|
||||
return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Creates clause with a list of variables \a VL.
|
||||
///
|
||||
@ -1168,10 +1264,25 @@ class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param VL List of references to the variables.
|
||||
/// \param SrcExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for lastprivate clause. This list represents
|
||||
/// private variables (for arrays, single array element).
|
||||
/// \param DstExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for lastprivate clause. This list represents
|
||||
/// original variables (for arrays, single array element).
|
||||
/// \param AssignmentOps List of helper expressions that represents assignment
|
||||
/// operation:
|
||||
/// \code
|
||||
/// DstExprs = SrcExprs;
|
||||
/// \endcode
|
||||
/// Required for proper codegen of final assignment performed by the
|
||||
/// lastprivate clause.
|
||||
///
|
||||
///
|
||||
static OMPLastprivateClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, ArrayRef<Expr *> VL);
|
||||
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
|
||||
ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps);
|
||||
/// \brief Creates an empty clause with the place for \a N variables.
|
||||
///
|
||||
/// \param C AST context.
|
||||
@ -1179,6 +1290,48 @@ class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
|
||||
///
|
||||
static OMPLastprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
|
||||
typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
|
||||
typedef llvm::iterator_range<helper_expr_const_iterator>
|
||||
helper_expr_const_range;
|
||||
|
||||
/// \brief Set list of helper expressions, required for generation of private
|
||||
/// copies of original lastprivate variables.
|
||||
void setPrivateCopies(ArrayRef<Expr *> PrivateCopies);
|
||||
|
||||
helper_expr_const_range private_copies() const {
|
||||
return helper_expr_const_range(getPrivateCopies().begin(),
|
||||
getPrivateCopies().end());
|
||||
}
|
||||
helper_expr_range private_copies() {
|
||||
return helper_expr_range(getPrivateCopies().begin(),
|
||||
getPrivateCopies().end());
|
||||
}
|
||||
helper_expr_const_range source_exprs() const {
|
||||
return helper_expr_const_range(getSourceExprs().begin(),
|
||||
getSourceExprs().end());
|
||||
}
|
||||
helper_expr_range source_exprs() {
|
||||
return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end());
|
||||
}
|
||||
helper_expr_const_range destination_exprs() const {
|
||||
return helper_expr_const_range(getDestinationExprs().begin(),
|
||||
getDestinationExprs().end());
|
||||
}
|
||||
helper_expr_range destination_exprs() {
|
||||
return helper_expr_range(getDestinationExprs().begin(),
|
||||
getDestinationExprs().end());
|
||||
}
|
||||
helper_expr_const_range assignment_ops() const {
|
||||
return helper_expr_const_range(getAssignmentOps().begin(),
|
||||
getAssignmentOps().end());
|
||||
}
|
||||
helper_expr_range assignment_ops() {
|
||||
return helper_expr_range(getAssignmentOps().begin(),
|
||||
getAssignmentOps().end());
|
||||
}
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
@ -1301,6 +1454,48 @@ class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
|
||||
/// \brief Sets the nested name specifier.
|
||||
void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent LHS expression in the final
|
||||
/// reduction expression performed by the reduction clause.
|
||||
void setLHSExprs(ArrayRef<Expr *> LHSExprs);
|
||||
|
||||
/// \brief Get the list of helper LHS expressions.
|
||||
MutableArrayRef<Expr *> getLHSExprs() {
|
||||
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getLHSExprs() const {
|
||||
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent RHS expression in the final
|
||||
/// reduction expression performed by the reduction clause.
|
||||
/// Also, variables in these expressions are used for proper initialization of
|
||||
/// reduction copies.
|
||||
void setRHSExprs(ArrayRef<Expr *> RHSExprs);
|
||||
|
||||
/// \brief Get the list of helper destination expressions.
|
||||
MutableArrayRef<Expr *> getRHSExprs() {
|
||||
return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getRHSExprs() const {
|
||||
return llvm::makeArrayRef(getLHSExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper reduction expressions, required for proper
|
||||
/// codegen of the clause. These expressions are binary expressions or
|
||||
/// operator/custom reduction call that calculates new value from source
|
||||
/// helper expressions to destination helper expressions.
|
||||
void setReductionOps(ArrayRef<Expr *> ReductionOps);
|
||||
|
||||
/// \brief Get the list of helper reduction expressions.
|
||||
MutableArrayRef<Expr *> getReductionOps() {
|
||||
return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getReductionOps() const {
|
||||
return llvm::makeArrayRef(getRHSExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Creates clause with a list of variables \a VL.
|
||||
///
|
||||
@ -1311,12 +1506,30 @@ class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
|
||||
/// \param VL The variables in the clause.
|
||||
/// \param QualifierLoc The nested-name qualifier with location information
|
||||
/// \param NameInfo The full name info for reduction identifier.
|
||||
/// \param LHSExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyprivate clause. This list represents
|
||||
/// LHSs of the reduction expressions.
|
||||
/// \param RHSExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyprivate clause. This list represents
|
||||
/// RHSs of the reduction expressions.
|
||||
/// Also, variables in these expressions are used for proper initialization of
|
||||
/// reduction copies.
|
||||
/// \param ReductionOps List of helper expressions that represents reduction
|
||||
/// expressions:
|
||||
/// \code
|
||||
/// LHSExprs binop RHSExprs;
|
||||
/// operator binop(LHSExpr, RHSExpr);
|
||||
/// <CutomReduction>(LHSExpr, RHSExpr);
|
||||
/// \endcode
|
||||
/// Required for proper codegen of final reduction operation performed by the
|
||||
/// reduction clause.
|
||||
///
|
||||
static OMPReductionClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
const DeclarationNameInfo &NameInfo);
|
||||
const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> LHSExprs,
|
||||
ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps);
|
||||
/// \brief Creates an empty clause with the place for \a N variables.
|
||||
///
|
||||
/// \param C AST context.
|
||||
@ -1331,6 +1544,33 @@ class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
|
||||
/// \brief Gets the nested name specifier.
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
|
||||
typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
|
||||
typedef llvm::iterator_range<helper_expr_const_iterator>
|
||||
helper_expr_const_range;
|
||||
|
||||
helper_expr_const_range lhs_exprs() const {
|
||||
return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
|
||||
}
|
||||
helper_expr_range lhs_exprs() {
|
||||
return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end());
|
||||
}
|
||||
helper_expr_const_range rhs_exprs() const {
|
||||
return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end());
|
||||
}
|
||||
helper_expr_range rhs_exprs() {
|
||||
return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end());
|
||||
}
|
||||
helper_expr_const_range reduction_ops() const {
|
||||
return helper_expr_const_range(getReductionOps().begin(),
|
||||
getReductionOps().end());
|
||||
}
|
||||
helper_expr_range reduction_ops() {
|
||||
return helper_expr_range(getReductionOps().begin(),
|
||||
getReductionOps().end());
|
||||
}
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
@ -1356,7 +1596,10 @@ class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
/// \brief Sets the linear step for clause.
|
||||
void setStep(Expr *Step) { *varlist_end() = Step; }
|
||||
void setStep(Expr *Step) { *(getFinals().end()) = Step; }
|
||||
|
||||
/// \brief Sets the expression to calculate linear step for clause.
|
||||
void setCalcStep(Expr *CalcStep) { *(getFinals().end() + 1) = CalcStep; }
|
||||
|
||||
/// \brief Build 'linear' clause with given number of variables \a NumVars.
|
||||
///
|
||||
@ -1383,6 +1626,46 @@ class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
|
||||
NumVars),
|
||||
ColonLoc(SourceLocation()) {}
|
||||
|
||||
/// \brief Gets the list of initial values for linear variables.
|
||||
///
|
||||
/// There are NumVars expressions with initial values allocated after the
|
||||
/// varlist, they are followed by NumVars update expressions (used to update
|
||||
/// the linear variable's value on current iteration) and they are followed by
|
||||
/// NumVars final expressions (used to calculate the linear variable's
|
||||
/// value after the loop body). After these lists, there are 2 helper
|
||||
/// expressions - linear step and a helper to calculate it before the
|
||||
/// loop body (used when the linear step is not constant):
|
||||
///
|
||||
/// { Vars[] /* in OMPVarListClause */; Inits[]; Updates[]; Finals[];
|
||||
/// Step; CalcStep; }
|
||||
///
|
||||
MutableArrayRef<Expr *> getInits() {
|
||||
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getInits() const {
|
||||
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Sets the list of update expressions for linear variables.
|
||||
MutableArrayRef<Expr *> getUpdates() {
|
||||
return MutableArrayRef<Expr *>(getInits().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getUpdates() const {
|
||||
return llvm::makeArrayRef(getInits().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Sets the list of final update expressions for linear variables.
|
||||
MutableArrayRef<Expr *> getFinals() {
|
||||
return MutableArrayRef<Expr *>(getUpdates().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getFinals() const {
|
||||
return llvm::makeArrayRef(getUpdates().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Sets the list of the initial values for linear variables.
|
||||
/// \param IL List of expressions.
|
||||
void setInits(ArrayRef<Expr *> IL);
|
||||
|
||||
public:
|
||||
/// \brief Creates clause with a list of variables \a VL and a linear step
|
||||
/// \a Step.
|
||||
@ -1393,11 +1676,14 @@ class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
|
||||
/// \param ColonLoc Location of ':'.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param VL List of references to the variables.
|
||||
/// \param IL List of initial values for the variables.
|
||||
/// \param Step Linear step.
|
||||
/// \param CalcStep Calculation of the linear step.
|
||||
static OMPLinearClause *Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc,
|
||||
ArrayRef<Expr *> VL, Expr *Step);
|
||||
ArrayRef<Expr *> VL, ArrayRef<Expr *> IL,
|
||||
Expr *Step, Expr *CalcStep);
|
||||
|
||||
/// \brief Creates an empty clause with the place for \a NumVars variables.
|
||||
///
|
||||
@ -1412,13 +1698,61 @@ class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
|
||||
/// \brief Returns linear step.
|
||||
Expr *getStep() { return *varlist_end(); }
|
||||
Expr *getStep() { return *(getFinals().end()); }
|
||||
/// \brief Returns linear step.
|
||||
const Expr *getStep() const { return *varlist_end(); }
|
||||
const Expr *getStep() const { return *(getFinals().end()); }
|
||||
/// \brief Returns expression to calculate linear step.
|
||||
Expr *getCalcStep() { return *(getFinals().end() + 1); }
|
||||
/// \brief Returns expression to calculate linear step.
|
||||
const Expr *getCalcStep() const { return *(getFinals().end() + 1); }
|
||||
|
||||
/// \brief Sets the list of update expressions for linear variables.
|
||||
/// \param UL List of expressions.
|
||||
void setUpdates(ArrayRef<Expr *> UL);
|
||||
|
||||
/// \brief Sets the list of final update expressions for linear variables.
|
||||
/// \param FL List of expressions.
|
||||
void setFinals(ArrayRef<Expr *> FL);
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator inits_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator inits_const_iterator;
|
||||
typedef llvm::iterator_range<inits_iterator> inits_range;
|
||||
typedef llvm::iterator_range<inits_const_iterator> inits_const_range;
|
||||
|
||||
inits_range inits() {
|
||||
return inits_range(getInits().begin(), getInits().end());
|
||||
}
|
||||
inits_const_range inits() const {
|
||||
return inits_const_range(getInits().begin(), getInits().end());
|
||||
}
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator updates_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator updates_const_iterator;
|
||||
typedef llvm::iterator_range<updates_iterator> updates_range;
|
||||
typedef llvm::iterator_range<updates_const_iterator> updates_const_range;
|
||||
|
||||
updates_range updates() {
|
||||
return updates_range(getUpdates().begin(), getUpdates().end());
|
||||
}
|
||||
updates_const_range updates() const {
|
||||
return updates_const_range(getUpdates().begin(), getUpdates().end());
|
||||
}
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator finals_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator finals_const_iterator;
|
||||
typedef llvm::iterator_range<finals_iterator> finals_range;
|
||||
typedef llvm::iterator_range<finals_const_iterator> finals_const_range;
|
||||
|
||||
finals_range finals() {
|
||||
return finals_range(getFinals().begin(), getFinals().end());
|
||||
}
|
||||
finals_const_range finals() const {
|
||||
return finals_const_range(getFinals().begin(), getFinals().end());
|
||||
}
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end() + 1));
|
||||
reinterpret_cast<Stmt **>(getFinals().end() + 2));
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
@ -1520,6 +1854,20 @@ class OMPAlignedClause : public OMPVarListClause<OMPAlignedClause> {
|
||||
/// with the variables 'a' and 'b'.
|
||||
///
|
||||
class OMPCopyinClause : public OMPVarListClause<OMPCopyinClause> {
|
||||
// Class has 3 additional tail allocated arrays:
|
||||
// 1. List of helper expressions for proper generation of assignment operation
|
||||
// required for copyin clause. This list represents sources.
|
||||
// 2. List of helper expressions for proper generation of assignment operation
|
||||
// required for copyin clause. This list represents destinations.
|
||||
// 3. List of helper expressions that represents assignment operation:
|
||||
// \code
|
||||
// DstExprs = SrcExprs;
|
||||
// \endcode
|
||||
// Required for proper codegen of propagation of master's thread values of
|
||||
// threadprivate variables to local instances of that variables in other
|
||||
// implicit threads.
|
||||
|
||||
friend class OMPClauseReader;
|
||||
/// \brief Build clause with number of variables \a N.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
@ -1541,6 +1889,46 @@ class OMPCopyinClause : public OMPVarListClause<OMPCopyinClause> {
|
||||
SourceLocation(), SourceLocation(),
|
||||
N) {}
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent source expression in the final
|
||||
/// assignment statement performed by the copyin clause.
|
||||
void setSourceExprs(ArrayRef<Expr *> SrcExprs);
|
||||
|
||||
/// \brief Get the list of helper source expressions.
|
||||
MutableArrayRef<Expr *> getSourceExprs() {
|
||||
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getSourceExprs() const {
|
||||
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent destination expression in the final
|
||||
/// assignment statement performed by the copyin clause.
|
||||
void setDestinationExprs(ArrayRef<Expr *> DstExprs);
|
||||
|
||||
/// \brief Get the list of helper destination expressions.
|
||||
MutableArrayRef<Expr *> getDestinationExprs() {
|
||||
return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getDestinationExprs() const {
|
||||
return llvm::makeArrayRef(getSourceExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper assignment expressions, required for proper
|
||||
/// codegen of the clause. These expressions are assignment expressions that
|
||||
/// assign source helper expressions to destination helper expressions
|
||||
/// correspondingly.
|
||||
void setAssignmentOps(ArrayRef<Expr *> AssignmentOps);
|
||||
|
||||
/// \brief Get the list of helper assignment expressions.
|
||||
MutableArrayRef<Expr *> getAssignmentOps() {
|
||||
return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getAssignmentOps() const {
|
||||
return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Creates clause with a list of variables \a VL.
|
||||
///
|
||||
@ -1549,10 +1937,25 @@ class OMPCopyinClause : public OMPVarListClause<OMPCopyinClause> {
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param VL List of references to the variables.
|
||||
/// \param SrcExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyin clause. This list represents
|
||||
/// sources.
|
||||
/// \param DstExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyin clause. This list represents
|
||||
/// destinations.
|
||||
/// \param AssignmentOps List of helper expressions that represents assignment
|
||||
/// operation:
|
||||
/// \code
|
||||
/// DstExprs = SrcExprs;
|
||||
/// \endcode
|
||||
/// Required for proper codegen of propagation of master's thread values of
|
||||
/// threadprivate variables to local instances of that variables in other
|
||||
/// implicit threads.
|
||||
///
|
||||
static OMPCopyinClause *Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, ArrayRef<Expr *> VL);
|
||||
static OMPCopyinClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
|
||||
ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps);
|
||||
/// \brief Creates an empty clause with \a N variables.
|
||||
///
|
||||
/// \param C AST context.
|
||||
@ -1560,6 +1963,36 @@ class OMPCopyinClause : public OMPVarListClause<OMPCopyinClause> {
|
||||
///
|
||||
static OMPCopyinClause *CreateEmpty(const ASTContext &C, unsigned N);
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
|
||||
typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
|
||||
typedef llvm::iterator_range<helper_expr_const_iterator>
|
||||
helper_expr_const_range;
|
||||
|
||||
helper_expr_const_range source_exprs() const {
|
||||
return helper_expr_const_range(getSourceExprs().begin(),
|
||||
getSourceExprs().end());
|
||||
}
|
||||
helper_expr_range source_exprs() {
|
||||
return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end());
|
||||
}
|
||||
helper_expr_const_range destination_exprs() const {
|
||||
return helper_expr_const_range(getDestinationExprs().begin(),
|
||||
getDestinationExprs().end());
|
||||
}
|
||||
helper_expr_range destination_exprs() {
|
||||
return helper_expr_range(getDestinationExprs().begin(),
|
||||
getDestinationExprs().end());
|
||||
}
|
||||
helper_expr_const_range assignment_ops() const {
|
||||
return helper_expr_const_range(getAssignmentOps().begin(),
|
||||
getAssignmentOps().end());
|
||||
}
|
||||
helper_expr_range assignment_ops() {
|
||||
return helper_expr_range(getAssignmentOps().begin(),
|
||||
getAssignmentOps().end());
|
||||
}
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
@ -1580,6 +2013,7 @@ class OMPCopyinClause : public OMPVarListClause<OMPCopyinClause> {
|
||||
/// with the variables 'a' and 'b'.
|
||||
///
|
||||
class OMPCopyprivateClause : public OMPVarListClause<OMPCopyprivateClause> {
|
||||
friend class OMPClauseReader;
|
||||
/// \brief Build clause with number of variables \a N.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
@ -1601,6 +2035,46 @@ class OMPCopyprivateClause : public OMPVarListClause<OMPCopyprivateClause> {
|
||||
OMPC_copyprivate, SourceLocation(), SourceLocation(),
|
||||
SourceLocation(), N) {}
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent source expression in the final
|
||||
/// assignment statement performed by the copyprivate clause.
|
||||
void setSourceExprs(ArrayRef<Expr *> SrcExprs);
|
||||
|
||||
/// \brief Get the list of helper source expressions.
|
||||
MutableArrayRef<Expr *> getSourceExprs() {
|
||||
return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getSourceExprs() const {
|
||||
return llvm::makeArrayRef(varlist_end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper expressions, required for proper codegen of the
|
||||
/// clause. These expressions represent destination expression in the final
|
||||
/// assignment statement performed by the copyprivate clause.
|
||||
void setDestinationExprs(ArrayRef<Expr *> DstExprs);
|
||||
|
||||
/// \brief Get the list of helper destination expressions.
|
||||
MutableArrayRef<Expr *> getDestinationExprs() {
|
||||
return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getDestinationExprs() const {
|
||||
return llvm::makeArrayRef(getSourceExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
/// \brief Set list of helper assignment expressions, required for proper
|
||||
/// codegen of the clause. These expressions are assignment expressions that
|
||||
/// assign source helper expressions to destination helper expressions
|
||||
/// correspondingly.
|
||||
void setAssignmentOps(ArrayRef<Expr *> AssignmentOps);
|
||||
|
||||
/// \brief Get the list of helper assignment expressions.
|
||||
MutableArrayRef<Expr *> getAssignmentOps() {
|
||||
return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size());
|
||||
}
|
||||
ArrayRef<const Expr *> getAssignmentOps() const {
|
||||
return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size());
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Creates clause with a list of variables \a VL.
|
||||
///
|
||||
@ -1609,10 +2083,24 @@ class OMPCopyprivateClause : public OMPVarListClause<OMPCopyprivateClause> {
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param VL List of references to the variables.
|
||||
/// \param SrcExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyprivate clause. This list represents
|
||||
/// sources.
|
||||
/// \param DstExprs List of helper expressions for proper generation of
|
||||
/// assignment operation required for copyprivate clause. This list represents
|
||||
/// destinations.
|
||||
/// \param AssignmentOps List of helper expressions that represents assignment
|
||||
/// operation:
|
||||
/// \code
|
||||
/// DstExprs = SrcExprs;
|
||||
/// \endcode
|
||||
/// Required for proper codegen of final assignment performed by the
|
||||
/// copyprivate clause.
|
||||
///
|
||||
static OMPCopyprivateClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, ArrayRef<Expr *> VL);
|
||||
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
|
||||
ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps);
|
||||
/// \brief Creates an empty clause with \a N variables.
|
||||
///
|
||||
/// \param C AST context.
|
||||
@ -1620,6 +2108,36 @@ class OMPCopyprivateClause : public OMPVarListClause<OMPCopyprivateClause> {
|
||||
///
|
||||
static OMPCopyprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
|
||||
|
||||
typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
|
||||
typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
|
||||
typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
|
||||
typedef llvm::iterator_range<helper_expr_const_iterator>
|
||||
helper_expr_const_range;
|
||||
|
||||
helper_expr_const_range source_exprs() const {
|
||||
return helper_expr_const_range(getSourceExprs().begin(),
|
||||
getSourceExprs().end());
|
||||
}
|
||||
helper_expr_range source_exprs() {
|
||||
return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end());
|
||||
}
|
||||
helper_expr_const_range destination_exprs() const {
|
||||
return helper_expr_const_range(getDestinationExprs().begin(),
|
||||
getDestinationExprs().end());
|
||||
}
|
||||
helper_expr_range destination_exprs() {
|
||||
return helper_expr_range(getDestinationExprs().begin(),
|
||||
getDestinationExprs().end());
|
||||
}
|
||||
helper_expr_const_range assignment_ops() const {
|
||||
return helper_expr_const_range(getAssignmentOps().begin(),
|
||||
getAssignmentOps().end());
|
||||
}
|
||||
helper_expr_range assignment_ops() {
|
||||
return helper_expr_range(getAssignmentOps().begin(),
|
||||
getAssignmentOps().end());
|
||||
}
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
|
@ -159,12 +159,12 @@ class ASTRecordLayout {
|
||||
const BaseOffsetsMapTy& BaseOffsets,
|
||||
const VBaseOffsetsMapTy& VBaseOffsets);
|
||||
|
||||
~ASTRecordLayout() {}
|
||||
~ASTRecordLayout() = default;
|
||||
|
||||
void Destroy(ASTContext &Ctx);
|
||||
|
||||
ASTRecordLayout(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
|
||||
ASTRecordLayout(const ASTRecordLayout &) = delete;
|
||||
void operator=(const ASTRecordLayout &) = delete;
|
||||
public:
|
||||
|
||||
/// getAlignment - Get the record alignment in characters.
|
||||
|
@ -857,7 +857,7 @@ template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE,
|
||||
const LambdaCapture *C) {
|
||||
if (C->isInitCapture())
|
||||
if (LE->isInitCapture(C))
|
||||
TRY_TO(TraverseDecl(C->getCapturedVar()));
|
||||
return true;
|
||||
}
|
||||
@ -1356,6 +1356,8 @@ DEF_TRAVERSE_DECL(
|
||||
// D->getAnonymousNamespace().
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ExternCContextDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
|
||||
// We shouldn't traverse an aliased namespace, since it will be
|
||||
// defined (and, therefore, traversed) somewhere else.
|
||||
@ -2032,12 +2034,20 @@ DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
|
||||
// to the syntactic form.
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
|
||||
if (InitListExpr *Syn = S->getSyntacticForm())
|
||||
S = Syn;
|
||||
TRY_TO(WalkUpFromInitListExpr(S));
|
||||
// All we need are the default actions. FIXME: use a helper function.
|
||||
for (Stmt::child_range range = S->children(); range; ++range) {
|
||||
TRY_TO(TraverseStmt(*range));
|
||||
InitListExpr *Syn = S->isSemanticForm() ? S->getSyntacticForm() : S;
|
||||
if (Syn) {
|
||||
TRY_TO(WalkUpFromInitListExpr(Syn));
|
||||
// All we need are the default actions. FIXME: use a helper function.
|
||||
for (Stmt::child_range range = Syn->children(); range; ++range) {
|
||||
TRY_TO(TraverseStmt(*range));
|
||||
}
|
||||
}
|
||||
InitListExpr *Sem = S->isSemanticForm() ? S : S->getSemanticForm();
|
||||
if (Sem) {
|
||||
TRY_TO(WalkUpFromInitListExpr(Sem));
|
||||
for (Stmt::child_range range = Sem->children(); range; ++range) {
|
||||
TRY_TO(TraverseStmt(*range));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -2455,6 +2465,7 @@ template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getChunkSize()));
|
||||
TRY_TO(TraverseStmt(C->getHelperChunkSize()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2539,6 +2550,18 @@ template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
|
||||
OMPLastprivateClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->private_copies()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->source_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->destination_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->assignment_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2551,7 +2574,17 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
|
||||
TRY_TO(TraverseStmt(C->getStep()));
|
||||
TRY_TO(TraverseStmt(C->getCalcStep()));
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->inits()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->updates()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->finals()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2565,6 +2598,15 @@ bool RecursiveASTVisitor<Derived>::VisitOMPAlignedClause(OMPAlignedClause *C) {
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->source_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->destination_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->assignment_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2572,6 +2614,15 @@ template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
|
||||
OMPCopyprivateClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->source_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->destination_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->assignment_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2581,6 +2632,15 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
for (auto *E : C->lhs_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->rhs_exprs()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
for (auto *E : C->reduction_ops()) {
|
||||
TRY_TO(TraverseStmt(E));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,13 @@ class Redeclarable {
|
||||
}
|
||||
|
||||
void markIncomplete() { Next.get<KnownLatest>().markIncomplete(); }
|
||||
|
||||
Decl *getLatestNotUpdated() const {
|
||||
assert(NextIsLatest() && "expected a canonical decl");
|
||||
if (Next.is<NotKnownLatest>())
|
||||
return nullptr;
|
||||
return Next.get<KnownLatest>().getNotUpdated();
|
||||
}
|
||||
};
|
||||
|
||||
static DeclLink PreviousDeclLink(decl_type *D) {
|
||||
@ -114,14 +121,15 @@ class Redeclarable {
|
||||
///
|
||||
/// If there is only one declaration, it is <pointer to self, true>
|
||||
DeclLink RedeclLink;
|
||||
decl_type *First;
|
||||
|
||||
decl_type *getNextRedeclaration() const {
|
||||
return RedeclLink.getNext(static_cast<const decl_type *>(this));
|
||||
}
|
||||
|
||||
public:
|
||||
Redeclarable(const ASTContext &Ctx)
|
||||
: RedeclLink(LatestDeclLink(Ctx)) {}
|
||||
Redeclarable(const ASTContext &Ctx)
|
||||
: RedeclLink(LatestDeclLink(Ctx)), First(static_cast<decl_type *>(this)) {}
|
||||
|
||||
/// \brief Return the previous declaration of this declaration or NULL if this
|
||||
/// is the first declaration.
|
||||
@ -137,21 +145,11 @@ class Redeclarable {
|
||||
|
||||
/// \brief Return the first declaration of this declaration or itself if this
|
||||
/// is the only declaration.
|
||||
decl_type *getFirstDecl() {
|
||||
decl_type *D = static_cast<decl_type*>(this);
|
||||
while (D->getPreviousDecl())
|
||||
D = D->getPreviousDecl();
|
||||
return D;
|
||||
}
|
||||
decl_type *getFirstDecl() { return First; }
|
||||
|
||||
/// \brief Return the first declaration of this declaration or itself if this
|
||||
/// is the only declaration.
|
||||
const decl_type *getFirstDecl() const {
|
||||
const decl_type *D = static_cast<const decl_type*>(this);
|
||||
while (D->getPreviousDecl())
|
||||
D = D->getPreviousDecl();
|
||||
return D;
|
||||
}
|
||||
const decl_type *getFirstDecl() const { return First; }
|
||||
|
||||
/// \brief True if this is the first declaration in its redeclaration chain.
|
||||
bool isFirstDecl() const { return RedeclLink.NextIsLatest(); }
|
||||
|
@ -58,7 +58,9 @@ namespace clang {
|
||||
class Stmt;
|
||||
class Expr;
|
||||
|
||||
class ExprIterator {
|
||||
class ExprIterator : public std::iterator<std::forward_iterator_tag,
|
||||
Expr *&, ptrdiff_t,
|
||||
Expr *&, Expr *&> {
|
||||
Stmt** I;
|
||||
public:
|
||||
ExprIterator(Stmt** i) : I(i) {}
|
||||
@ -77,7 +79,10 @@ namespace clang {
|
||||
bool operator>=(const ExprIterator& R) const { return I >= R.I; }
|
||||
};
|
||||
|
||||
class ConstExprIterator {
|
||||
class ConstExprIterator : public std::iterator<std::forward_iterator_tag,
|
||||
const Expr *&, ptrdiff_t,
|
||||
const Expr *&,
|
||||
const Expr *&> {
|
||||
const Stmt * const *I;
|
||||
public:
|
||||
ConstExprIterator(const Stmt * const *i) : I(i) {}
|
||||
@ -101,7 +106,7 @@ namespace clang {
|
||||
|
||||
/// Stmt - This represents one statement.
|
||||
///
|
||||
class Stmt {
|
||||
class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt {
|
||||
public:
|
||||
enum StmtClass {
|
||||
NoStmtClass = 0,
|
||||
@ -287,9 +292,6 @@ class Stmt {
|
||||
};
|
||||
|
||||
union {
|
||||
// FIXME: this is wasteful on 64-bit platforms.
|
||||
void *Aligner;
|
||||
|
||||
StmtBitfields StmtBits;
|
||||
CompoundStmtBitfields CompoundStmtBits;
|
||||
ExprBitfields ExprBits;
|
||||
@ -341,13 +343,12 @@ class Stmt {
|
||||
|
||||
protected:
|
||||
/// \brief Construct an empty statement.
|
||||
explicit Stmt(StmtClass SC, EmptyShell) {
|
||||
StmtBits.sClass = SC;
|
||||
if (StatisticsEnabled) Stmt::addStmtClass(SC);
|
||||
}
|
||||
explicit Stmt(StmtClass SC, EmptyShell) : Stmt(SC) {}
|
||||
|
||||
public:
|
||||
Stmt(StmtClass SC) {
|
||||
static_assert(sizeof(*this) % llvm::AlignOf<void *>::Alignment == 0,
|
||||
"Insufficient alignment!");
|
||||
StmtBits.sClass = SC;
|
||||
if (StatisticsEnabled) Stmt::addStmtClass(SC);
|
||||
}
|
||||
@ -374,6 +375,7 @@ class Stmt {
|
||||
void dump() const;
|
||||
void dump(SourceManager &SM) const;
|
||||
void dump(raw_ostream &OS, SourceManager &SM) const;
|
||||
void dump(raw_ostream &OS) const;
|
||||
|
||||
/// dumpColor - same as dump(), but forces color highlighting.
|
||||
void dumpColor() const;
|
||||
@ -583,6 +585,7 @@ class CompoundStmt : public Stmt {
|
||||
body_range body() { return body_range(body_begin(), body_end()); }
|
||||
body_iterator body_begin() { return Body; }
|
||||
body_iterator body_end() { return Body + size(); }
|
||||
Stmt *body_front() { return !body_empty() ? Body[0] : nullptr; }
|
||||
Stmt *body_back() { return !body_empty() ? Body[size()-1] : nullptr; }
|
||||
|
||||
void setLastStmt(Stmt *S) {
|
||||
@ -598,6 +601,9 @@ class CompoundStmt : public Stmt {
|
||||
}
|
||||
const_body_iterator body_begin() const { return Body; }
|
||||
const_body_iterator body_end() const { return Body + size(); }
|
||||
const Stmt *body_front() const {
|
||||
return !body_empty() ? Body[0] : nullptr;
|
||||
}
|
||||
const Stmt *body_back() const {
|
||||
return !body_empty() ? Body[size() - 1] : nullptr;
|
||||
}
|
||||
@ -684,10 +690,10 @@ class SwitchCase : public Stmt {
|
||||
};
|
||||
|
||||
class CaseStmt : public SwitchCase {
|
||||
SourceLocation EllipsisLoc;
|
||||
enum { LHS, RHS, SUBSTMT, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for
|
||||
// GNU "case 1 ... 4" extension
|
||||
SourceLocation EllipsisLoc;
|
||||
public:
|
||||
CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
|
||||
SourceLocation ellipsisLoc, SourceLocation colonLoc)
|
||||
@ -784,12 +790,16 @@ inline SourceLocation SwitchCase::getLocEnd() const {
|
||||
/// foo: return;
|
||||
///
|
||||
class LabelStmt : public Stmt {
|
||||
SourceLocation IdentLoc;
|
||||
LabelDecl *TheDecl;
|
||||
Stmt *SubStmt;
|
||||
SourceLocation IdentLoc;
|
||||
|
||||
public:
|
||||
LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt)
|
||||
: Stmt(LabelStmtClass), TheDecl(D), SubStmt(substmt), IdentLoc(IL) {
|
||||
: Stmt(LabelStmtClass), IdentLoc(IL), TheDecl(D), SubStmt(substmt) {
|
||||
static_assert(sizeof(LabelStmt) ==
|
||||
2 * sizeof(SourceLocation) + 2 * sizeof(void *),
|
||||
"LabelStmt too big");
|
||||
}
|
||||
|
||||
// \brief Build an empty label statement.
|
||||
@ -939,16 +949,14 @@ class IfStmt : public Stmt {
|
||||
/// SwitchStmt - This represents a 'switch' stmt.
|
||||
///
|
||||
class SwitchStmt : public Stmt {
|
||||
SourceLocation SwitchLoc;
|
||||
enum { VAR, COND, BODY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
// This points to a linked list of case and default statements.
|
||||
SwitchCase *FirstCase;
|
||||
SourceLocation SwitchLoc;
|
||||
|
||||
/// If the SwitchStmt is a switch on an enum value, this records whether
|
||||
/// all the enum values were covered by CaseStmts. This value is meant to
|
||||
/// be a hint for possible clients.
|
||||
unsigned AllEnumCasesCovered : 1;
|
||||
// This points to a linked list of case and default statements and, if the
|
||||
// SwitchStmt is a switch on an enum value, records whether all the enum
|
||||
// values were covered by CaseStmts. The coverage information value is meant
|
||||
// to be a hint for possible clients.
|
||||
llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase;
|
||||
|
||||
public:
|
||||
SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
|
||||
@ -976,16 +984,16 @@ class SwitchStmt : public Stmt {
|
||||
|
||||
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
|
||||
const Stmt *getBody() const { return SubExprs[BODY]; }
|
||||
const SwitchCase *getSwitchCaseList() const { return FirstCase; }
|
||||
const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); }
|
||||
|
||||
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);}
|
||||
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
|
||||
Stmt *getBody() { return SubExprs[BODY]; }
|
||||
void setBody(Stmt *S) { SubExprs[BODY] = S; }
|
||||
SwitchCase *getSwitchCaseList() { return FirstCase; }
|
||||
SwitchCase *getSwitchCaseList() { return FirstCase.getPointer(); }
|
||||
|
||||
/// \brief Set the case list for this switch statement.
|
||||
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
|
||||
void setSwitchCaseList(SwitchCase *SC) { FirstCase.setPointer(SC); }
|
||||
|
||||
SourceLocation getSwitchLoc() const { return SwitchLoc; }
|
||||
void setSwitchLoc(SourceLocation L) { SwitchLoc = L; }
|
||||
@ -997,21 +1005,17 @@ class SwitchStmt : public Stmt {
|
||||
void addSwitchCase(SwitchCase *SC) {
|
||||
assert(!SC->getNextSwitchCase()
|
||||
&& "case/default already added to a switch");
|
||||
SC->setNextSwitchCase(FirstCase);
|
||||
FirstCase = SC;
|
||||
SC->setNextSwitchCase(FirstCase.getPointer());
|
||||
FirstCase.setPointer(SC);
|
||||
}
|
||||
|
||||
/// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a
|
||||
/// switch over an enum value then all cases have been explicitly covered.
|
||||
void setAllEnumCasesCovered() {
|
||||
AllEnumCasesCovered = 1;
|
||||
}
|
||||
void setAllEnumCasesCovered() { FirstCase.setInt(true); }
|
||||
|
||||
/// Returns true if the SwitchStmt is a switch of an enum value and all cases
|
||||
/// have been explicitly covered.
|
||||
bool isAllEnumCasesCovered() const {
|
||||
return (bool) AllEnumCasesCovered;
|
||||
}
|
||||
bool isAllEnumCasesCovered() const { return FirstCase.getInt(); }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY {
|
||||
@ -1032,9 +1036,9 @@ class SwitchStmt : public Stmt {
|
||||
/// WhileStmt - This represents a 'while' stmt.
|
||||
///
|
||||
class WhileStmt : public Stmt {
|
||||
SourceLocation WhileLoc;
|
||||
enum { VAR, COND, BODY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
SourceLocation WhileLoc;
|
||||
public:
|
||||
WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
|
||||
SourceLocation WL);
|
||||
@ -1087,9 +1091,9 @@ class WhileStmt : public Stmt {
|
||||
/// DoStmt - This represents a 'do/while' stmt.
|
||||
///
|
||||
class DoStmt : public Stmt {
|
||||
SourceLocation DoLoc;
|
||||
enum { BODY, COND, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
SourceLocation DoLoc;
|
||||
SourceLocation WhileLoc;
|
||||
SourceLocation RParenLoc; // Location of final ')' in do stmt condition.
|
||||
|
||||
@ -1138,9 +1142,9 @@ class DoStmt : public Stmt {
|
||||
/// specified in the source.
|
||||
///
|
||||
class ForStmt : public Stmt {
|
||||
SourceLocation ForLoc;
|
||||
enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt.
|
||||
SourceLocation ForLoc;
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
@ -1310,8 +1314,12 @@ class ContinueStmt : public Stmt {
|
||||
///
|
||||
class BreakStmt : public Stmt {
|
||||
SourceLocation BreakLoc;
|
||||
|
||||
public:
|
||||
BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {}
|
||||
BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {
|
||||
static_assert(sizeof(BreakStmt) == 2 * sizeof(SourceLocation),
|
||||
"BreakStmt too large");
|
||||
}
|
||||
|
||||
/// \brief Build an empty break statement.
|
||||
explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { }
|
||||
@ -1341,18 +1349,16 @@ class BreakStmt : public Stmt {
|
||||
/// depend on the return type of the function and the presence of an argument.
|
||||
///
|
||||
class ReturnStmt : public Stmt {
|
||||
Stmt *RetExpr;
|
||||
SourceLocation RetLoc;
|
||||
Stmt *RetExpr;
|
||||
const VarDecl *NRVOCandidate;
|
||||
|
||||
public:
|
||||
ReturnStmt(SourceLocation RL)
|
||||
: Stmt(ReturnStmtClass), RetExpr(nullptr), RetLoc(RL),
|
||||
NRVOCandidate(nullptr) {}
|
||||
explicit ReturnStmt(SourceLocation RL) : ReturnStmt(RL, nullptr, nullptr) {}
|
||||
|
||||
ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
|
||||
: Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL),
|
||||
NRVOCandidate(NRVOCandidate) {}
|
||||
: Stmt(ReturnStmtClass), RetLoc(RL), RetExpr((Stmt *)E),
|
||||
NRVOCandidate(NRVOCandidate) {}
|
||||
|
||||
/// \brief Build an empty return expression.
|
||||
explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { }
|
||||
|
@ -126,11 +126,11 @@ class CXXTryStmt : public Stmt {
|
||||
/// analysis of the constituent components. The original syntactic components
|
||||
/// can be extracted using getLoopVariable and getRangeInit.
|
||||
class CXXForRangeStmt : public Stmt {
|
||||
SourceLocation ForLoc;
|
||||
enum { RANGE, BEGINEND, COND, INC, LOOPVAR, BODY, END };
|
||||
// SubExprs[RANGE] is an expression or declstmt.
|
||||
// SubExprs[COND] and SubExprs[INC] are expressions.
|
||||
Stmt *SubExprs[END];
|
||||
SourceLocation ForLoc;
|
||||
SourceLocation ColonLoc;
|
||||
SourceLocation RParenLoc;
|
||||
public:
|
||||
|
@ -148,7 +148,7 @@ struct StmtRange : std::pair<StmtIterator,StmtIterator> {
|
||||
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
LLVM_EXPLICIT operator bool() const { return !empty(); }
|
||||
explicit operator bool() const { return !empty(); }
|
||||
|
||||
Stmt *operator->() const { return first.operator->(); }
|
||||
Stmt *&operator*() const { return first.operator*(); }
|
||||
@ -191,7 +191,7 @@ struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
|
||||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
LLVM_EXPLICIT operator bool() const { return !empty(); }
|
||||
explicit operator bool() const { return !empty(); }
|
||||
|
||||
const Stmt *operator->() const { return first.operator->(); }
|
||||
const Stmt *operator*() const { return first.operator*(); }
|
||||
|
@ -118,12 +118,13 @@ class ObjCAtCatchStmt : public Stmt {
|
||||
|
||||
/// \brief Represents Objective-C's \@finally statement
|
||||
class ObjCAtFinallyStmt : public Stmt {
|
||||
Stmt *AtFinallyStmt;
|
||||
SourceLocation AtFinallyLoc;
|
||||
Stmt *AtFinallyStmt;
|
||||
|
||||
public:
|
||||
ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt)
|
||||
: Stmt(ObjCAtFinallyStmtClass),
|
||||
AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {}
|
||||
: Stmt(ObjCAtFinallyStmtClass), AtFinallyLoc(atFinallyLoc),
|
||||
AtFinallyStmt(atFinallyStmt) {}
|
||||
|
||||
explicit ObjCAtFinallyStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAtFinallyStmtClass, Empty) { }
|
||||
@ -260,9 +261,9 @@ class ObjCAtTryStmt : public Stmt {
|
||||
/// \endcode
|
||||
class ObjCAtSynchronizedStmt : public Stmt {
|
||||
private:
|
||||
SourceLocation AtSynchronizedLoc;
|
||||
enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
|
||||
Stmt* SubStmts[END_EXPR];
|
||||
SourceLocation AtSynchronizedLoc;
|
||||
|
||||
public:
|
||||
ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
|
||||
@ -310,8 +311,9 @@ class ObjCAtSynchronizedStmt : public Stmt {
|
||||
|
||||
/// \brief Represents Objective-C's \@throw statement.
|
||||
class ObjCAtThrowStmt : public Stmt {
|
||||
Stmt *Throw;
|
||||
SourceLocation AtThrowLoc;
|
||||
Stmt *Throw;
|
||||
|
||||
public:
|
||||
ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr)
|
||||
: Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) {
|
||||
@ -341,13 +343,12 @@ class ObjCAtThrowStmt : public Stmt {
|
||||
|
||||
/// \brief Represents Objective-C's \@autoreleasepool Statement
|
||||
class ObjCAutoreleasePoolStmt : public Stmt {
|
||||
Stmt *SubStmt;
|
||||
SourceLocation AtLoc;
|
||||
Stmt *SubStmt;
|
||||
|
||||
public:
|
||||
ObjCAutoreleasePoolStmt(SourceLocation atLoc,
|
||||
Stmt *subStmt)
|
||||
: Stmt(ObjCAutoreleasePoolStmtClass),
|
||||
SubStmt(subStmt), AtLoc(atLoc) {}
|
||||
ObjCAutoreleasePoolStmt(SourceLocation atLoc, Stmt *subStmt)
|
||||
: Stmt(ObjCAutoreleasePoolStmtClass), AtLoc(atLoc), SubStmt(subStmt) {}
|
||||
|
||||
explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) :
|
||||
Stmt(ObjCAutoreleasePoolStmtClass, Empty) { }
|
||||
|
@ -95,6 +95,7 @@ class OMPExecutableDirective : public Stmt {
|
||||
/// This iterator visits only those declarations that meet some run-time
|
||||
/// criteria.
|
||||
template <class FilterPredicate> class filtered_clause_iterator {
|
||||
protected:
|
||||
ArrayRef<OMPClause *>::const_iterator Current;
|
||||
ArrayRef<OMPClause *>::const_iterator End;
|
||||
FilterPredicate Pred;
|
||||
@ -107,7 +108,7 @@ class OMPExecutableDirective : public Stmt {
|
||||
typedef const OMPClause *value_type;
|
||||
filtered_clause_iterator() : Current(), End() {}
|
||||
filtered_clause_iterator(ArrayRef<OMPClause *> Arr, FilterPredicate Pred)
|
||||
: Current(Arr.begin()), End(Arr.end()), Pred(Pred) {
|
||||
: Current(Arr.begin()), End(Arr.end()), Pred(std::move(Pred)) {
|
||||
SkipToNextClause();
|
||||
}
|
||||
value_type operator*() const { return *Current; }
|
||||
@ -125,9 +126,25 @@ class OMPExecutableDirective : public Stmt {
|
||||
}
|
||||
|
||||
bool operator!() { return Current == End; }
|
||||
operator bool() { return Current != End; }
|
||||
explicit operator bool() { return Current != End; }
|
||||
bool empty() const { return Current == End; }
|
||||
};
|
||||
|
||||
template <typename Fn>
|
||||
filtered_clause_iterator<Fn> getFilteredClauses(Fn &&fn) const {
|
||||
return filtered_clause_iterator<Fn>(clauses(), std::move(fn));
|
||||
}
|
||||
struct ClauseKindFilter {
|
||||
OpenMPClauseKind Kind;
|
||||
bool operator()(const OMPClause *clause) const {
|
||||
return clause->getClauseKind() == Kind;
|
||||
}
|
||||
};
|
||||
filtered_clause_iterator<ClauseKindFilter>
|
||||
getClausesOfKind(OpenMPClauseKind Kind) const {
|
||||
return getFilteredClauses(ClauseKindFilter{Kind});
|
||||
}
|
||||
|
||||
/// \brief Gets a single clause of the specified kind \a K associated with the
|
||||
/// current directive iff there is only one clause of this kind (and assertion
|
||||
/// is fired if there is more than one clause is associated with the
|
||||
@ -410,6 +427,8 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
Expr *IterationVarRef;
|
||||
/// \brief Loop last iteration number.
|
||||
Expr *LastIteration;
|
||||
/// \brief Loop number of iterations.
|
||||
Expr *NumIterations;
|
||||
/// \brief Calculation of last iteration.
|
||||
Expr *CalcLastIteration;
|
||||
/// \brief Loop pre-condition.
|
||||
@ -447,8 +466,9 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
/// worksharing ones).
|
||||
bool builtAll() {
|
||||
return IterationVarRef != nullptr && LastIteration != nullptr &&
|
||||
PreCond != nullptr && Cond != nullptr &&
|
||||
SeparatedCond != nullptr && Init != nullptr && Inc != nullptr;
|
||||
NumIterations != nullptr && PreCond != nullptr &&
|
||||
Cond != nullptr && SeparatedCond != nullptr && Init != nullptr &&
|
||||
Inc != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Initialize all the fields to null.
|
||||
@ -1557,6 +1577,26 @@ class OMPOrderedDirective : public OMPExecutableDirective {
|
||||
///
|
||||
class OMPAtomicDirective : public OMPExecutableDirective {
|
||||
friend class ASTStmtReader;
|
||||
/// \brief Used for 'atomic update' or 'atomic capture' constructs. They may
|
||||
/// have atomic expressions of forms
|
||||
/// \code
|
||||
/// x = x binop expr;
|
||||
/// x = expr binop x;
|
||||
/// \endcode
|
||||
/// This field is true for the first form of the expression and false for the
|
||||
/// second. Required for correct codegen of non-associative operations (like
|
||||
/// << or >>).
|
||||
bool IsXLHSInRHSPart;
|
||||
/// \brief Used for 'atomic update' or 'atomic capture' constructs. They may
|
||||
/// have atomic expressions of forms
|
||||
/// \code
|
||||
/// v = x; <update x>;
|
||||
/// <update x>; v = x;
|
||||
/// \endcode
|
||||
/// This field is true for the first(postfix) form of the expression and false
|
||||
/// otherwise.
|
||||
bool IsPostfixUpdate;
|
||||
|
||||
/// \brief Build directive with the given start and end location.
|
||||
///
|
||||
/// \param StartLoc Starting location of the directive kind.
|
||||
@ -1566,7 +1606,8 @@ class OMPAtomicDirective : public OMPExecutableDirective {
|
||||
OMPAtomicDirective(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
unsigned NumClauses)
|
||||
: OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
|
||||
StartLoc, EndLoc, NumClauses, 4) {}
|
||||
StartLoc, EndLoc, NumClauses, 5),
|
||||
IsXLHSInRHSPart(false), IsPostfixUpdate(false) {}
|
||||
|
||||
/// \brief Build an empty directive.
|
||||
///
|
||||
@ -1575,14 +1616,19 @@ class OMPAtomicDirective : public OMPExecutableDirective {
|
||||
explicit OMPAtomicDirective(unsigned NumClauses)
|
||||
: OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
|
||||
SourceLocation(), SourceLocation(), NumClauses,
|
||||
4) {}
|
||||
5),
|
||||
IsXLHSInRHSPart(false), IsPostfixUpdate(false) {}
|
||||
|
||||
/// \brief Set 'x' part of the associated expression/statement.
|
||||
void setX(Expr *X) { *std::next(child_begin()) = X; }
|
||||
/// \brief Set helper expression of the form
|
||||
/// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
|
||||
/// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
|
||||
void setUpdateExpr(Expr *UE) { *std::next(child_begin(), 2) = UE; }
|
||||
/// \brief Set 'v' part of the associated expression/statement.
|
||||
void setV(Expr *V) { *std::next(child_begin(), 2) = V; }
|
||||
void setV(Expr *V) { *std::next(child_begin(), 3) = V; }
|
||||
/// \brief Set 'expr' part of the associated expression/statement.
|
||||
void setExpr(Expr *E) { *std::next(child_begin(), 3) = E; }
|
||||
void setExpr(Expr *E) { *std::next(child_begin(), 4) = E; }
|
||||
|
||||
public:
|
||||
/// \brief Creates directive with a list of \a Clauses and 'x', 'v' and 'expr'
|
||||
@ -1597,11 +1643,17 @@ class OMPAtomicDirective : public OMPExecutableDirective {
|
||||
/// \param X 'x' part of the associated expression/statement.
|
||||
/// \param V 'v' part of the associated expression/statement.
|
||||
/// \param E 'expr' part of the associated expression/statement.
|
||||
///
|
||||
/// \param UE Helper expression of the form
|
||||
/// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
|
||||
/// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
|
||||
/// \param IsXLHSInRHSPart true if \a UE has the first form and false if the
|
||||
/// second.
|
||||
/// \param IsPostfixUpdate true if original value of 'x' must be stored in
|
||||
/// 'v', not an updated one.
|
||||
static OMPAtomicDirective *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V,
|
||||
Expr *E);
|
||||
Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate);
|
||||
|
||||
/// \brief Creates an empty directive with the place for \a NumClauses
|
||||
/// clauses.
|
||||
@ -1617,16 +1669,32 @@ class OMPAtomicDirective : public OMPExecutableDirective {
|
||||
const Expr *getX() const {
|
||||
return cast_or_null<Expr>(*std::next(child_begin()));
|
||||
}
|
||||
/// \brief Get 'v' part of the associated expression/statement.
|
||||
Expr *getV() { return cast_or_null<Expr>(*std::next(child_begin(), 2)); }
|
||||
const Expr *getV() const {
|
||||
/// \brief Get helper expression of the form
|
||||
/// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
|
||||
/// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
|
||||
Expr *getUpdateExpr() {
|
||||
return cast_or_null<Expr>(*std::next(child_begin(), 2));
|
||||
}
|
||||
/// \brief Get 'expr' part of the associated expression/statement.
|
||||
Expr *getExpr() { return cast_or_null<Expr>(*std::next(child_begin(), 3)); }
|
||||
const Expr *getExpr() const {
|
||||
const Expr *getUpdateExpr() const {
|
||||
return cast_or_null<Expr>(*std::next(child_begin(), 2));
|
||||
}
|
||||
/// \brief Return true if helper update expression has form
|
||||
/// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' and false if it has form
|
||||
/// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
|
||||
bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
|
||||
/// \brief Return true if 'v' expression must be updated to original value of
|
||||
/// 'x', false if 'v' must be updated to the new value of 'x'.
|
||||
bool isPostfixUpdate() const { return IsPostfixUpdate; }
|
||||
/// \brief Get 'v' part of the associated expression/statement.
|
||||
Expr *getV() { return cast_or_null<Expr>(*std::next(child_begin(), 3)); }
|
||||
const Expr *getV() const {
|
||||
return cast_or_null<Expr>(*std::next(child_begin(), 3));
|
||||
}
|
||||
/// \brief Get 'expr' part of the associated expression/statement.
|
||||
Expr *getExpr() { return cast_or_null<Expr>(*std::next(child_begin(), 4)); }
|
||||
const Expr *getExpr() const {
|
||||
return cast_or_null<Expr>(*std::next(child_begin(), 4));
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == OMPAtomicDirectiveClass;
|
||||
|
@ -114,7 +114,7 @@ class TemplateArgument {
|
||||
struct TV TypeOrValue;
|
||||
};
|
||||
|
||||
TemplateArgument(TemplateName, bool) LLVM_DELETED_FUNCTION;
|
||||
TemplateArgument(TemplateName, bool) = delete;
|
||||
|
||||
public:
|
||||
/// \brief Construct an empty, invalid template argument.
|
||||
|
@ -456,7 +456,7 @@ class Qualifiers {
|
||||
bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
|
||||
bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return hasQualifiers(); }
|
||||
explicit operator bool() const { return hasQualifiers(); }
|
||||
|
||||
Qualifiers &operator+=(Qualifiers R) {
|
||||
addQualifiers(R);
|
||||
@ -1179,8 +1179,8 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
};
|
||||
|
||||
private:
|
||||
Type(const Type &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Type &) LLVM_DELETED_FUNCTION;
|
||||
Type(const Type &) = delete;
|
||||
void operator=(const Type &) = delete;
|
||||
|
||||
/// Bitfields required by the Type class.
|
||||
class TypeBitfields {
|
||||
@ -1575,6 +1575,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
bool isObjCLifetimeType() const; // (array of)* retainable type
|
||||
bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type
|
||||
bool isObjCNSObjectType() const; // __attribute__((NSObject))
|
||||
bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class))
|
||||
// FIXME: change this to 'raw' interface type, so we can used 'interface' type
|
||||
// for the common case.
|
||||
bool isObjCObjectType() const; // NSString or typeof(*(id)0)
|
||||
@ -3472,7 +3473,6 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||
attr_thiscall,
|
||||
attr_pascal,
|
||||
attr_vectorcall,
|
||||
attr_pnaclcall,
|
||||
attr_inteloclbicc,
|
||||
attr_ms_abi,
|
||||
attr_sysv_abi,
|
||||
|
@ -93,7 +93,7 @@ class TypeLoc {
|
||||
}
|
||||
|
||||
bool isNull() const { return !Ty; }
|
||||
LLVM_EXPLICIT operator bool() const { return Ty; }
|
||||
explicit operator bool() const { return Ty; }
|
||||
|
||||
/// \brief Returns the size of type source info data block for the given type.
|
||||
static unsigned getFullDataSizeForType(QualType Ty);
|
||||
|
@ -11,7 +11,7 @@
|
||||
// enumerated by providing its name (e.g., "Builtin" or "Enum") and
|
||||
// base class (e.g., "Type" or "TagType"). Depending on where in the
|
||||
// abstract syntax tree the type will show up, the enumeration uses
|
||||
// one of four different macros:
|
||||
// one of five different macros:
|
||||
//
|
||||
// TYPE(Class, Base) - A type that can show up anywhere in the AST,
|
||||
// and might be dependent, canonical, or non-canonical. All clients
|
||||
|
@ -19,74 +19,36 @@
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <iterator>
|
||||
#include "llvm/ADT/iterator.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// The iterator over UnresolvedSets. Serves as both the const and
|
||||
/// non-const iterator.
|
||||
class UnresolvedSetIterator {
|
||||
private:
|
||||
typedef MutableArrayRef<DeclAccessPair> DeclsTy;
|
||||
typedef DeclsTy::iterator IteratorTy;
|
||||
|
||||
IteratorTy ir;
|
||||
|
||||
class UnresolvedSetIterator : public llvm::iterator_adaptor_base<
|
||||
UnresolvedSetIterator, DeclAccessPair *,
|
||||
std::random_access_iterator_tag, NamedDecl *,
|
||||
std::ptrdiff_t, NamedDecl *, NamedDecl *> {
|
||||
friend class UnresolvedSetImpl;
|
||||
friend class ASTUnresolvedSet;
|
||||
friend class OverloadExpr;
|
||||
explicit UnresolvedSetIterator(DeclsTy::iterator ir) : ir(ir) {}
|
||||
explicit UnresolvedSetIterator(DeclsTy::const_iterator ir) :
|
||||
ir(const_cast<DeclsTy::iterator>(ir)) {}
|
||||
|
||||
IteratorTy getIterator() const { return ir; }
|
||||
|
||||
|
||||
explicit UnresolvedSetIterator(DeclAccessPair *Iter)
|
||||
: iterator_adaptor_base(Iter) {}
|
||||
explicit UnresolvedSetIterator(const DeclAccessPair *Iter)
|
||||
: iterator_adaptor_base(const_cast<DeclAccessPair *>(Iter)) {}
|
||||
|
||||
public:
|
||||
UnresolvedSetIterator() {}
|
||||
|
||||
typedef std::iterator_traits<IteratorTy>::difference_type difference_type;
|
||||
typedef NamedDecl *value_type;
|
||||
typedef NamedDecl **pointer;
|
||||
typedef NamedDecl *reference;
|
||||
typedef std::iterator_traits<IteratorTy>::iterator_category iterator_category;
|
||||
|
||||
NamedDecl *getDecl() const { return ir->getDecl(); }
|
||||
void setDecl(NamedDecl *ND) const { return ir->setDecl(ND); }
|
||||
AccessSpecifier getAccess() const { return ir->getAccess(); }
|
||||
void setAccess(AccessSpecifier AS) { ir->setAccess(AS); }
|
||||
DeclAccessPair getPair() const { return *ir; }
|
||||
NamedDecl *getDecl() const { return I->getDecl(); }
|
||||
void setDecl(NamedDecl *ND) const { return I->setDecl(ND); }
|
||||
AccessSpecifier getAccess() const { return I->getAccess(); }
|
||||
void setAccess(AccessSpecifier AS) { I->setAccess(AS); }
|
||||
const DeclAccessPair &getPair() const { return *I; }
|
||||
|
||||
NamedDecl *operator*() const { return getDecl(); }
|
||||
|
||||
UnresolvedSetIterator &operator++() { ++ir; return *this; }
|
||||
UnresolvedSetIterator operator++(int) { return UnresolvedSetIterator(ir++); }
|
||||
UnresolvedSetIterator &operator--() { --ir; return *this; }
|
||||
UnresolvedSetIterator operator--(int) { return UnresolvedSetIterator(ir--); }
|
||||
|
||||
UnresolvedSetIterator &operator+=(difference_type d) {
|
||||
ir += d; return *this;
|
||||
}
|
||||
UnresolvedSetIterator operator+(difference_type d) const {
|
||||
return UnresolvedSetIterator(ir + d);
|
||||
}
|
||||
UnresolvedSetIterator &operator-=(difference_type d) {
|
||||
ir -= d; return *this;
|
||||
}
|
||||
UnresolvedSetIterator operator-(difference_type d) const {
|
||||
return UnresolvedSetIterator(ir - d);
|
||||
}
|
||||
value_type operator[](difference_type d) const { return *(*this + d); }
|
||||
|
||||
difference_type operator-(const UnresolvedSetIterator &o) const {
|
||||
return ir - o.ir;
|
||||
}
|
||||
|
||||
bool operator==(const UnresolvedSetIterator &o) const { return ir == o.ir; }
|
||||
bool operator!=(const UnresolvedSetIterator &o) const { return ir != o.ir; }
|
||||
bool operator<(const UnresolvedSetIterator &o) const { return ir < o.ir; }
|
||||
bool operator<=(const UnresolvedSetIterator &o) const { return ir <= o.ir; }
|
||||
bool operator>=(const UnresolvedSetIterator &o) const { return ir >= o.ir; }
|
||||
bool operator>(const UnresolvedSetIterator &o) const { return ir > o.ir; }
|
||||
NamedDecl *operator->() const { return **this; }
|
||||
};
|
||||
|
||||
/// \brief A set of unresolved declarations.
|
||||
@ -132,21 +94,17 @@ class UnresolvedSetImpl {
|
||||
|
||||
/// Replaces the declaration at the given iterator with the new one,
|
||||
/// preserving the original access bits.
|
||||
void replace(iterator I, NamedDecl *New) {
|
||||
I.ir->setDecl(New);
|
||||
}
|
||||
void replace(iterator I, NamedDecl *New) { I.I->setDecl(New); }
|
||||
|
||||
void replace(iterator I, NamedDecl *New, AccessSpecifier AS) {
|
||||
I.ir->set(New, AS);
|
||||
I.I->set(New, AS);
|
||||
}
|
||||
|
||||
void erase(unsigned I) { decls()[I] = decls().pop_back_val(); }
|
||||
|
||||
void erase(iterator I) { *I.ir = decls().pop_back_val(); }
|
||||
void erase(iterator I) { *I.I = decls().pop_back_val(); }
|
||||
|
||||
void setAccess(iterator I, AccessSpecifier AS) {
|
||||
I.ir->setAccess(AS);
|
||||
}
|
||||
void setAccess(iterator I, AccessSpecifier AS) { I.I->setAccess(AS); }
|
||||
|
||||
void clear() { decls().clear(); }
|
||||
void set_size(unsigned N) { decls().set_size(N); }
|
||||
@ -154,9 +112,7 @@ class UnresolvedSetImpl {
|
||||
bool empty() const { return decls().empty(); }
|
||||
unsigned size() const { return decls().size(); }
|
||||
|
||||
void append(iterator I, iterator E) {
|
||||
decls().append(I.ir, E.ir);
|
||||
}
|
||||
void append(iterator I, iterator E) { decls().append(I.I, E.I); }
|
||||
|
||||
DeclAccessPair &operator[](unsigned I) { return decls()[I]; }
|
||||
const DeclAccessPair &operator[](unsigned I) const { return decls()[I]; }
|
||||
|
@ -333,7 +333,7 @@ class ItaniumVTableContext : public VTableContextBase {
|
||||
|
||||
public:
|
||||
ItaniumVTableContext(ASTContext &Context);
|
||||
~ItaniumVTableContext();
|
||||
~ItaniumVTableContext() override;
|
||||
|
||||
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
|
||||
computeVTableRelatedInformation(RD);
|
||||
@ -511,7 +511,7 @@ class MicrosoftVTableContext : public VTableContextBase {
|
||||
MicrosoftVTableContext(ASTContext &Context)
|
||||
: VTableContextBase(/*MS=*/true), Context(Context) {}
|
||||
|
||||
~MicrosoftVTableContext();
|
||||
~MicrosoftVTableContext() override;
|
||||
|
||||
const VPtrInfoVector &getVFPtrOffsets(const CXXRecordDecl *RD);
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/DeclFriend.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/ASTMatchers/ASTMatchersInternal.h"
|
||||
#include "clang/ASTMatchers/ASTMatchersMacros.h"
|
||||
@ -143,6 +144,20 @@ typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher;
|
||||
/// Usable as: Any Matcher
|
||||
inline internal::TrueMatcher anything() { return internal::TrueMatcher(); }
|
||||
|
||||
/// \brief Matches the top declaration context.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
/// int X;
|
||||
/// namespace NS {
|
||||
/// int Y;
|
||||
/// } // namespace NS
|
||||
/// \endcode
|
||||
/// decl(hasDeclContext(translationUnitDecl()))
|
||||
/// matches "int X", but not "int Y".
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl>
|
||||
translationUnitDecl;
|
||||
|
||||
/// \brief Matches typedef declarations.
|
||||
///
|
||||
/// Given
|
||||
@ -167,8 +182,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl;
|
||||
///
|
||||
/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
|
||||
AST_POLYMORPHIC_MATCHER(isExpansionInMainFile,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
|
||||
TypeLoc)) {
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc)) {
|
||||
auto &SourceManager = Finder->getASTContext().getSourceManager();
|
||||
return SourceManager.isInMainFile(
|
||||
SourceManager.getExpansionLoc(Node.getLocStart()));
|
||||
@ -189,8 +203,7 @@ AST_POLYMORPHIC_MATCHER(isExpansionInMainFile,
|
||||
///
|
||||
/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
|
||||
AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
|
||||
TypeLoc)) {
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc)) {
|
||||
auto &SourceManager = Finder->getASTContext().getSourceManager();
|
||||
auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
|
||||
if (ExpansionLoc.isInvalid()) {
|
||||
@ -215,8 +228,7 @@ AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader,
|
||||
///
|
||||
/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
|
||||
AST_POLYMORPHIC_MATCHER_P(isExpansionInFileMatching,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
|
||||
TypeLoc),
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
|
||||
std::string, RegExp) {
|
||||
auto &SourceManager = Finder->getASTContext().getSourceManager();
|
||||
auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
|
||||
@ -442,8 +454,8 @@ AST_MATCHER(Decl, isImplicit) {
|
||||
/// matches the specialization \c A<int>
|
||||
AST_POLYMORPHIC_MATCHER_P(
|
||||
hasAnyTemplateArgument,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
internal::Matcher<TemplateArgument>, InnerMatcher) {
|
||||
ArrayRef<TemplateArgument> List =
|
||||
internal::getTemplateSpecializationArgs(Node);
|
||||
@ -542,8 +554,8 @@ AST_MATCHER_P(Expr, ignoringParenImpCasts,
|
||||
/// matches the specialization \c A<bool, int>
|
||||
AST_POLYMORPHIC_MATCHER_P2(
|
||||
hasTemplateArgument,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
|
||||
ArrayRef<TemplateArgument> List =
|
||||
internal::getTemplateSpecializationArgs(Node);
|
||||
@ -563,8 +575,8 @@ AST_POLYMORPHIC_MATCHER_P2(
|
||||
/// matches C<int>.
|
||||
AST_POLYMORPHIC_MATCHER_P(
|
||||
templateArgumentCountIs,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
|
||||
TemplateSpecializationType),
|
||||
unsigned, N) {
|
||||
return internal::getTemplateSpecializationArgs(Node).size() == N;
|
||||
}
|
||||
@ -745,6 +757,15 @@ const internal::VariadicDynCastAllOfMatcher<
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> methodDecl;
|
||||
|
||||
/// \brief Matches conversion operator declarations.
|
||||
///
|
||||
/// Example matches the operator.
|
||||
/// \code
|
||||
/// class X { operator int() const; };
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
|
||||
conversionDecl;
|
||||
|
||||
/// \brief Matches variable declarations.
|
||||
///
|
||||
/// Note: this does not match declarations of member variables, which are
|
||||
@ -858,6 +879,20 @@ const internal::VariadicDynCastAllOfMatcher<
|
||||
Stmt,
|
||||
CXXMemberCallExpr> memberCallExpr;
|
||||
|
||||
/// \brief Matches ObjectiveC Message invocation expressions.
|
||||
///
|
||||
/// The innermost message send invokes the "alloc" class method on the
|
||||
/// NSString class, while the outermost message send invokes the
|
||||
/// "initWithString" instance method on the object returned from
|
||||
/// NSString's "alloc". This matcher should match both message sends.
|
||||
/// \code
|
||||
/// [[NSString alloc] initWithString:@"Hello"]
|
||||
/// \endcode
|
||||
const internal::VariadicDynCastAllOfMatcher<
|
||||
Stmt,
|
||||
ObjCMessageExpr> objcMessageExpr;
|
||||
|
||||
|
||||
/// \brief Matches expressions that introduce cleanups to be run at the end
|
||||
/// of the sub-expression's evaluation.
|
||||
///
|
||||
@ -1406,6 +1441,11 @@ const internal::VariadicDynCastAllOfMatcher<
|
||||
Stmt,
|
||||
CXXNullPtrLiteralExpr> nullPtrLiteralExpr;
|
||||
|
||||
/// \brief Matches GNU __null expression.
|
||||
const internal::VariadicDynCastAllOfMatcher<
|
||||
Stmt,
|
||||
GNUNullExpr> gnuNullExpr;
|
||||
|
||||
/// \brief Matches binary operator expressions.
|
||||
///
|
||||
/// Example matches a || b
|
||||
@ -1739,12 +1779,11 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
|
||||
/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl>
|
||||
inline internal::PolymorphicMatcherWithParam1<
|
||||
internal::HasOverloadedOperatorNameMatcher, StringRef,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl)>
|
||||
hasOverloadedOperatorName(StringRef Name) {
|
||||
return internal::PolymorphicMatcherWithParam1<
|
||||
internal::HasOverloadedOperatorNameMatcher, StringRef,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, FunctionDecl)>(
|
||||
Name);
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl)>(Name);
|
||||
}
|
||||
|
||||
/// \brief Matches C++ classes that are directly or indirectly derived from
|
||||
@ -1997,6 +2036,104 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
|
||||
InnerMatcher.matches(*ExprNode, Finder, Builder));
|
||||
}
|
||||
|
||||
|
||||
/// \brief Matches on the receiver of an ObjectiveC Message expression.
|
||||
///
|
||||
/// Example
|
||||
/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
|
||||
/// matches the [webView ...] message invocation.
|
||||
/// \code
|
||||
/// NSString *webViewJavaScript = ...
|
||||
/// UIWebView *webView = ...
|
||||
/// [webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
|
||||
/// \endcode
|
||||
AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>,
|
||||
InnerMatcher) {
|
||||
const QualType TypeDecl = Node.getReceiverType();
|
||||
return InnerMatcher.matches(TypeDecl, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Matches when BaseName == Selector.getAsString()
|
||||
///
|
||||
/// matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
|
||||
/// matches the outer message expr in the code below, but NOT the message
|
||||
/// invocation for self.bodyView.
|
||||
/// \code
|
||||
/// [self.bodyView loadHTMLString:html baseURL:NULL];
|
||||
/// \endcode
|
||||
AST_MATCHER_P(ObjCMessageExpr, hasSelector, std::string, BaseName) {
|
||||
Selector Sel = Node.getSelector();
|
||||
return BaseName.compare(Sel.getAsString()) == 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Matches ObjC selectors whose name contains
|
||||
/// a substring matched by the given RegExp.
|
||||
/// matcher = objCMessageExpr(matchesSelector("loadHTMLString\:baseURL?"));
|
||||
/// matches the outer message expr in the code below, but NOT the message
|
||||
/// invocation for self.bodyView.
|
||||
/// \code
|
||||
/// [self.bodyView loadHTMLString:html baseURL:NULL];
|
||||
/// \endcode
|
||||
AST_MATCHER_P(ObjCMessageExpr, matchesSelector, std::string, RegExp) {
|
||||
assert(!RegExp.empty());
|
||||
std::string SelectorString = Node.getSelector().getAsString();
|
||||
llvm::Regex RE(RegExp);
|
||||
return RE.match(SelectorString);
|
||||
}
|
||||
|
||||
/// \brief Matches when the selector is the empty selector
|
||||
///
|
||||
/// Matches only when the selector of the objCMessageExpr is NULL. This may
|
||||
/// represent an error condition in the tree!
|
||||
AST_MATCHER(ObjCMessageExpr, hasNullSelector) {
|
||||
return Node.getSelector().isNull();
|
||||
}
|
||||
|
||||
/// \brief Matches when the selector is a Unary Selector
|
||||
///
|
||||
/// matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
|
||||
/// matches self.bodyView in the code below, but NOT the outer message
|
||||
/// invocation of "loadHTMLString:baseURL:".
|
||||
/// \code
|
||||
/// [self.bodyView loadHTMLString:html baseURL:NULL];
|
||||
/// \endcode
|
||||
AST_MATCHER(ObjCMessageExpr, hasUnarySelector) {
|
||||
return Node.getSelector().isUnarySelector();
|
||||
}
|
||||
|
||||
/// \brief Matches when the selector is a keyword selector
|
||||
///
|
||||
/// objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
|
||||
/// message expression in
|
||||
///
|
||||
/// \code
|
||||
/// UIWebView *webView = ...;
|
||||
/// CGRect bodyFrame = webView.frame;
|
||||
/// bodyFrame.size.height = self.bodyContentHeight;
|
||||
/// webView.frame = bodyFrame;
|
||||
/// // ^---- matches here
|
||||
/// \endcode
|
||||
|
||||
AST_MATCHER(ObjCMessageExpr, hasKeywordSelector) {
|
||||
return Node.getSelector().isKeywordSelector();
|
||||
}
|
||||
|
||||
/// \brief Matches when the selector has the specified number of arguments
|
||||
///
|
||||
/// matcher = objCMessageExpr(numSelectorArgs(1));
|
||||
/// matches self.bodyView in the code below
|
||||
///
|
||||
/// matcher = objCMessageExpr(numSelectorArgs(2));
|
||||
/// matches the invocation of "loadHTMLString:baseURL:" but not that
|
||||
/// of self.bodyView
|
||||
/// \code
|
||||
/// [self.bodyView loadHTMLString:html baseURL:NULL];
|
||||
/// \endcode
|
||||
AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) {
|
||||
return Node.getSelector().getNumArgs() == N;
|
||||
}
|
||||
|
||||
/// \brief Matches if the call expression's callee expression matches.
|
||||
///
|
||||
/// Given
|
||||
@ -2043,7 +2180,7 @@ AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
|
||||
/// void y(X &x) { x; X z; }
|
||||
/// \endcode
|
||||
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
|
||||
hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
|
||||
hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, ValueDecl),
|
||||
internal::Matcher<QualType>, InnerMatcher, 0) {
|
||||
return InnerMatcher.matches(Node.getType(), Finder, Builder);
|
||||
}
|
||||
@ -2065,9 +2202,10 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
|
||||
/// \endcode
|
||||
///
|
||||
/// Usable as: Matcher<Expr>, Matcher<ValueDecl>
|
||||
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
|
||||
hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
|
||||
internal::Matcher<Decl>, InnerMatcher, 1) {
|
||||
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(hasType,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(Expr,
|
||||
ValueDecl),
|
||||
internal::Matcher<Decl>, InnerMatcher, 1) {
|
||||
return qualType(hasDeclaration(InnerMatcher))
|
||||
.matches(Node.getType(), Finder, Builder);
|
||||
}
|
||||
@ -2303,8 +2441,10 @@ AST_MATCHER(VarDecl, hasGlobalStorage) {
|
||||
/// void f(int x, int y);
|
||||
/// f(0, 0);
|
||||
/// \endcode
|
||||
AST_POLYMORPHIC_MATCHER_P(argumentCountIs, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
|
||||
CallExpr, CXXConstructExpr),
|
||||
AST_POLYMORPHIC_MATCHER_P(argumentCountIs,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr,
|
||||
CXXConstructExpr,
|
||||
ObjCMessageExpr),
|
||||
unsigned, N) {
|
||||
return Node.getNumArgs() == N;
|
||||
}
|
||||
@ -2317,10 +2457,11 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountIs, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
|
||||
/// \code
|
||||
/// void x(int) { int y; x(y); }
|
||||
/// \endcode
|
||||
AST_POLYMORPHIC_MATCHER_P2(
|
||||
hasArgument,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(CallExpr, CXXConstructExpr),
|
||||
unsigned, N, internal::Matcher<Expr>, InnerMatcher) {
|
||||
AST_POLYMORPHIC_MATCHER_P2(hasArgument,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr,
|
||||
CXXConstructExpr,
|
||||
ObjCMessageExpr),
|
||||
unsigned, N, internal::Matcher<Expr>, InnerMatcher) {
|
||||
return (N < Node.getNumArgs() &&
|
||||
InnerMatcher.matches(
|
||||
*Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
|
||||
@ -2460,8 +2601,9 @@ AST_MATCHER(CXXCtorInitializer, isWritten) {
|
||||
/// the argument before applying the inner matcher. We'll want to remove
|
||||
/// this to allow for greater control by the user once \c ignoreImplicit()
|
||||
/// has been implemented.
|
||||
AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
|
||||
CallExpr, CXXConstructExpr),
|
||||
AST_POLYMORPHIC_MATCHER_P(hasAnyArgument,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr,
|
||||
CXXConstructExpr),
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
for (const Expr *Arg : Node.arguments()) {
|
||||
BoundNodesTreeBuilder Result(*Builder);
|
||||
@ -2567,6 +2709,23 @@ AST_MATCHER(FunctionDecl, isDeleted) {
|
||||
return Node.isDeleted();
|
||||
}
|
||||
|
||||
/// \brief Matches constexpr variable and function declarations.
|
||||
///
|
||||
/// Given:
|
||||
/// \code
|
||||
/// constexpr int foo = 42;
|
||||
/// constexpr int bar();
|
||||
/// \endcode
|
||||
/// varDecl(isConstexpr())
|
||||
/// matches the declaration of foo.
|
||||
/// functionDecl(isConstexpr())
|
||||
/// matches the declaration of bar.
|
||||
AST_POLYMORPHIC_MATCHER(isConstexpr,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(VarDecl,
|
||||
FunctionDecl)) {
|
||||
return Node.isConstexpr();
|
||||
}
|
||||
|
||||
/// \brief Matches the condition expression of an if statement, for loop,
|
||||
/// or conditional operator.
|
||||
///
|
||||
@ -2574,10 +2733,11 @@ AST_MATCHER(FunctionDecl, isDeleted) {
|
||||
/// \code
|
||||
/// if (true) {}
|
||||
/// \endcode
|
||||
AST_POLYMORPHIC_MATCHER_P(
|
||||
hasCondition, AST_POLYMORPHIC_SUPPORTED_TYPES_5(
|
||||
IfStmt, ForStmt, WhileStmt, DoStmt, ConditionalOperator),
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
AST_POLYMORPHIC_MATCHER_P(hasCondition,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt,
|
||||
WhileStmt, DoStmt,
|
||||
ConditionalOperator),
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
const Expr *const Condition = Node.getCond();
|
||||
return (Condition != nullptr &&
|
||||
InnerMatcher.matches(*Condition, Finder, Builder));
|
||||
@ -2628,8 +2788,9 @@ AST_MATCHER_P(IfStmt, hasElse, internal::Matcher<Stmt>, InnerMatcher) {
|
||||
/// forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
|
||||
/// will trigger a match for each combination of variable declaration
|
||||
/// and reference to that variable declaration within a compound statement.
|
||||
AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, AST_POLYMORPHIC_SUPPORTED_TYPES_4(
|
||||
Stmt, Decl, Type, QualType),
|
||||
AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(Stmt, Decl, Type,
|
||||
QualType),
|
||||
std::string, ID) {
|
||||
// FIXME: Figure out whether it makes sense to allow this
|
||||
// on any other node types.
|
||||
@ -2704,9 +2865,9 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
|
||||
/// with compoundStmt()
|
||||
/// matching '{}'
|
||||
AST_POLYMORPHIC_MATCHER_P(hasBody,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_4(DoStmt, ForStmt,
|
||||
WhileStmt,
|
||||
CXXForRangeStmt),
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
|
||||
WhileStmt,
|
||||
CXXForRangeStmt),
|
||||
internal::Matcher<Stmt>, InnerMatcher) {
|
||||
const Stmt *const Statement = Node.getBody();
|
||||
return (Statement != nullptr &&
|
||||
@ -2768,8 +2929,9 @@ equals(const ValueT &Value) {
|
||||
/// \code
|
||||
/// !(a || b)
|
||||
/// \endcode
|
||||
AST_POLYMORPHIC_MATCHER_P(hasOperatorName, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
|
||||
BinaryOperator, UnaryOperator),
|
||||
AST_POLYMORPHIC_MATCHER_P(hasOperatorName,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator,
|
||||
UnaryOperator),
|
||||
std::string, Name) {
|
||||
return Name == Node.getOpcodeStr(Node.getOpcode());
|
||||
}
|
||||
@ -2892,8 +3054,9 @@ AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
|
||||
/// \endcode
|
||||
///
|
||||
/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
|
||||
AST_POLYMORPHIC_MATCHER(isDefinition, AST_POLYMORPHIC_SUPPORTED_TYPES_3(
|
||||
TagDecl, VarDecl, FunctionDecl)) {
|
||||
AST_POLYMORPHIC_MATCHER(isDefinition,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(TagDecl, VarDecl,
|
||||
FunctionDecl)) {
|
||||
return Node.isThisDeclarationADefinition();
|
||||
}
|
||||
|
||||
@ -2979,7 +3142,7 @@ AST_MATCHER(CXXMethodDecl, isConst) {
|
||||
/// \endcode
|
||||
/// matches B::x
|
||||
AST_MATCHER(CXXMethodDecl, isOverride) {
|
||||
return Node.size_overridden_methods() > 0;
|
||||
return Node.size_overridden_methods() > 0 || Node.hasAttr<OverrideAttr>();
|
||||
}
|
||||
|
||||
/// \brief Matches member expressions that are called with '->' as opposed
|
||||
@ -3140,9 +3303,9 @@ AST_MATCHER_P(UsingShadowDecl, hasTargetDecl,
|
||||
/// does not match, as X<A> is an explicit template specialization.
|
||||
///
|
||||
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
|
||||
AST_POLYMORPHIC_MATCHER(
|
||||
isTemplateInstantiation,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) {
|
||||
AST_POLYMORPHIC_MATCHER(isTemplateInstantiation,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl,
|
||||
CXXRecordDecl)) {
|
||||
return (Node.getTemplateSpecializationKind() == TSK_ImplicitInstantiation ||
|
||||
Node.getTemplateSpecializationKind() ==
|
||||
TSK_ExplicitInstantiationDefinition);
|
||||
@ -3197,9 +3360,9 @@ AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) {
|
||||
/// matches the specialization A<int>().
|
||||
///
|
||||
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
|
||||
AST_POLYMORPHIC_MATCHER(
|
||||
isExplicitTemplateSpecialization,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) {
|
||||
AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl,
|
||||
CXXRecordDecl)) {
|
||||
return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
|
||||
}
|
||||
|
||||
@ -3272,9 +3435,9 @@ AST_TYPE_MATCHER(ComplexType, complexType);
|
||||
/// matches "int b[7]"
|
||||
///
|
||||
/// Usable as: Matcher<ArrayType>, Matcher<ComplexType>
|
||||
AST_TYPELOC_TRAVERSE_MATCHER(
|
||||
hasElementType, getElement,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_2(ArrayType, ComplexType));
|
||||
AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(ArrayType,
|
||||
ComplexType));
|
||||
|
||||
/// \brief Matches C arrays with a specified constant size.
|
||||
///
|
||||
@ -3383,7 +3546,7 @@ AST_TYPE_MATCHER(AtomicType, atomicType);
|
||||
///
|
||||
/// Usable as: Matcher<AtomicType>
|
||||
AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_1(AtomicType));
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(AtomicType));
|
||||
|
||||
/// \brief Matches types nodes representing C++11 auto types.
|
||||
///
|
||||
@ -3412,7 +3575,7 @@ AST_TYPE_MATCHER(AutoType, autoType);
|
||||
///
|
||||
/// Usable as: Matcher<AutoType>
|
||||
AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_1(AutoType));
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(AutoType));
|
||||
|
||||
/// \brief Matches \c FunctionType nodes.
|
||||
///
|
||||
@ -3450,7 +3613,7 @@ AST_TYPE_MATCHER(ParenType, parenType);
|
||||
///
|
||||
/// Usable as: Matcher<ParenType>
|
||||
AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_1(ParenType));
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(ParenType));
|
||||
|
||||
/// \brief Matches block pointer types, i.e. types syntactically represented as
|
||||
/// "void (^)(int)".
|
||||
@ -3544,10 +3707,11 @@ AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType);
|
||||
///
|
||||
/// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>,
|
||||
/// Matcher<PointerType>, Matcher<ReferenceType>
|
||||
AST_TYPELOC_TRAVERSE_MATCHER(
|
||||
pointee, getPointee,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES_4(BlockPointerType, MemberPointerType,
|
||||
PointerType, ReferenceType));
|
||||
AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType,
|
||||
MemberPointerType,
|
||||
PointerType,
|
||||
ReferenceType));
|
||||
|
||||
/// \brief Matches typedef types.
|
||||
///
|
||||
|
@ -38,9 +38,13 @@
|
||||
#include "clang/AST/ASTTypeTraits.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/VariadicFunction.h"
|
||||
@ -139,7 +143,7 @@ class BoundNodesTreeBuilder {
|
||||
void setBinding(const std::string &Id,
|
||||
const ast_type_traits::DynTypedNode &DynNode) {
|
||||
if (Bindings.empty())
|
||||
Bindings.push_back(BoundNodesMap());
|
||||
Bindings.emplace_back();
|
||||
for (BoundNodesMap &Binding : Bindings)
|
||||
Binding.addNode(Id, DynNode);
|
||||
}
|
||||
@ -206,7 +210,7 @@ class DynMatcherInterface : public RefCountedBaseVPTR {
|
||||
template <typename T>
|
||||
class MatcherInterface : public DynMatcherInterface {
|
||||
public:
|
||||
virtual ~MatcherInterface() {}
|
||||
~MatcherInterface() override {}
|
||||
|
||||
/// \brief Returns true if 'Node' can be matched.
|
||||
///
|
||||
@ -381,6 +385,19 @@ class DynTypedMatcher {
|
||||
IntrusiveRefCntPtr<DynMatcherInterface> Implementation;
|
||||
};
|
||||
|
||||
/// \brief Wrapper base class for a wrapping matcher.
|
||||
///
|
||||
/// This is just a container for a DynTypedMatcher that can be used as a base
|
||||
/// class for another matcher.
|
||||
template <typename T>
|
||||
class WrapperMatcherInterface : public MatcherInterface<T> {
|
||||
protected:
|
||||
explicit WrapperMatcherInterface(DynTypedMatcher &&InnerMatcher)
|
||||
: InnerMatcher(std::move(InnerMatcher)) {}
|
||||
|
||||
const DynTypedMatcher InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
|
||||
///
|
||||
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
|
||||
@ -453,19 +470,18 @@ class Matcher {
|
||||
/// does only matches in the absence of qualifiers, or not, i.e. simply
|
||||
/// ignores any qualifiers.
|
||||
template <typename TypeT>
|
||||
class TypeToQualType : public MatcherInterface<QualType> {
|
||||
public:
|
||||
class TypeToQualType : public WrapperMatcherInterface<QualType> {
|
||||
public:
|
||||
TypeToQualType(const Matcher<TypeT> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
: TypeToQualType::WrapperMatcherInterface(InnerMatcher) {}
|
||||
|
||||
bool matches(const QualType &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
if (Node.isNull())
|
||||
return false;
|
||||
return InnerMatcher.matches(*Node, Finder, Builder);
|
||||
return this->InnerMatcher.matches(
|
||||
ast_type_traits::DynTypedNode::create(*Node), Finder, Builder);
|
||||
}
|
||||
private:
|
||||
const Matcher<TypeT> InnerMatcher;
|
||||
};
|
||||
|
||||
private:
|
||||
@ -629,13 +645,13 @@ class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> {
|
||||
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
|
||||
/// not actually used.
|
||||
template <typename T, typename DeclMatcherT>
|
||||
class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
class HasDeclarationMatcher : public WrapperMatcherInterface<T> {
|
||||
static_assert(std::is_same<DeclMatcherT, Matcher<Decl>>::value,
|
||||
"instantiated with wrong types");
|
||||
|
||||
public:
|
||||
explicit HasDeclarationMatcher(const Matcher<Decl> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
: HasDeclarationMatcher::WrapperMatcherInterface(InnerMatcher) {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
@ -698,13 +714,12 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
|
||||
/// \brief Returns whether the inner matcher \c Node. Returns false if \c Node
|
||||
/// is \c NULL.
|
||||
bool matchesDecl(const Decl *Node,
|
||||
ASTMatchFinder *Finder,
|
||||
bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Node != nullptr && InnerMatcher.matches(*Node, Finder, Builder);
|
||||
return Node != nullptr &&
|
||||
this->InnerMatcher.matches(
|
||||
ast_type_traits::DynTypedNode::create(*Node), Finder, Builder);
|
||||
}
|
||||
|
||||
const Matcher<Decl> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST
|
||||
@ -847,19 +862,11 @@ class ASTMatchFinder {
|
||||
|
||||
/// \brief A type-list implementation.
|
||||
///
|
||||
/// A list is declared as a tree of type list nodes, where the leafs are the
|
||||
/// types.
|
||||
/// However, it is used as a "linked list" of types, by using the ::head and
|
||||
/// ::tail typedefs.
|
||||
/// Each node supports up to 4 children (instead of just 2) to reduce the
|
||||
/// nesting required by large lists.
|
||||
template <typename T1 = void, typename T2 = void, typename T3 = void,
|
||||
typename T4 = void>
|
||||
struct TypeList {
|
||||
/// \brief Implementation detail. Combined with the specializations below,
|
||||
/// this typedef allows for flattening of nested structures.
|
||||
typedef TypeList<T1, T2, T3, T4> self;
|
||||
/// A "linked list" of types, accessible by using the ::head and ::tail
|
||||
/// typedefs.
|
||||
template <typename... Ts> struct TypeList {}; // Empty sentinel type list.
|
||||
|
||||
template <typename T1, typename... Ts> struct TypeList<T1, Ts...> {
|
||||
/// \brief The first type on the list.
|
||||
typedef T1 head;
|
||||
|
||||
@ -867,24 +874,7 @@ struct TypeList {
|
||||
///
|
||||
/// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the
|
||||
/// end of the list.
|
||||
typedef typename TypeList<T2, T3, T4>::self tail;
|
||||
};
|
||||
|
||||
/// \brief Template specialization to allow nested lists.
|
||||
///
|
||||
/// First element is a typelist. Pop its first element.
|
||||
template <typename Sub1, typename Sub2, typename Sub3, typename Sub4,
|
||||
typename T2, typename T3, typename T4>
|
||||
struct TypeList<TypeList<Sub1, Sub2, Sub3, Sub4>, T2, T3,
|
||||
T4> : public TypeList<Sub1,
|
||||
typename TypeList<Sub2, Sub3, Sub4>::self,
|
||||
typename TypeList<T2, T3, T4>::self> {};
|
||||
|
||||
/// \brief Template specialization to allow nested lists.
|
||||
///
|
||||
/// First element is an empty typelist. Skip it.
|
||||
template <typename T2, typename T3, typename T4>
|
||||
struct TypeList<TypeList<>, T2, T3, T4> : public TypeList<T2, T3, T4> {
|
||||
typedef TypeList<Ts...> tail;
|
||||
};
|
||||
|
||||
/// \brief The empty type list.
|
||||
@ -906,14 +896,13 @@ struct TypeListContainsSuperOf<EmptyTypeList, T> {
|
||||
/// \brief A "type list" that contains all types.
|
||||
///
|
||||
/// Useful for matchers like \c anything and \c unless.
|
||||
typedef TypeList<
|
||||
TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc>,
|
||||
TypeList<QualType, Type, TypeLoc, CXXCtorInitializer> > AllNodeBaseTypes;
|
||||
typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc,
|
||||
QualType, Type, TypeLoc, CXXCtorInitializer> AllNodeBaseTypes;
|
||||
|
||||
/// \brief Helper meta-function to extract the argument out of a function of
|
||||
/// type void(Arg).
|
||||
///
|
||||
/// See AST_POLYMORPHIC_SUPPORTED_TYPES_* for details.
|
||||
/// See AST_POLYMORPHIC_SUPPORTED_TYPES for details.
|
||||
template <class T> struct ExtractFunctionArgMeta;
|
||||
template <class T> struct ExtractFunctionArgMeta<void(T)> {
|
||||
typedef T type;
|
||||
@ -921,17 +910,15 @@ template <class T> struct ExtractFunctionArgMeta<void(T)> {
|
||||
|
||||
/// \brief Default type lists for ArgumentAdaptingMatcher matchers.
|
||||
typedef AllNodeBaseTypes AdaptativeDefaultFromTypes;
|
||||
typedef TypeList<TypeList<Decl, Stmt, NestedNameSpecifier>,
|
||||
TypeList<NestedNameSpecifierLoc, TypeLoc, QualType> >
|
||||
AdaptativeDefaultToTypes;
|
||||
typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc,
|
||||
TypeLoc, QualType> AdaptativeDefaultToTypes;
|
||||
|
||||
/// \brief All types that are supported by HasDeclarationMatcher above.
|
||||
typedef TypeList<TypeList<CallExpr, CXXConstructExpr, DeclRefExpr, EnumType>,
|
||||
TypeList<InjectedClassNameType, LabelStmt, MemberExpr>,
|
||||
TypeList<QualType, RecordType, TagType>,
|
||||
TypeList<TemplateSpecializationType, TemplateTypeParmType,
|
||||
TypedefType, UnresolvedUsingType> >
|
||||
HasDeclarationSupportedTypes;
|
||||
typedef TypeList<CallExpr, CXXConstructExpr, DeclRefExpr, EnumType,
|
||||
InjectedClassNameType, LabelStmt, MemberExpr, QualType,
|
||||
RecordType, TagType, TemplateSpecializationType,
|
||||
TemplateTypeParmType, TypedefType,
|
||||
UnresolvedUsingType> HasDeclarationSupportedTypes;
|
||||
|
||||
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
|
||||
/// "adapting" a \c To into a \c T.
|
||||
@ -1095,24 +1082,21 @@ class BindableMatcher : public Matcher<T> {
|
||||
///
|
||||
/// ChildT must be an AST base type.
|
||||
template <typename T, typename ChildT>
|
||||
class HasMatcher : public MatcherInterface<T> {
|
||||
class HasMatcher : public WrapperMatcherInterface<T> {
|
||||
static_assert(IsBaseType<ChildT>::value,
|
||||
"has only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
: HasMatcher::WrapperMatcherInterface(ChildMatcher) {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
Node, this->InnerMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
ASTMatchFinder::BK_First);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have child nodes of type ChildT for
|
||||
@ -1121,176 +1105,65 @@ class HasMatcher : public MatcherInterface<T> {
|
||||
/// As opposed to the HasMatcher, the ForEachMatcher will produce a match
|
||||
/// for each child that matches.
|
||||
template <typename T, typename ChildT>
|
||||
class ForEachMatcher : public MatcherInterface<T> {
|
||||
class ForEachMatcher : public WrapperMatcherInterface<T> {
|
||||
static_assert(IsBaseType<ChildT>::value,
|
||||
"for each only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit ForEachMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
explicit ForEachMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ForEachMatcher::WrapperMatcherInterface(ChildMatcher) {}
|
||||
|
||||
bool matches(const T& Node, ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const override {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
ASTMatchFinder::BK_All);
|
||||
Node, this->InnerMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
ASTMatchFinder::BK_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief VariadicOperatorMatcher related types.
|
||||
/// @{
|
||||
|
||||
/// \brief "No argument" placeholder to use as template paratemers.
|
||||
struct VariadicOperatorNoArg {};
|
||||
|
||||
/// \brief Polymorphic matcher object that uses a \c
|
||||
/// DynTypedMatcher::VariadicOperator operator.
|
||||
///
|
||||
/// Input matchers can have any type (including other polymorphic matcher
|
||||
/// types), and the actual Matcher<T> is generated on demand with an implicit
|
||||
/// coversion operator.
|
||||
template <typename P1, typename P2 = VariadicOperatorNoArg,
|
||||
typename P3 = VariadicOperatorNoArg,
|
||||
typename P4 = VariadicOperatorNoArg,
|
||||
typename P5 = VariadicOperatorNoArg,
|
||||
typename P6 = VariadicOperatorNoArg,
|
||||
typename P7 = VariadicOperatorNoArg,
|
||||
typename P8 = VariadicOperatorNoArg,
|
||||
typename P9 = VariadicOperatorNoArg>
|
||||
class VariadicOperatorMatcher {
|
||||
template <typename... Ps> class VariadicOperatorMatcher {
|
||||
public:
|
||||
VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op,
|
||||
const P1 &Param1,
|
||||
const P2 &Param2 = VariadicOperatorNoArg(),
|
||||
const P3 &Param3 = VariadicOperatorNoArg(),
|
||||
const P4 &Param4 = VariadicOperatorNoArg(),
|
||||
const P5 &Param5 = VariadicOperatorNoArg(),
|
||||
const P6 &Param6 = VariadicOperatorNoArg(),
|
||||
const P7 &Param7 = VariadicOperatorNoArg(),
|
||||
const P8 &Param8 = VariadicOperatorNoArg(),
|
||||
const P9 &Param9 = VariadicOperatorNoArg())
|
||||
: Op(Op), Param1(Param1), Param2(Param2), Param3(Param3),
|
||||
Param4(Param4), Param5(Param5), Param6(Param6), Param7(Param7),
|
||||
Param8(Param8), Param9(Param9) {}
|
||||
VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, Ps &&... Params)
|
||||
: Op(Op), Params(std::forward<Ps>(Params)...) {}
|
||||
|
||||
template <typename T> operator Matcher<T>() const {
|
||||
std::vector<DynTypedMatcher> Matchers;
|
||||
addMatcher<T>(Param1, Matchers);
|
||||
addMatcher<T>(Param2, Matchers);
|
||||
addMatcher<T>(Param3, Matchers);
|
||||
addMatcher<T>(Param4, Matchers);
|
||||
addMatcher<T>(Param5, Matchers);
|
||||
addMatcher<T>(Param6, Matchers);
|
||||
addMatcher<T>(Param7, Matchers);
|
||||
addMatcher<T>(Param8, Matchers);
|
||||
addMatcher<T>(Param9, Matchers);
|
||||
return DynTypedMatcher::constructVariadic(Op, std::move(Matchers))
|
||||
return DynTypedMatcher::constructVariadic(
|
||||
Op, getMatchers<T>(llvm::index_sequence_for<Ps...>()))
|
||||
.template unconditionalConvertTo<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static void addMatcher(const Matcher<T> &M,
|
||||
std::vector<DynTypedMatcher> &Matchers) {
|
||||
Matchers.push_back(M);
|
||||
// Helper method to unpack the tuple into a vector.
|
||||
template <typename T, std::size_t... Is>
|
||||
std::vector<DynTypedMatcher> getMatchers(llvm::index_sequence<Is...>) const {
|
||||
return {Matcher<T>(std::get<Is>(Params))...};
|
||||
}
|
||||
|
||||
/// \brief Overload to ignore \c VariadicOperatorNoArg arguments.
|
||||
template <typename T>
|
||||
static void addMatcher(VariadicOperatorNoArg,
|
||||
std::vector<DynTypedMatcher> &Matchers) {}
|
||||
|
||||
const DynTypedMatcher::VariadicOperator Op;
|
||||
const P1 Param1;
|
||||
const P2 Param2;
|
||||
const P3 Param3;
|
||||
const P4 Param4;
|
||||
const P5 Param5;
|
||||
const P6 Param6;
|
||||
const P7 Param7;
|
||||
const P8 Param8;
|
||||
const P9 Param9;
|
||||
std::tuple<Ps...> Params;
|
||||
};
|
||||
|
||||
/// \brief Overloaded function object to generate VariadicOperatorMatcher
|
||||
/// objects from arbitrary matchers.
|
||||
///
|
||||
/// It supports 1-9 argument overloaded operator(). More can be added if needed.
|
||||
template <unsigned MinCount, unsigned MaxCount>
|
||||
struct VariadicOperatorMatcherFunc {
|
||||
DynTypedMatcher::VariadicOperator Op;
|
||||
|
||||
template <unsigned Count, typename T>
|
||||
struct EnableIfValidArity
|
||||
: public std::enable_if<MinCount <= Count && Count <= MaxCount, T> {};
|
||||
|
||||
template <typename M1>
|
||||
typename EnableIfValidArity<1, VariadicOperatorMatcher<M1> >::type
|
||||
operator()(const M1 &P1) const {
|
||||
return VariadicOperatorMatcher<M1>(Op, P1);
|
||||
}
|
||||
template <typename M1, typename M2>
|
||||
typename EnableIfValidArity<2, VariadicOperatorMatcher<M1, M2> >::type
|
||||
operator()(const M1 &P1, const M2 &P2) const {
|
||||
return VariadicOperatorMatcher<M1, M2>(Op, P1, P2);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3>
|
||||
typename EnableIfValidArity<3, VariadicOperatorMatcher<M1, M2, M3> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3>(Op, P1, P2, P3);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4>
|
||||
typename EnableIfValidArity<4, VariadicOperatorMatcher<M1, M2, M3, M4> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4>(Op, P1, P2, P3, P4);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5>
|
||||
typename EnableIfValidArity<
|
||||
5, VariadicOperatorMatcher<M1, M2, M3, M4, M5> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Op, P1, P2, P3, P4, P5);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6>
|
||||
typename EnableIfValidArity<
|
||||
6, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6>(
|
||||
Op, P1, P2, P3, P4, P5, P6);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6, typename M7>
|
||||
typename EnableIfValidArity<
|
||||
7, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6, const M7 &P7) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7>(
|
||||
Op, P1, P2, P3, P4, P5, P6, P7);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6, typename M7, typename M8>
|
||||
typename EnableIfValidArity<
|
||||
8, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8>(
|
||||
Op, P1, P2, P3, P4, P5, P6, P7, P8);
|
||||
}
|
||||
template <typename M1, typename M2, typename M3, typename M4, typename M5,
|
||||
typename M6, typename M7, typename M8, typename M9>
|
||||
typename EnableIfValidArity<
|
||||
9, VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8, M9> >::type
|
||||
operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
|
||||
const M5 &P5, const M6 &P6, const M7 &P7, const M8 &P8,
|
||||
const M9 &P9) const {
|
||||
return VariadicOperatorMatcher<M1, M2, M3, M4, M5, M6, M7, M8, M9>(
|
||||
Op, P1, P2, P3, P4, P5, P6, P7, P8, P9);
|
||||
template <typename... Ms>
|
||||
VariadicOperatorMatcher<Ms...> operator()(Ms &&... Ps) const {
|
||||
static_assert(MinCount <= sizeof...(Ms) && sizeof...(Ms) <= MaxCount,
|
||||
"invalid number of parameters for variadic matcher");
|
||||
return VariadicOperatorMatcher<Ms...>(Op, std::forward<Ms>(Ps)...);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1315,11 +1188,9 @@ BindableMatcher<T> makeAllOfComposite(
|
||||
return BindableMatcher<T>(*InnerMatchers[0]);
|
||||
}
|
||||
|
||||
std::vector<DynTypedMatcher> DynMatchers;
|
||||
DynMatchers.reserve(InnerMatchers.size());
|
||||
for (const auto *InnerMatcher : InnerMatchers) {
|
||||
DynMatchers.push_back(*InnerMatcher);
|
||||
}
|
||||
typedef llvm::pointee_iterator<const Matcher<T> *const *> PI;
|
||||
std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()),
|
||||
PI(InnerMatchers.end()));
|
||||
return BindableMatcher<T>(
|
||||
DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf,
|
||||
std::move(DynMatchers))
|
||||
@ -1344,22 +1215,19 @@ BindableMatcher<T> makeDynCastAllOfComposite(
|
||||
///
|
||||
/// DescendantT must be an AST base type.
|
||||
template <typename T, typename DescendantT>
|
||||
class HasDescendantMatcher : public MatcherInterface<T> {
|
||||
class HasDescendantMatcher : public WrapperMatcherInterface<T> {
|
||||
static_assert(IsBaseType<DescendantT>::value,
|
||||
"has descendant only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
: HasDescendantMatcher::WrapperMatcherInterface(DescendantMatcher) {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesDescendantOf(
|
||||
Node, DescendantMatcher, Builder, ASTMatchFinder::BK_First);
|
||||
return Finder->matchesDescendantOf(Node, this->InnerMatcher, Builder,
|
||||
ASTMatchFinder::BK_First);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c T that have a parent node of type \c ParentT
|
||||
@ -1367,22 +1235,19 @@ class HasDescendantMatcher : public MatcherInterface<T> {
|
||||
///
|
||||
/// \c ParentT must be an AST base type.
|
||||
template <typename T, typename ParentT>
|
||||
class HasParentMatcher : public MatcherInterface<T> {
|
||||
class HasParentMatcher : public WrapperMatcherInterface<T> {
|
||||
static_assert(IsBaseType<ParentT>::value,
|
||||
"has parent only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasParentMatcher(const Matcher<ParentT> &ParentMatcher)
|
||||
: ParentMatcher(ParentMatcher) {}
|
||||
: HasParentMatcher::WrapperMatcherInterface(ParentMatcher) {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesAncestorOf(
|
||||
Node, ParentMatcher, Builder, ASTMatchFinder::AMM_ParentOnly);
|
||||
return Finder->matchesAncestorOf(Node, this->InnerMatcher, Builder,
|
||||
ASTMatchFinder::AMM_ParentOnly);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<ParentT> ParentMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c T that have at least one ancestor node of
|
||||
@ -1390,22 +1255,19 @@ class HasParentMatcher : public MatcherInterface<T> {
|
||||
///
|
||||
/// \c AncestorT must be an AST base type.
|
||||
template <typename T, typename AncestorT>
|
||||
class HasAncestorMatcher : public MatcherInterface<T> {
|
||||
class HasAncestorMatcher : public WrapperMatcherInterface<T> {
|
||||
static_assert(IsBaseType<AncestorT>::value,
|
||||
"has ancestor only accepts base type matcher");
|
||||
|
||||
public:
|
||||
explicit HasAncestorMatcher(const Matcher<AncestorT> &AncestorMatcher)
|
||||
: AncestorMatcher(AncestorMatcher) {}
|
||||
: HasAncestorMatcher::WrapperMatcherInterface(AncestorMatcher) {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesAncestorOf(
|
||||
Node, AncestorMatcher, Builder, ASTMatchFinder::AMM_All);
|
||||
return Finder->matchesAncestorOf(Node, this->InnerMatcher, Builder,
|
||||
ASTMatchFinder::AMM_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<AncestorT> AncestorMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have at least one descendant node of
|
||||
@ -1415,23 +1277,20 @@ class HasAncestorMatcher : public MatcherInterface<T> {
|
||||
/// As opposed to HasDescendantMatcher, ForEachDescendantMatcher will match
|
||||
/// for each descendant node that matches instead of only for the first.
|
||||
template <typename T, typename DescendantT>
|
||||
class ForEachDescendantMatcher : public MatcherInterface<T> {
|
||||
class ForEachDescendantMatcher : public WrapperMatcherInterface<T> {
|
||||
static_assert(IsBaseType<DescendantT>::value,
|
||||
"for each descendant only accepts base type matcher");
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit ForEachDescendantMatcher(
|
||||
const Matcher<DescendantT>& DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
const Matcher<DescendantT> &DescendantMatcher)
|
||||
: ForEachDescendantMatcher::WrapperMatcherInterface(DescendantMatcher) {}
|
||||
|
||||
bool matches(const T& Node, ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const override {
|
||||
return Finder->matchesDescendantOf(Node, DescendantMatcher, Builder,
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
return Finder->matchesDescendantOf(Node, this->InnerMatcher, Builder,
|
||||
ASTMatchFinder::BK_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches on nodes that have a getValue() method if getValue() equals
|
||||
@ -1456,6 +1315,32 @@ class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> {
|
||||
const ValueT ExpectedValue;
|
||||
};
|
||||
|
||||
/// \brief Template specializations to easily write matchers for floating point
|
||||
/// literals.
|
||||
template <>
|
||||
inline bool ValueEqualsMatcher<FloatingLiteral, double>::matchesNode(
|
||||
const FloatingLiteral &Node) const {
|
||||
if ((&Node.getSemantics()) == &llvm::APFloat::IEEEsingle)
|
||||
return Node.getValue().convertToFloat() == ExpectedValue;
|
||||
if ((&Node.getSemantics()) == &llvm::APFloat::IEEEdouble)
|
||||
return Node.getValue().convertToDouble() == ExpectedValue;
|
||||
return false;
|
||||
}
|
||||
template <>
|
||||
inline bool ValueEqualsMatcher<FloatingLiteral, float>::matchesNode(
|
||||
const FloatingLiteral &Node) const {
|
||||
if ((&Node.getSemantics()) == &llvm::APFloat::IEEEsingle)
|
||||
return Node.getValue().convertToFloat() == ExpectedValue;
|
||||
if ((&Node.getSemantics()) == &llvm::APFloat::IEEEdouble)
|
||||
return Node.getValue().convertToDouble() == ExpectedValue;
|
||||
return false;
|
||||
}
|
||||
template <>
|
||||
inline bool ValueEqualsMatcher<FloatingLiteral, llvm::APFloat>::matchesNode(
|
||||
const FloatingLiteral &Node) const {
|
||||
return ExpectedValue.compare(Node.getValue()) == llvm::APFloat::cmpEqual;
|
||||
}
|
||||
|
||||
/// \brief A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a
|
||||
/// variadic functor that takes a number of Matcher<TargetT> and returns a
|
||||
/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the
|
||||
@ -1498,66 +1383,64 @@ class VariadicAllOfMatcher : public llvm::VariadicFunction<
|
||||
/// \brief Matches nodes of type \c TLoc for which the inner
|
||||
/// \c Matcher<T> matches.
|
||||
template <typename TLoc, typename T>
|
||||
class LocMatcher : public MatcherInterface<TLoc> {
|
||||
class LocMatcher : public WrapperMatcherInterface<TLoc> {
|
||||
public:
|
||||
explicit LocMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
: LocMatcher::WrapperMatcherInterface(InnerMatcher) {}
|
||||
|
||||
bool matches(const TLoc &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
if (!Node)
|
||||
return false;
|
||||
return InnerMatcher.matches(*extract(Node), Finder, Builder);
|
||||
return this->InnerMatcher.matches(extract(Node), Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const NestedNameSpecifier *extract(const NestedNameSpecifierLoc &Loc) const {
|
||||
return Loc.getNestedNameSpecifier();
|
||||
static ast_type_traits::DynTypedNode
|
||||
extract(const NestedNameSpecifierLoc &Loc) {
|
||||
return ast_type_traits::DynTypedNode::create(*Loc.getNestedNameSpecifier());
|
||||
}
|
||||
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches \c TypeLocs based on an inner matcher matching a certain
|
||||
/// \c QualType.
|
||||
///
|
||||
/// Used to implement the \c loc() matcher.
|
||||
class TypeLocTypeMatcher : public MatcherInterface<TypeLoc> {
|
||||
class TypeLocTypeMatcher : public WrapperMatcherInterface<TypeLoc> {
|
||||
public:
|
||||
explicit TypeLocTypeMatcher(const Matcher<QualType> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
: TypeLocTypeMatcher::WrapperMatcherInterface(InnerMatcher) {}
|
||||
|
||||
bool matches(const TypeLoc &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
if (!Node)
|
||||
return false;
|
||||
return InnerMatcher.matches(Node.getType(), Finder, Builder);
|
||||
return this->InnerMatcher.matches(
|
||||
ast_type_traits::DynTypedNode::create(Node.getType()), Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<QualType> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c T for which the inner matcher matches on a
|
||||
/// another node of type \c T that can be reached using a given traverse
|
||||
/// function.
|
||||
template <typename T>
|
||||
class TypeTraverseMatcher : public MatcherInterface<T> {
|
||||
class TypeTraverseMatcher : public WrapperMatcherInterface<T> {
|
||||
public:
|
||||
explicit TypeTraverseMatcher(const Matcher<QualType> &InnerMatcher,
|
||||
QualType (T::*TraverseFunction)() const)
|
||||
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
|
||||
: TypeTraverseMatcher::WrapperMatcherInterface(InnerMatcher),
|
||||
TraverseFunction(TraverseFunction) {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
QualType NextNode = (Node.*TraverseFunction)();
|
||||
if (NextNode.isNull())
|
||||
return false;
|
||||
return InnerMatcher.matches(NextNode, Finder, Builder);
|
||||
return this->InnerMatcher.matches(
|
||||
ast_type_traits::DynTypedNode::create(NextNode), Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<QualType> InnerMatcher;
|
||||
QualType (T::*TraverseFunction)() const;
|
||||
};
|
||||
|
||||
@ -1565,22 +1448,23 @@ class TypeTraverseMatcher : public MatcherInterface<T> {
|
||||
/// matcher matches on a another node of type \c T that can be reached using a
|
||||
/// given traverse function.
|
||||
template <typename T>
|
||||
class TypeLocTraverseMatcher : public MatcherInterface<T> {
|
||||
class TypeLocTraverseMatcher : public WrapperMatcherInterface<T> {
|
||||
public:
|
||||
explicit TypeLocTraverseMatcher(const Matcher<TypeLoc> &InnerMatcher,
|
||||
TypeLoc (T::*TraverseFunction)() const)
|
||||
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
|
||||
: TypeLocTraverseMatcher::WrapperMatcherInterface(InnerMatcher),
|
||||
TraverseFunction(TraverseFunction) {}
|
||||
|
||||
bool matches(const T &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const override {
|
||||
TypeLoc NextNode = (Node.*TraverseFunction)();
|
||||
if (!NextNode)
|
||||
return false;
|
||||
return InnerMatcher.matches(NextNode, Finder, Builder);
|
||||
return this->InnerMatcher.matches(
|
||||
ast_type_traits::DynTypedNode::create(NextNode), Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<TypeLoc> InnerMatcher;
|
||||
TypeLoc (T::*TraverseFunction)() const;
|
||||
};
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H
|
||||
#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H
|
||||
|
||||
/// \brief AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) {
|
||||
/// \brief AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) { ... }
|
||||
/// defines a zero parameter function named DefineMatcher() that returns a
|
||||
/// ReturnType object.
|
||||
#define AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) \
|
||||
@ -48,7 +48,7 @@
|
||||
} \
|
||||
inline ReturnType DefineMatcher##_getInstance()
|
||||
|
||||
/// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) {
|
||||
/// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that returns a
|
||||
/// ReturnType object.
|
||||
///
|
||||
@ -193,15 +193,8 @@
|
||||
/// \c void(TypeList<Foo, Bar>), which works thanks to the parenthesis.
|
||||
/// The \c PolymorphicMatcherWithParam* classes will unpack the function type to
|
||||
/// extract the TypeList object.
|
||||
#define AST_POLYMORPHIC_SUPPORTED_TYPES_1(t1) void(internal::TypeList<t1>)
|
||||
#define AST_POLYMORPHIC_SUPPORTED_TYPES_2(t1, t2) \
|
||||
void(internal::TypeList<t1, t2>)
|
||||
#define AST_POLYMORPHIC_SUPPORTED_TYPES_3(t1, t2, t3) \
|
||||
void(internal::TypeList<t1, t2, t3>)
|
||||
#define AST_POLYMORPHIC_SUPPORTED_TYPES_4(t1, t2, t3, t4) \
|
||||
void(internal::TypeList<t1, t2, t3, t4>)
|
||||
#define AST_POLYMORPHIC_SUPPORTED_TYPES_5(t1, t2, t3, t4, t5) \
|
||||
void(internal::TypeList<t1, t2, t3, internal::TypeList<t4, t5> >)
|
||||
#define AST_POLYMORPHIC_SUPPORTED_TYPES(...) \
|
||||
void(internal::TypeList<__VA_ARGS__>)
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER(DefineMatcher) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that is
|
||||
|
@ -123,7 +123,7 @@ class Parser {
|
||||
/// tokens.
|
||||
class RegistrySema : public Parser::Sema {
|
||||
public:
|
||||
virtual ~RegistrySema();
|
||||
~RegistrySema() override;
|
||||
|
||||
llvm::Optional<MatcherCtor>
|
||||
lookupMatcherCtor(StringRef MatcherName) override;
|
||||
|
@ -123,7 +123,7 @@ class Registry {
|
||||
Diagnostics *Error);
|
||||
|
||||
private:
|
||||
Registry() LLVM_DELETED_FUNCTION;
|
||||
Registry() = delete;
|
||||
};
|
||||
|
||||
} // namespace dynamic
|
||||
|
@ -111,7 +111,7 @@ class VariantMatcher {
|
||||
ArrayRef<VariantMatcher> InnerMatchers) const;
|
||||
|
||||
protected:
|
||||
~MatcherOps() {}
|
||||
~MatcherOps() = default;
|
||||
|
||||
private:
|
||||
ast_type_traits::ASTNodeKind NodeKind;
|
||||
@ -122,7 +122,7 @@ class VariantMatcher {
|
||||
/// It follows a similar interface as VariantMatcher itself.
|
||||
class Payload : public RefCountedBaseVPTR {
|
||||
public:
|
||||
virtual ~Payload();
|
||||
~Payload() override;
|
||||
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
|
||||
virtual std::string getTypeAsString() const = 0;
|
||||
virtual llvm::Optional<DynTypedMatcher>
|
||||
@ -258,7 +258,7 @@ class VariantValue {
|
||||
VariantValue(const VariantMatcher &Matchers);
|
||||
|
||||
/// \brief Returns true iff this is not an empty value.
|
||||
LLVM_EXPLICIT operator bool() const { return hasValue(); }
|
||||
explicit operator bool() const { return hasValue(); }
|
||||
bool hasValue() const { return Type != VT_Nothing; }
|
||||
|
||||
/// \brief Unsigned value functions.
|
||||
|
@ -44,9 +44,7 @@ class DominatorTree : public ManagedAnalysis {
|
||||
DT = new llvm::DominatorTreeBase<CFGBlock>(false);
|
||||
}
|
||||
|
||||
~DominatorTree() {
|
||||
delete DT;
|
||||
}
|
||||
~DominatorTree() override { delete DT; }
|
||||
|
||||
llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; }
|
||||
|
||||
|
@ -49,7 +49,7 @@ class OptionalFlag {
|
||||
const char *toString() const { return representation; }
|
||||
|
||||
// Overloaded operators for bool like qualities
|
||||
LLVM_EXPLICIT operator bool() const { return flag; }
|
||||
explicit operator bool() const { return flag; }
|
||||
OptionalFlag& operator=(const bool &rhs) {
|
||||
flag = rhs;
|
||||
return *this; // Return a reference to myself.
|
||||
@ -161,6 +161,12 @@ class ConversionSpecifier {
|
||||
ObjCObjArg, // '@'
|
||||
ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
|
||||
|
||||
// FreeBSD kernel specific specifiers.
|
||||
FreeBSDbArg,
|
||||
FreeBSDDArg,
|
||||
FreeBSDrArg,
|
||||
FreeBSDyArg,
|
||||
|
||||
// GlibC specific specifiers.
|
||||
PrintErrno, // 'm'
|
||||
|
||||
@ -204,7 +210,8 @@ class ConversionSpecifier {
|
||||
return EndScanList ? EndScanList - Position : 1;
|
||||
}
|
||||
|
||||
bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
|
||||
bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
|
||||
kind == FreeBSDrArg || kind == FreeBSDyArg; }
|
||||
bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
|
||||
bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
|
||||
const char *toString() const;
|
||||
@ -224,6 +231,9 @@ class ArgType {
|
||||
public:
|
||||
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
|
||||
AnyCharTy, CStrTy, WCStrTy, WIntTy };
|
||||
|
||||
enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
|
||||
|
||||
private:
|
||||
const Kind K;
|
||||
QualType T;
|
||||
@ -247,7 +257,7 @@ class ArgType {
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool matchesType(ASTContext &C, QualType argTy) const;
|
||||
MatchKind matchesType(ASTContext &C, QualType argTy) const;
|
||||
|
||||
QualType getRepresentativeType(ASTContext &C) const;
|
||||
|
||||
@ -646,10 +656,10 @@ class FormatStringHandler {
|
||||
|
||||
bool ParsePrintfString(FormatStringHandler &H,
|
||||
const char *beg, const char *end, const LangOptions &LO,
|
||||
const TargetInfo &Target);
|
||||
|
||||
bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO,
|
||||
const TargetInfo &Target);
|
||||
const TargetInfo &Target, bool isFreeBSDKPrintf);
|
||||
|
||||
bool ParseFormatStringHasSArg(const char *beg, const char *end,
|
||||
const LangOptions &LO, const TargetInfo &Target);
|
||||
|
||||
bool ParseScanfString(FormatStringHandler &H,
|
||||
const char *beg, const char *end, const LangOptions &LO,
|
||||
|
@ -44,8 +44,6 @@ class LiveVariables : public ManagedAnalysis {
|
||||
llvm::ImmutableSet<const VarDecl *> LiveDecls)
|
||||
: liveStmts(LiveStmts), liveDecls(LiveDecls) {}
|
||||
|
||||
~LivenessValues() {}
|
||||
|
||||
bool isLive(const Stmt *S) const;
|
||||
bool isLive(const VarDecl *D) const;
|
||||
|
||||
@ -66,11 +64,10 @@ class LiveVariables : public ManagedAnalysis {
|
||||
/// Called when the live variables analysis registers
|
||||
/// that a variable is killed.
|
||||
virtual void observerKill(const DeclRefExpr *DR) {}
|
||||
};
|
||||
};
|
||||
|
||||
~LiveVariables() override;
|
||||
|
||||
virtual ~LiveVariables();
|
||||
|
||||
/// Compute the liveness information for a given CFG.
|
||||
static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext,
|
||||
bool killAtAssign);
|
||||
|
@ -26,6 +26,8 @@
|
||||
namespace clang {
|
||||
namespace threadSafety {
|
||||
|
||||
class BeforeSet;
|
||||
|
||||
/// 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 {
|
||||
@ -183,6 +185,14 @@ class ThreadSafetyHandler {
|
||||
virtual void handleFunExcludesLock(StringRef Kind, Name FunName,
|
||||
Name LockName, SourceLocation Loc) {}
|
||||
|
||||
|
||||
/// Warn that L1 cannot be acquired before L2.
|
||||
virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name,
|
||||
Name L2Name, SourceLocation Loc) {}
|
||||
|
||||
/// Warn that there is a cycle in acquired_before/after dependencies.
|
||||
virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {}
|
||||
|
||||
/// Called by the analysis when starting analysis of a function.
|
||||
/// Used to issue suggestions for changes to annotations.
|
||||
virtual void enterFunction(const FunctionDecl *FD) {}
|
||||
@ -203,7 +213,10 @@ class ThreadSafetyHandler {
|
||||
/// at the end of each block, and issue warnings for thread safety violations.
|
||||
/// Each block in the CFG is traversed exactly once.
|
||||
void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
|
||||
ThreadSafetyHandler &Handler);
|
||||
ThreadSafetyHandler &Handler,
|
||||
BeforeSet **Bset);
|
||||
|
||||
void threadSafetyCleanup(BeforeSet *Cache);
|
||||
|
||||
/// \brief Helper function that returns a LockKind required for the given level
|
||||
/// of access.
|
||||
|
@ -286,6 +286,14 @@ class CapabilityExpr {
|
||||
sx::partiallyMatches(CapExpr, other.CapExpr);
|
||||
}
|
||||
|
||||
const ValueDecl* valueDecl() const {
|
||||
if (Negated)
|
||||
return nullptr;
|
||||
if (auto *P = dyn_cast<til::Project>(CapExpr))
|
||||
return P->clangDecl();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
if (Negated)
|
||||
return "!" + sx::toString(CapExpr);
|
||||
@ -422,8 +430,8 @@ class SExprBuilder {
|
||||
}
|
||||
|
||||
private:
|
||||
BlockInfo(const BlockInfo &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const BlockInfo &) LLVM_DELETED_FUNCTION;
|
||||
BlockInfo(const BlockInfo &) = delete;
|
||||
void operator=(const BlockInfo &) = delete;
|
||||
};
|
||||
|
||||
// We implement the CFGVisitor API
|
||||
|
@ -282,7 +282,7 @@ class SExpr {
|
||||
/// SExpr objects cannot be deleted.
|
||||
// This declaration is public to workaround a gcc bug that breaks building
|
||||
// with REQUIRES_EH=1.
|
||||
void operator delete(void *) LLVM_DELETED_FUNCTION;
|
||||
void operator delete(void *) = delete;
|
||||
|
||||
/// Returns the instruction ID for this expression.
|
||||
/// All basic block instructions have a unique ID (i.e. virtual register).
|
||||
@ -309,10 +309,10 @@ class SExpr {
|
||||
BasicBlock* Block;
|
||||
|
||||
private:
|
||||
SExpr() LLVM_DELETED_FUNCTION;
|
||||
SExpr() = delete;
|
||||
|
||||
/// SExpr objects must be created in an arena.
|
||||
void *operator new(size_t) LLVM_DELETED_FUNCTION;
|
||||
void *operator new(size_t) = delete;
|
||||
};
|
||||
|
||||
|
||||
@ -424,7 +424,7 @@ class Future : public SExpr {
|
||||
Future() : SExpr(COP_Future), Status(FS_pending), Result(nullptr) {}
|
||||
|
||||
private:
|
||||
virtual ~Future() LLVM_DELETED_FUNCTION;
|
||||
virtual ~Future() = delete;
|
||||
|
||||
public:
|
||||
// A lazy rewriting strategy should subclass Future and override this method.
|
||||
|
@ -130,6 +130,8 @@ template <class T> class SimpleArray {
|
||||
|
||||
typedef T *iterator;
|
||||
typedef const T *const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
size_t size() const { return Size; }
|
||||
size_t capacity() const { return Capacity; }
|
||||
@ -160,6 +162,16 @@ template <class T> class SimpleArray {
|
||||
const_iterator cbegin() const { return Data; }
|
||||
const_iterator cend() const { return Data + Size; }
|
||||
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
void push_back(const T &Elem) {
|
||||
assert(Size < Capacity);
|
||||
Data[Size++] = Elem;
|
||||
@ -188,36 +200,12 @@ template <class T> class SimpleArray {
|
||||
return J - Osz;
|
||||
}
|
||||
|
||||
// An adaptor to reverse a simple array
|
||||
class ReverseAdaptor {
|
||||
public:
|
||||
ReverseAdaptor(SimpleArray &Array) : Array(Array) {}
|
||||
// A reverse iterator used by the reverse adaptor
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(T *Data) : Data(Data) {}
|
||||
T &operator*() { return *Data; }
|
||||
const T &operator*() const { return *Data; }
|
||||
Iterator &operator++() {
|
||||
--Data;
|
||||
return *this;
|
||||
}
|
||||
bool operator!=(Iterator Other) { return Data != Other.Data; }
|
||||
|
||||
private:
|
||||
T *Data;
|
||||
};
|
||||
Iterator begin() { return Array.end() - 1; }
|
||||
Iterator end() { return Array.begin() - 1; }
|
||||
const Iterator begin() const { return Array.end() - 1; }
|
||||
const Iterator end() const { return Array.begin() - 1; }
|
||||
|
||||
private:
|
||||
SimpleArray &Array;
|
||||
};
|
||||
|
||||
const ReverseAdaptor reverse() const { return ReverseAdaptor(*this); }
|
||||
ReverseAdaptor reverse() { return ReverseAdaptor(*this); }
|
||||
llvm::iterator_range<reverse_iterator> reverse() {
|
||||
return llvm::make_range(rbegin(), rend());
|
||||
}
|
||||
llvm::iterator_range<const_reverse_iterator> reverse() const {
|
||||
return llvm::make_range(rbegin(), rend());
|
||||
}
|
||||
|
||||
private:
|
||||
// std::max is annoying here, because it requires a reference,
|
||||
@ -226,7 +214,7 @@ template <class T> class SimpleArray {
|
||||
|
||||
static const size_t InitialCapacity = 4;
|
||||
|
||||
SimpleArray(const SimpleArray<T> &A) LLVM_DELETED_FUNCTION;
|
||||
SimpleArray(const SimpleArray<T> &A) = delete;
|
||||
|
||||
T *Data;
|
||||
size_t Size;
|
||||
@ -255,8 +243,8 @@ class CopyOnWriteVector {
|
||||
};
|
||||
|
||||
// No copy constructor or copy assignment. Use clone() with move assignment.
|
||||
CopyOnWriteVector(const CopyOnWriteVector &V) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const CopyOnWriteVector &V) LLVM_DELETED_FUNCTION;
|
||||
CopyOnWriteVector(const CopyOnWriteVector &V) = delete;
|
||||
void operator=(const CopyOnWriteVector &V) = delete;
|
||||
|
||||
public:
|
||||
CopyOnWriteVector() : Data(nullptr) {}
|
||||
|
@ -173,8 +173,8 @@ class AnalysisDeclContext {
|
||||
|
||||
typedef const VarDecl * const * referenced_decls_iterator;
|
||||
|
||||
std::pair<referenced_decls_iterator, referenced_decls_iterator>
|
||||
getReferencedBlockVars(const BlockDecl *BD);
|
||||
llvm::iterator_range<referenced_decls_iterator>
|
||||
getReferencedBlockVars(const BlockDecl *BD);
|
||||
|
||||
/// Return the ImplicitParamDecl* associated with 'self' if this
|
||||
/// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise.
|
||||
@ -289,7 +289,7 @@ class StackFrameContext : public LocationContext {
|
||||
Block(blk), Index(idx) {}
|
||||
|
||||
public:
|
||||
~StackFrameContext() {}
|
||||
~StackFrameContext() override {}
|
||||
|
||||
const Stmt *getCallSite() const { return CallSite; }
|
||||
|
||||
@ -324,7 +324,7 @@ class ScopeContext : public LocationContext {
|
||||
: LocationContext(Scope, ctx, parent), Enter(s) {}
|
||||
|
||||
public:
|
||||
~ScopeContext() {}
|
||||
~ScopeContext() override {}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) override;
|
||||
|
||||
@ -352,7 +352,7 @@ class BlockInvocationContext : public LocationContext {
|
||||
: LocationContext(Block, ctx, parent), BD(bd), ContextData(contextData) {}
|
||||
|
||||
public:
|
||||
~BlockInvocationContext() {}
|
||||
~BlockInvocationContext() override {}
|
||||
|
||||
const BlockDecl *getBlockDecl() const { return BD; }
|
||||
|
||||
|
@ -322,7 +322,7 @@ class CFGTerminator {
|
||||
Stmt &operator*() { return *getStmt(); }
|
||||
const Stmt &operator*() const { return *getStmt(); }
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return getStmt(); }
|
||||
explicit operator bool() const { return getStmt(); }
|
||||
};
|
||||
|
||||
/// CFGBlock - Represents a single basic block in a source-level CFG.
|
||||
@ -493,7 +493,6 @@ class CFGBlock {
|
||||
: Elements(C), Label(nullptr), Terminator(nullptr), LoopTarget(nullptr),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false),
|
||||
Parent(parent) {}
|
||||
~CFGBlock() {}
|
||||
|
||||
// Statement iterators
|
||||
typedef ElementList::iterator iterator;
|
||||
|
@ -17,14 +17,17 @@
|
||||
#define LLVM_CLANG_BASIC_ABI_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief C++ constructor types.
|
||||
enum CXXCtorType {
|
||||
Ctor_Complete, ///< Complete object ctor
|
||||
Ctor_Base, ///< Base object ctor
|
||||
Ctor_Comdat ///< The COMDAT used for ctors
|
||||
Ctor_Complete, ///< Complete object ctor
|
||||
Ctor_Base, ///< Base object ctor
|
||||
Ctor_Comdat, ///< The COMDAT used for ctors
|
||||
Ctor_CopyingClosure, ///< Copying closure variant of a ctor
|
||||
Ctor_DefaultClosure, ///< Default closure variant of a ctor
|
||||
};
|
||||
|
||||
/// \brief C++ destructor types.
|
||||
|
@ -144,6 +144,7 @@ class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
|
||||
class VariadicExprArgument<string name> : Argument<name, 1>;
|
||||
class VariadicStringArgument<string name> : Argument<name, 1>;
|
||||
|
||||
// A version of the form major.minor[.subminor].
|
||||
class VersionArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
@ -224,12 +225,14 @@ class SubjectList<list<AttrSubject> subjects, SubjectDiag diag = WarnDiag,
|
||||
string CustomDiag = customDiag;
|
||||
}
|
||||
|
||||
class LangOpt<string name> {
|
||||
class LangOpt<string name, bit negated = 0> {
|
||||
string Name = name;
|
||||
bit Negated = negated;
|
||||
}
|
||||
def MicrosoftExt : LangOpt<"MicrosoftExt">;
|
||||
def Borland : LangOpt<"Borland">;
|
||||
def CUDA : LangOpt<"CUDA">;
|
||||
def COnly : LangOpt<"CPlusPlus", 1>;
|
||||
|
||||
// Defines targets for target-specific attributes. The list of strings should
|
||||
// specify architectures for which the target applies, based off the ArchType
|
||||
@ -343,6 +346,8 @@ def AddressSpace : TypeAttr {
|
||||
def Alias : Attr {
|
||||
let Spellings = [GCC<"alias">];
|
||||
let Args = [StringArgument<"Aliasee">];
|
||||
let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag,
|
||||
"ExpectedFunctionGlobalVarMethodOrProperty">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
@ -436,8 +441,11 @@ def Availability : InheritableAttr {
|
||||
let AdditionalMembers =
|
||||
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
|
||||
return llvm::StringSwitch<llvm::StringRef>(Platform)
|
||||
.Case("android", "Android")
|
||||
.Case("ios", "iOS")
|
||||
.Case("macosx", "OS X")
|
||||
.Case("ios_app_extension", "iOS (App Extension)")
|
||||
.Case("macosx_app_extension", "OS X (App Extension)")
|
||||
.Default(llvm::StringRef());
|
||||
} }];
|
||||
let HasCustomParsing = 1;
|
||||
@ -574,7 +582,7 @@ def CUDAInvalidTarget : InheritableAttr {
|
||||
|
||||
def CUDALaunchBounds : InheritableAttr {
|
||||
let Spellings = [GNU<"launch_bounds">];
|
||||
let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>];
|
||||
let Args = [ExprArgument<"MaxThreads">, ExprArgument<"MinBlocks", 1>];
|
||||
let LangOpts = [CUDA];
|
||||
let Subjects = SubjectList<[ObjCMethod, FunctionLike], WarnDiag,
|
||||
"ExpectedFunctionOrMethod">;
|
||||
@ -707,6 +715,25 @@ def MinSize : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def FlagEnum : InheritableAttr {
|
||||
let Spellings = [GNU<"flag_enum">];
|
||||
let Subjects = SubjectList<[Enum]>;
|
||||
let Documentation = [FlagEnumDocs];
|
||||
let LangOpts = [COnly];
|
||||
let AdditionalMembers = [{
|
||||
private:
|
||||
llvm::APInt FlagBits;
|
||||
public:
|
||||
llvm::APInt &getFlagBits() {
|
||||
return FlagBits;
|
||||
}
|
||||
|
||||
const llvm::APInt &getFlagBits() const {
|
||||
return FlagBits;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def Flatten : InheritableAttr {
|
||||
let Spellings = [GCC<"flatten">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
@ -767,9 +794,9 @@ def IBOutletCollection : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def Malloc : InheritableAttr {
|
||||
let Spellings = [GCC<"malloc">];
|
||||
// let Subjects = [Function];
|
||||
def Restrict : InheritableAttr {
|
||||
let Spellings = [Declspec<"restrict">, GCC<"malloc">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
@ -958,7 +985,8 @@ def NoThrow : InheritableAttr {
|
||||
|
||||
def ObjCBridge : InheritableAttr {
|
||||
let Spellings = [GNU<"objc_bridge">];
|
||||
let Subjects = SubjectList<[Record], ErrorDiag>;
|
||||
let Subjects = SubjectList<[Record, TypedefName], ErrorDiag,
|
||||
"ExpectedStructOrUnionOrTypedef">;
|
||||
let Args = [IdentifierArgument<"BridgedType">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
@ -1031,6 +1059,11 @@ def ObjCNSObject : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def ObjCIndependentClass : InheritableAttr {
|
||||
let Spellings = [GNU<"objc_independent_class">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def ObjCPreciseLifetime : InheritableAttr {
|
||||
let Spellings = [GNU<"objc_precise_lifetime">];
|
||||
let Subjects = SubjectList<[Var], ErrorDiag>;
|
||||
@ -1118,12 +1151,6 @@ def Packed : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def PnaclCall : InheritableAttr {
|
||||
let Spellings = [GNU<"pnaclcall">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def IntelOclBicc : InheritableAttr {
|
||||
let Spellings = [GNU<"intel_ocl_bicc">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
@ -1360,26 +1387,35 @@ def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
// Attribute to disable AddressSanitizer (or equivalent) checks.
|
||||
def NoSanitizeAddress : InheritableAttr {
|
||||
def NoSanitize : InheritableAttr {
|
||||
let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">];
|
||||
let Args = [VariadicStringArgument<"Sanitizers">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeDocs];
|
||||
let AdditionalMembers = [{
|
||||
SanitizerMask getMask() const {
|
||||
SanitizerMask Mask = 0;
|
||||
for (auto SanitizerName : sanitizers()) {
|
||||
SanitizerMask ParsedMask =
|
||||
parseSanitizerValue(SanitizerName, /*AllowGroups=*/true);
|
||||
Mask |= expandSanitizerGroups(ParsedMask);
|
||||
}
|
||||
return Mask;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
// Attributes to disable a specific sanitizer. No new sanitizers should be added
|
||||
// to this list; the no_sanitize attribute should be extended instead.
|
||||
def NoSanitizeSpecific : InheritableAttr {
|
||||
let Spellings = [GCC<"no_address_safety_analysis">,
|
||||
GCC<"no_sanitize_address">];
|
||||
GCC<"no_sanitize_address">,
|
||||
GCC<"no_sanitize_thread">,
|
||||
GNU<"no_sanitize_memory">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeAddressDocs];
|
||||
}
|
||||
|
||||
// Attribute to disable ThreadSanitizer checks.
|
||||
def NoSanitizeThread : InheritableAttr {
|
||||
let Spellings = [GNU<"no_sanitize_thread">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeThreadDocs];
|
||||
}
|
||||
|
||||
// Attribute to disable MemorySanitizer checks.
|
||||
def NoSanitizeMemory : InheritableAttr {
|
||||
let Spellings = [GNU<"no_sanitize_memory">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [NoSanitizeMemoryDocs];
|
||||
let Documentation = [NoSanitizeAddressDocs, NoSanitizeThreadDocs,
|
||||
NoSanitizeMemoryDocs];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
|
||||
@ -1743,11 +1779,17 @@ def TypeTagForDatatype : InheritableAttr {
|
||||
|
||||
// Microsoft-related attributes
|
||||
|
||||
def MsProperty : IgnoredAttr {
|
||||
def MSNoVTable : InheritableAttr {
|
||||
let Spellings = [Declspec<"novtable">];
|
||||
let Subjects = SubjectList<[CXXRecord]>;
|
||||
let Documentation = [MSNoVTableDocs];
|
||||
}
|
||||
|
||||
def : IgnoredAttr {
|
||||
let Spellings = [Declspec<"property">];
|
||||
}
|
||||
|
||||
def MsStruct : InheritableAttr {
|
||||
def MSStruct : InheritableAttr {
|
||||
let Spellings = [GCC<"ms_struct">];
|
||||
let Subjects = SubjectList<[Record]>;
|
||||
let Documentation = [Undocumented];
|
||||
|
@ -920,6 +920,22 @@ This attribute accepts a single parameter that must be one of the following:
|
||||
}];
|
||||
}
|
||||
|
||||
def NoSanitizeDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Use the ``no_sanitize`` attribute on a function declaration to specify
|
||||
that a particular instrumentation or set of instrumentations should not be
|
||||
applied to that function. The attribute takes a list of string literals,
|
||||
which have the same meaning as values accepted by the ``-fno-sanitize=``
|
||||
flag. For example, ``__attribute__((no_sanitize("address", "thread")))``
|
||||
specifies that AddressSanitizer and ThreadSanitizer should not be applied
|
||||
to the function.
|
||||
|
||||
See :ref:`Controlling Code Generation <controlling-code-generation>` for a
|
||||
full list of supported sanitizer flags.
|
||||
}];
|
||||
}
|
||||
|
||||
def NoSanitizeAddressDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
// This function has multiple distinct spellings, and so it requires a custom
|
||||
@ -936,6 +952,7 @@ not be applied to that function.
|
||||
|
||||
def NoSanitizeThreadDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "no_sanitize_thread";
|
||||
let Content = [{
|
||||
.. _langext-thread_sanitizer:
|
||||
|
||||
@ -948,6 +965,7 @@ tool to avoid false positives and provide meaningful stack traces.
|
||||
|
||||
def NoSanitizeMemoryDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "no_sanitize_memory";
|
||||
let Content = [{
|
||||
.. _langext-memory_sanitizer:
|
||||
|
||||
@ -1196,6 +1214,16 @@ behavior of the program is undefined.
|
||||
}];
|
||||
}
|
||||
|
||||
def FlagEnumDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
This attribute can be added to an enumerator to signal to the compiler that it
|
||||
is intended to be used as a flag type. This will cause the compiler to assume
|
||||
that the range of the type includes all of the values that you can get by
|
||||
manipulating bits of the enumerator when issuing warnings.
|
||||
}];
|
||||
}
|
||||
|
||||
def MSInheritanceDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Heading = "__single_inhertiance, __multiple_inheritance, __virtual_inheritance";
|
||||
@ -1243,6 +1271,15 @@ an error:
|
||||
}];
|
||||
}
|
||||
|
||||
def MSNoVTableDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
This attribute can be added to a class declaration or definition to signal to
|
||||
the compiler that constructors and destructors will not reference the virtual
|
||||
function table.
|
||||
}];
|
||||
}
|
||||
|
||||
def OptnoneDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
@ -56,7 +56,8 @@
|
||||
// I -> Required to constant fold to an integer constant expression.
|
||||
//
|
||||
// Types may be postfixed with the following modifiers:
|
||||
// * -> pointer (optionally followed by an address space number)
|
||||
// * -> pointer (optionally followed by an address space number, if no address
|
||||
// space is specified than any address space will be accepted)
|
||||
// & -> reference (optionally followed by an address space number)
|
||||
// C -> const
|
||||
// D -> volatile
|
||||
@ -692,19 +693,29 @@ BUILTIN(__builtin_index, "c*cC*i", "Fn")
|
||||
BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
|
||||
|
||||
// Microsoft builtins. These are only active with -fms-extensions.
|
||||
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
|
||||
|
||||
// Microsoft library builtins.
|
||||
LIBBUILTIN(_setjmpex, "iJ", "fj", "setjmpex.h", ALL_MS_LANGUAGES)
|
||||
|
||||
// C99 library functions
|
||||
// C99 stdlib.h
|
||||
|
@ -143,6 +143,12 @@ class Context {
|
||||
return strchr(GetRecord(ID).Attributes, 't') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this builtin has a result or any arguments which
|
||||
/// are pointer types.
|
||||
bool hasPtrArgsOrResult(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Type, '*') != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Completely forget that the given ID was ever considered a builtin,
|
||||
/// e.g., because the user provided a conflicting signature.
|
||||
void ForgetBuiltin(unsigned ID, IdentifierTable &Table);
|
||||
|
@ -96,7 +96,7 @@ LANGBUILTIN(__sevl, "v", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__dmb, "vUi", "nc", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__dsb, "vUi", "nc", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__isb, "vUi", "nc", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__ldrexd, "WiCDWi*", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__ldrexd, "WiWiCD*", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_MoveFromCoprocessor, "UiUiUiUiUiUi", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_MoveFromCoprocessor2, "UiUiUiUiUiUi", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_MoveToCoprocessor, "vUiUiUiUiUiUi", "", ALL_MS_LANGUAGES)
|
||||
|
@ -26,6 +26,9 @@ BUILTIN(__builtin_altivec_vaddshs, "V8SsV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vadduhs, "V8UsV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vaddsws, "V4SiV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vadduws, "V4UiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vaddeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","")
|
||||
BUILTIN(__builtin_altivec_vaddcuq, "V1ULLLiV1ULLLiV1ULLLi","")
|
||||
BUILTIN(__builtin_altivec_vaddecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","")
|
||||
|
||||
BUILTIN(__builtin_altivec_vsubsbs, "V16ScV16ScV16Sc", "")
|
||||
BUILTIN(__builtin_altivec_vsububs, "V16UcV16UcV16Uc", "")
|
||||
@ -33,6 +36,9 @@ BUILTIN(__builtin_altivec_vsubshs, "V8SsV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vsubuhs, "V8UsV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vsubsws, "V4SiV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vsubuws, "V4UiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vsubeuqm, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","")
|
||||
BUILTIN(__builtin_altivec_vsubcuq, "V1ULLLiV1ULLLiV1ULLLi","")
|
||||
BUILTIN(__builtin_altivec_vsubecuq, "V1ULLLiV1ULLLiV1ULLLiV1ULLLi","")
|
||||
|
||||
BUILTIN(__builtin_altivec_vavgsb, "V16ScV16ScV16Sc", "")
|
||||
BUILTIN(__builtin_altivec_vavgub, "V16UcV16UcV16Uc", "")
|
||||
@ -85,10 +91,14 @@ BUILTIN(__builtin_altivec_vmuleub, "V8UsV16UcV16Uc", "")
|
||||
BUILTIN(__builtin_altivec_vmulesb, "V8SsV16ScV16Sc", "")
|
||||
BUILTIN(__builtin_altivec_vmuleuh, "V4UiV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vmulesh, "V4SiV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vmuleuw, "V2ULLiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vmulesw, "V2SLLiV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vmuloub, "V8UsV16UcV16Uc", "")
|
||||
BUILTIN(__builtin_altivec_vmulosb, "V8SsV16ScV16Sc", "")
|
||||
BUILTIN(__builtin_altivec_vmulouh, "V4UiV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vmulosh, "V4SiV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vmulouw, "V2ULLiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vmulosw, "V2SLLiV4SiV4Si", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vnmsubfp, "V4fV4fV4fV4f", "")
|
||||
|
||||
@ -99,6 +109,10 @@ BUILTIN(__builtin_altivec_vpkuwus, "V8UsV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vpkswss, "V8SsV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vpkshus, "V16UcV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vpkswus, "V8UsV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vpksdss, "V4SiV2SLLiV2SLLi", "")
|
||||
BUILTIN(__builtin_altivec_vpksdus, "V4UiV2SLLiV2SLLi", "")
|
||||
BUILTIN(__builtin_altivec_vpkudus, "V4UiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_vpkudum, "V4UiV2ULLiV2ULLi", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vperm_4si, "V4iV4iV4iV16Uc", "")
|
||||
|
||||
@ -115,6 +129,7 @@ BUILTIN(__builtin_altivec_vcmpgefp, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequb, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequh, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequw, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequd, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpeqfp, "V4iV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vcmpgtsb, "V16cV16ScV16Sc", "")
|
||||
@ -123,6 +138,8 @@ BUILTIN(__builtin_altivec_vcmpgtsh, "V8sV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtuh, "V8sV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtsw, "V4iV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtuw, "V4iV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtsd, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtud, "V2LLiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtfp, "V4iV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vmaxsb, "V16ScV16ScV16Sc", "")
|
||||
@ -131,6 +148,8 @@ BUILTIN(__builtin_altivec_vmaxsh, "V8SsV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vmaxuh, "V8UsV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vmaxsw, "V4SiV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vmaxuw, "V4UiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vmaxsd, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_altivec_vmaxud, "V2ULLiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_vmaxfp, "V4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_mfvscr, "V8Us", "")
|
||||
@ -141,6 +160,8 @@ BUILTIN(__builtin_altivec_vminsh, "V8SsV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vminuh, "V8UsV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vminsw, "V4SiV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vminuw, "V4UiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vminsd, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_altivec_vminud, "V2ULLiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_vminfp, "V4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_mtvscr, "vV4i", "")
|
||||
@ -150,6 +171,7 @@ BUILTIN(__builtin_altivec_vrefp, "V4fV4f", "")
|
||||
BUILTIN(__builtin_altivec_vrlb, "V16cV16cV16Uc", "")
|
||||
BUILTIN(__builtin_altivec_vrlh, "V8sV8sV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vrlw, "V4iV4iV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vrld, "V2LLiV2LLiV2ULLi", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vsel_4si, "V4iV4iV4iV4Ui", "")
|
||||
|
||||
@ -182,10 +204,12 @@ BUILTIN(__builtin_altivec_vrfiz, "V4fV4f", "")
|
||||
BUILTIN(__builtin_altivec_vupkhsb, "V8sV16c", "")
|
||||
BUILTIN(__builtin_altivec_vupkhpx, "V4UiV8s", "")
|
||||
BUILTIN(__builtin_altivec_vupkhsh, "V4iV8s", "")
|
||||
BUILTIN(__builtin_altivec_vupkhsw, "V2LLiV4i", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vupklsb, "V8sV16c", "")
|
||||
BUILTIN(__builtin_altivec_vupklpx, "V4UiV8s", "")
|
||||
BUILTIN(__builtin_altivec_vupklsh, "V4iV8s", "")
|
||||
BUILTIN(__builtin_altivec_vupklsw, "V2LLiV4i", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vcmpbfp_p, "iiV4fV4f", "")
|
||||
|
||||
@ -194,6 +218,7 @@ BUILTIN(__builtin_altivec_vcmpgefp_p, "iiV4fV4f", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequb_p, "iiV16cV16c", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequh_p, "iiV8sV8s", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequw_p, "iiV4iV4i", "")
|
||||
BUILTIN(__builtin_altivec_vcmpequd_p, "iiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpeqfp_p, "iiV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vcmpgtsb_p, "iiV16ScV16Sc", "")
|
||||
@ -202,8 +227,24 @@ BUILTIN(__builtin_altivec_vcmpgtsh_p, "iiV8SsV8Ss", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtuh_p, "iiV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtsd_p, "iiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtud_p, "iiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "")
|
||||
|
||||
// P8 Crypto built-ins.
|
||||
BUILTIN(__builtin_altivec_crypto_vsbox, "V2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpermxor, "V16UcV16UcV16UcV16Uc", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vshasigmaw, "V4UiV4UiIiIi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vshasigmad, "V2ULLiV2ULLiIiIi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vcipher, "V2ULLiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vcipherlast, "V2ULLiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vncipher, "V2ULLiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vncipherlast, "V2ULLiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpmsumb, "V16UcV16UcV16Uc", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpmsumh, "V8UsV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpmsumw, "V4UiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpmsumd, "V2ULLiV2ULLiV2ULLi", "")
|
||||
|
||||
// VSX built-ins.
|
||||
|
||||
BUILTIN(__builtin_vsx_lxvd2x, "V2divC*", "")
|
||||
@ -223,6 +264,44 @@ BUILTIN(__builtin_vsx_xsmindp, "ddd", "")
|
||||
BUILTIN(__builtin_vsx_xvdivdp, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvdivsp, "V4fV4fV4f", "")
|
||||
|
||||
// HTM builtins
|
||||
BUILTIN(__builtin_tbegin, "UiUIi", "")
|
||||
BUILTIN(__builtin_tend, "UiUIi", "")
|
||||
|
||||
BUILTIN(__builtin_tabort, "UiUi", "")
|
||||
BUILTIN(__builtin_tabortdc, "UiUiUiUi", "")
|
||||
BUILTIN(__builtin_tabortdci, "UiUiUii", "")
|
||||
BUILTIN(__builtin_tabortwc, "UiUiUiUi", "")
|
||||
BUILTIN(__builtin_tabortwci, "UiUiUii", "")
|
||||
|
||||
BUILTIN(__builtin_tcheck, "Ui", "")
|
||||
BUILTIN(__builtin_treclaim, "UiUi", "")
|
||||
BUILTIN(__builtin_trechkpt, "Ui", "")
|
||||
BUILTIN(__builtin_tsr, "UiUi", "")
|
||||
|
||||
BUILTIN(__builtin_tendall, "Ui", "")
|
||||
BUILTIN(__builtin_tresume, "Ui", "")
|
||||
BUILTIN(__builtin_tsuspend, "Ui", "")
|
||||
|
||||
BUILTIN(__builtin_get_texasr, "LUi", "c")
|
||||
BUILTIN(__builtin_get_texasru, "LUi", "c")
|
||||
BUILTIN(__builtin_get_tfhar, "LUi", "c")
|
||||
BUILTIN(__builtin_get_tfiar, "LUi", "c")
|
||||
|
||||
BUILTIN(__builtin_set_texasr, "vLUi", "c")
|
||||
BUILTIN(__builtin_set_texasru, "vLUi", "c")
|
||||
BUILTIN(__builtin_set_tfhar, "vLUi", "c")
|
||||
BUILTIN(__builtin_set_tfiar, "vLUi", "c")
|
||||
|
||||
BUILTIN(__builtin_ttest, "LUi", "")
|
||||
|
||||
// Scalar built-ins
|
||||
BUILTIN(__builtin_divwe, "SiSiSi", "")
|
||||
BUILTIN(__builtin_divweu, "UiUiUi", "")
|
||||
BUILTIN(__builtin_divde, "SLLiSLLiSLLi", "")
|
||||
BUILTIN(__builtin_divdeu, "ULLiULLiULLi", "")
|
||||
BUILTIN(__builtin_bpermd, "SLLiSLLiSLLi", "")
|
||||
|
||||
// FIXME: Obviously incomplete.
|
||||
|
||||
#undef BUILTIN
|
||||
|
252
include/clang/Basic/BuiltinsSystemZ.def
Normal file
252
include/clang/Basic/BuiltinsSystemZ.def
Normal file
@ -0,0 +1,252 @@
|
||||
//===-- BuiltinsSystemZ.def - SystemZ Builtin function database -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SystemZ-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The format of this database matches clang/Basic/Builtins.def.
|
||||
|
||||
// Transactional-memory intrinsics
|
||||
BUILTIN(__builtin_tbegin, "iv*", "j")
|
||||
BUILTIN(__builtin_tbegin_nofloat, "iv*", "j")
|
||||
BUILTIN(__builtin_tbeginc, "v", "nj")
|
||||
BUILTIN(__builtin_tabort, "vi", "r")
|
||||
BUILTIN(__builtin_tend, "i", "n")
|
||||
BUILTIN(__builtin_tx_nesting_depth, "i", "nc")
|
||||
BUILTIN(__builtin_tx_assist, "vi", "n")
|
||||
BUILTIN(__builtin_non_tx_store, "vULi*ULi", "")
|
||||
|
||||
// Vector intrinsics.
|
||||
// These all map directly to z instructions, except that some variants ending
|
||||
// in "s" have a final "int *" that receives the post-instruction CC value.
|
||||
|
||||
// Vector support instructions (chapter 21 of the PoP)
|
||||
BUILTIN(__builtin_s390_lcbb, "UivC*Ii", "nc")
|
||||
BUILTIN(__builtin_s390_vlbb, "V16ScvC*Ii", "")
|
||||
BUILTIN(__builtin_s390_vll, "V16ScUivC*", "")
|
||||
BUILTIN(__builtin_s390_vstl, "vV16ScUiv*", "")
|
||||
BUILTIN(__builtin_s390_vperm, "V16UcV16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vpdi, "V2ULLiV2ULLiV2ULLiIi", "nc")
|
||||
BUILTIN(__builtin_s390_vpksh, "V16ScV8SsV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vpkshs, "V16ScV8SsV8Ssi*", "nc")
|
||||
BUILTIN(__builtin_s390_vpksf, "V8SsV4SiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vpksfs, "V8SsV4SiV4Sii*", "nc")
|
||||
BUILTIN(__builtin_s390_vpksg, "V4SiV2SLLiV2SLLi", "nc")
|
||||
BUILTIN(__builtin_s390_vpksgs, "V4SiV2SLLiV2SLLii*", "nc")
|
||||
BUILTIN(__builtin_s390_vpklsh, "V16UcV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vpklshs, "V16UcV8UsV8Usi*", "nc")
|
||||
BUILTIN(__builtin_s390_vpklsf, "V8UsV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vpklsfs, "V8UsV4UiV4Uii*", "nc")
|
||||
BUILTIN(__builtin_s390_vpklsg, "V4UiV2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vpklsgs, "V4UiV2ULLiV2ULLii*", "nc")
|
||||
BUILTIN(__builtin_s390_vuphb, "V8SsV16Sc", "nc")
|
||||
BUILTIN(__builtin_s390_vuphh, "V4SiV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vuphf, "V2SLLiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vuplb, "V8SsV16Sc", "nc")
|
||||
BUILTIN(__builtin_s390_vuplhw, "V4SiV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vuplf, "V2SLLiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vuplhb, "V8UsV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vuplhh, "V4UiV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vuplhf, "V2ULLiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vupllb, "V8UsV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vupllh, "V4UiV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vupllf, "V2ULLiV4Ui", "nc")
|
||||
|
||||
// Vector integer instructions (chapter 22 of the PoP)
|
||||
BUILTIN(__builtin_s390_vaq, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vacq, "V16UcV16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vaccb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vacch, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vaccf, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vaccg, "V2ULLiV2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vaccq, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vacccq, "V16UcV16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vavgb, "V16ScV16ScV16Sc", "nc")
|
||||
BUILTIN(__builtin_s390_vavgh, "V8SsV8SsV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vavgf, "V4SiV4SiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vavgg, "V2SLLiV2SLLiV2SLLi", "nc")
|
||||
BUILTIN(__builtin_s390_vavglb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vavglh, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vavglf, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vavglg, "V2ULLiV2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vceqbs, "V16ScV16ScV16Sci*", "nc")
|
||||
BUILTIN(__builtin_s390_vceqhs, "V8SsV8SsV8Ssi*", "nc")
|
||||
BUILTIN(__builtin_s390_vceqfs, "V4SiV4SiV4Sii*", "nc")
|
||||
BUILTIN(__builtin_s390_vceqgs, "V2SLLiV2SLLiV2SLLii*", "nc")
|
||||
BUILTIN(__builtin_s390_vchbs, "V16ScV16ScV16Sci*", "nc")
|
||||
BUILTIN(__builtin_s390_vchhs, "V8SsV8SsV8Ssi*", "nc")
|
||||
BUILTIN(__builtin_s390_vchfs, "V4SiV4SiV4Sii*", "nc")
|
||||
BUILTIN(__builtin_s390_vchgs, "V2SLLiV2SLLiV2SLLii*", "nc")
|
||||
BUILTIN(__builtin_s390_vchlbs, "V16ScV16UcV16Uci*", "nc")
|
||||
BUILTIN(__builtin_s390_vchlhs, "V8SsV8UsV8Usi*", "nc")
|
||||
BUILTIN(__builtin_s390_vchlfs, "V4SiV4UiV4Uii*", "nc")
|
||||
BUILTIN(__builtin_s390_vchlgs, "V2SLLiV2ULLiV2ULLii*", "nc")
|
||||
BUILTIN(__builtin_s390_vcksm, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vclzb, "V16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vclzh, "V8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vclzf, "V4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vclzg, "V2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vctzb, "V16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vctzh, "V8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vctzf, "V4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vctzg, "V2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_verimb, "V16UcV16UcV16UcV16UcIi", "nc")
|
||||
BUILTIN(__builtin_s390_verimh, "V8UsV8UsV8UsV8UsIi", "nc")
|
||||
BUILTIN(__builtin_s390_verimf, "V4UiV4UiV4UiV4UiIi", "nc")
|
||||
BUILTIN(__builtin_s390_verimg, "V2ULLiV2ULLiV2ULLiV2ULLiIi", "nc")
|
||||
BUILTIN(__builtin_s390_verllb, "V16UcV16UcUi", "nc")
|
||||
BUILTIN(__builtin_s390_verllh, "V8UsV8UsUi", "nc")
|
||||
BUILTIN(__builtin_s390_verllf, "V4UiV4UiUi", "nc")
|
||||
BUILTIN(__builtin_s390_verllg, "V2ULLiV2ULLiUi", "nc")
|
||||
BUILTIN(__builtin_s390_verllvb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_verllvh, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_verllvf, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_verllvg, "V2ULLiV2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmb, "V8UsV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmh, "V4UiV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmf, "V2ULLiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmg, "V16UcV2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmab, "V8UsV16UcV16UcV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmah, "V4UiV8UsV8UsV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmaf, "V2ULLiV4UiV4UiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vgfmag, "V16UcV2ULLiV2ULLiV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vmahb, "V16ScV16ScV16ScV16Sc", "nc")
|
||||
BUILTIN(__builtin_s390_vmahh, "V8SsV8SsV8SsV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vmahf, "V4SiV4SiV4SiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vmalhb, "V16UcV16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vmalhh, "V8UsV8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vmalhf, "V4UiV4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vmaeb, "V8SsV16ScV16ScV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vmaeh, "V4SiV8SsV8SsV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vmaef, "V2SLLiV4SiV4SiV2SLLi", "nc")
|
||||
BUILTIN(__builtin_s390_vmaleb, "V8UsV16UcV16UcV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vmaleh, "V4UiV8UsV8UsV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vmalef, "V2ULLiV4UiV4UiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vmaob, "V8SsV16ScV16ScV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vmaoh, "V4SiV8SsV8SsV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vmaof, "V2SLLiV4SiV4SiV2SLLi", "nc")
|
||||
BUILTIN(__builtin_s390_vmalob, "V8UsV16UcV16UcV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vmaloh, "V4UiV8UsV8UsV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vmalof, "V2ULLiV4UiV4UiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vmhb, "V16ScV16ScV16Sc", "nc")
|
||||
BUILTIN(__builtin_s390_vmhh, "V8SsV8SsV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vmhf, "V4SiV4SiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vmlhb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vmlhh, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vmlhf, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vmeb, "V8SsV16ScV16Sc", "nc")
|
||||
BUILTIN(__builtin_s390_vmeh, "V4SiV8SsV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vmef, "V2SLLiV4SiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vmleb, "V8UsV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vmleh, "V4UiV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vmlef, "V2ULLiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vmob, "V8SsV16ScV16Sc", "nc")
|
||||
BUILTIN(__builtin_s390_vmoh, "V4SiV8SsV8Ss", "nc")
|
||||
BUILTIN(__builtin_s390_vmof, "V2SLLiV4SiV4Si", "nc")
|
||||
BUILTIN(__builtin_s390_vmlob, "V8UsV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vmloh, "V4UiV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vmlof, "V2ULLiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vpopctb, "V16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vpopcth, "V8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vpopctf, "V4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vpopctg, "V2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vsq, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsbcbiq, "V16UcV16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsbiq, "V16UcV16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vscbib, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vscbih, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vscbif, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vscbig, "V2ULLiV2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vscbiq, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsl, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vslb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsldb, "V16UcV16UcV16UcIi", "nc")
|
||||
BUILTIN(__builtin_s390_vsra, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsrab, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsrl, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsrlb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsumb, "V4UiV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vsumh, "V4UiV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vsumgh, "V2ULLiV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vsumgf, "V2ULLiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vsumqf, "V16UcV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vsumqg, "V16UcV2ULLiV2ULLi", "nc")
|
||||
BUILTIN(__builtin_s390_vtm, "iV16UcV16Uc", "nc")
|
||||
|
||||
// Vector string instructions (chapter 23 of the PoP)
|
||||
BUILTIN(__builtin_s390_vfaeb, "V16UcV16UcV16UcIi", "nc")
|
||||
BUILTIN(__builtin_s390_vfaebs, "V16UcV16UcV16UcIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfaeh, "V8UsV8UsV8UsIi", "nc")
|
||||
BUILTIN(__builtin_s390_vfaehs, "V8UsV8UsV8UsIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfaef, "V4UiV4UiV4UiIi", "nc")
|
||||
BUILTIN(__builtin_s390_vfaefs, "V4UiV4UiV4UiIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfaezb, "V16UcV16UcV16UcIi", "nc")
|
||||
BUILTIN(__builtin_s390_vfaezbs, "V16UcV16UcV16UcIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfaezh, "V8UsV8UsV8UsIi", "nc")
|
||||
BUILTIN(__builtin_s390_vfaezhs, "V8UsV8UsV8UsIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfaezf, "V4UiV4UiV4UiIi", "nc")
|
||||
BUILTIN(__builtin_s390_vfaezfs, "V4UiV4UiV4UiIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeeb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vfeebs, "V16UcV16UcV16Uci*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeeh, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vfeehs, "V8UsV8UsV8Usi*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeef, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vfeefs, "V4UiV4UiV4Uii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeezb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vfeezbs, "V16UcV16UcV16Uci*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeezh, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vfeezhs, "V8UsV8UsV8Usi*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeezf, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vfeezfs, "V4UiV4UiV4Uii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeneb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vfenebs, "V16UcV16UcV16Uci*", "nc")
|
||||
BUILTIN(__builtin_s390_vfeneh, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vfenehs, "V8UsV8UsV8Usi*", "nc")
|
||||
BUILTIN(__builtin_s390_vfenef, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vfenefs, "V4UiV4UiV4Uii*", "nc")
|
||||
BUILTIN(__builtin_s390_vfenezb, "V16UcV16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vfenezbs, "V16UcV16UcV16Uci*", "nc")
|
||||
BUILTIN(__builtin_s390_vfenezh, "V8UsV8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vfenezhs, "V8UsV8UsV8Usi*", "nc")
|
||||
BUILTIN(__builtin_s390_vfenezf, "V4UiV4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vfenezfs, "V4UiV4UiV4Uii*", "nc")
|
||||
BUILTIN(__builtin_s390_vistrb, "V16UcV16Uc", "nc")
|
||||
BUILTIN(__builtin_s390_vistrbs, "V16UcV16Uci*", "nc")
|
||||
BUILTIN(__builtin_s390_vistrh, "V8UsV8Us", "nc")
|
||||
BUILTIN(__builtin_s390_vistrhs, "V8UsV8Usi*", "nc")
|
||||
BUILTIN(__builtin_s390_vistrf, "V4UiV4Ui", "nc")
|
||||
BUILTIN(__builtin_s390_vistrfs, "V4UiV4Uii*", "nc")
|
||||
BUILTIN(__builtin_s390_vstrcb, "V16UcV16UcV16UcV16UcIi", "nc")
|
||||
BUILTIN(__builtin_s390_vstrcbs, "V16UcV16UcV16UcV16UcIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vstrch, "V8UsV8UsV8UsV8UsIi", "nc")
|
||||
BUILTIN(__builtin_s390_vstrchs, "V8UsV8UsV8UsV8UsIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vstrcf, "V4UiV4UiV4UiV4UiIi", "nc")
|
||||
BUILTIN(__builtin_s390_vstrcfs, "V4UiV4UiV4UiV4UiIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vstrczb, "V16UcV16UcV16UcV16UcIi", "nc")
|
||||
BUILTIN(__builtin_s390_vstrczbs, "V16UcV16UcV16UcV16UcIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vstrczh, "V8UsV8UsV8UsV8UsIi", "nc")
|
||||
BUILTIN(__builtin_s390_vstrczhs, "V8UsV8UsV8UsV8UsIii*", "nc")
|
||||
BUILTIN(__builtin_s390_vstrczf, "V4UiV4UiV4UiV4UiIi", "nc")
|
||||
BUILTIN(__builtin_s390_vstrczfs, "V4UiV4UiV4UiV4UiIii*", "nc")
|
||||
|
||||
// Vector floating-point instructions (chapter 24 of the PoP)
|
||||
BUILTIN(__builtin_s390_vfcedbs, "V2SLLiV2dV2di*", "nc")
|
||||
BUILTIN(__builtin_s390_vfchdbs, "V2SLLiV2dV2di*", "nc")
|
||||
BUILTIN(__builtin_s390_vfchedbs, "V2SLLiV2dV2di*", "nc")
|
||||
BUILTIN(__builtin_s390_vfidb, "V2dV2dIiIi", "nc")
|
||||
BUILTIN(__builtin_s390_vflndb, "V2dV2d", "nc")
|
||||
BUILTIN(__builtin_s390_vflpdb, "V2dV2d", "nc")
|
||||
BUILTIN(__builtin_s390_vfmadb, "V2dV2dV2dV2d", "nc")
|
||||
BUILTIN(__builtin_s390_vfmsdb, "V2dV2dV2dV2d", "nc")
|
||||
BUILTIN(__builtin_s390_vfsqdb, "V2dV2d", "nc")
|
||||
BUILTIN(__builtin_s390_vftcidb, "V2SLLiV2dIii*", "nc")
|
||||
|
||||
#undef BUILTIN
|
@ -316,8 +316,6 @@ BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psrlw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psrld128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLiIi", "")
|
||||
BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLiIi", "")
|
||||
BUILTIN(__builtin_ia32_psrlq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "")
|
||||
@ -338,9 +336,6 @@ BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "")
|
||||
BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fIc", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8sIc", "")
|
||||
BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2dIc", "")
|
||||
BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fIc", "")
|
||||
BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "")
|
||||
|
||||
@ -436,16 +431,11 @@ BUILTIN(__builtin_ia32_vpermilvarpd, "V2dV2dV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_vpermilvarps, "V4fV4fV4i", "")
|
||||
BUILTIN(__builtin_ia32_vpermilvarpd256, "V4dV4dV4LLi", "")
|
||||
BUILTIN(__builtin_ia32_vpermilvarps256, "V8fV8fV8i", "")
|
||||
BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4dIc", "")
|
||||
BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fIc", "")
|
||||
BUILTIN(__builtin_ia32_blendvpd256, "V4dV4dV4dV4d", "")
|
||||
BUILTIN(__builtin_ia32_blendvps256, "V8fV8fV8fV8f", "")
|
||||
BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIc", "")
|
||||
BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dIc", "")
|
||||
BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fIc", "")
|
||||
BUILTIN(__builtin_ia32_vextractf128_pd256, "V2dV4dIc", "")
|
||||
BUILTIN(__builtin_ia32_vextractf128_ps256, "V4fV8fIc", "")
|
||||
BUILTIN(__builtin_ia32_vextractf128_si256, "V4iV8iIc", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2pd256, "V4dV4i", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2ps256, "V8fV8i", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2ps256, "V4fV4d", "")
|
||||
@ -457,9 +447,6 @@ BUILTIN(__builtin_ia32_cvttps2dq256, "V8iV8f", "")
|
||||
BUILTIN(__builtin_ia32_vperm2f128_pd256, "V4dV4dV4dIc", "")
|
||||
BUILTIN(__builtin_ia32_vperm2f128_ps256, "V8fV8fV8fIc", "")
|
||||
BUILTIN(__builtin_ia32_vperm2f128_si256, "V8iV8iV8iIc", "")
|
||||
BUILTIN(__builtin_ia32_vinsertf128_pd256, "V4dV4dV2dIc", "")
|
||||
BUILTIN(__builtin_ia32_vinsertf128_ps256, "V8fV8fV4fIc", "")
|
||||
BUILTIN(__builtin_ia32_vinsertf128_si256, "V8iV8iV4iIc", "")
|
||||
BUILTIN(__builtin_ia32_sqrtpd256, "V4dV4d", "")
|
||||
BUILTIN(__builtin_ia32_sqrtps256, "V8fV8f", "")
|
||||
BUILTIN(__builtin_ia32_rsqrtps256, "V8fV8f", "")
|
||||
@ -524,7 +511,6 @@ BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIc", "")
|
||||
BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "")
|
||||
BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "")
|
||||
BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "")
|
||||
BUILTIN(__builtin_ia32_pblendw256, "V16sV16sV16sIc", "")
|
||||
BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "")
|
||||
BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "")
|
||||
BUILTIN(__builtin_ia32_phaddsw256, "V16sV16sV16s", "")
|
||||
@ -590,9 +576,6 @@ BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLi*", "")
|
||||
BUILTIN(__builtin_ia32_vbroadcastss_ps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_vbroadcastss_ps256, "V8fV4f", "")
|
||||
BUILTIN(__builtin_ia32_vbroadcastsd_pd256, "V4dV2d", "")
|
||||
BUILTIN(__builtin_ia32_vbroadcastsi256, "V4LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIc", "")
|
||||
BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIc", "")
|
||||
BUILTIN(__builtin_ia32_pbroadcastb256, "V32cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pbroadcastw256, "V16sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pbroadcastd256, "V8iV4i", "")
|
||||
@ -604,8 +587,6 @@ BUILTIN(__builtin_ia32_pbroadcastq128, "V2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "")
|
||||
BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8f", "")
|
||||
BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "")
|
||||
BUILTIN(__builtin_ia32_extract128i256, "V2LLiV4LLiIc", "")
|
||||
BUILTIN(__builtin_ia32_insert128i256, "V4LLiV4LLiV2LLiIc", "")
|
||||
BUILTIN(__builtin_ia32_maskloadd256, "V8iV8iC*V8i", "")
|
||||
BUILTIN(__builtin_ia32_maskloadq256, "V4LLiV4LLiC*V4LLi", "")
|
||||
BUILTIN(__builtin_ia32_maskloadd, "V4iV4iC*V4i", "")
|
||||
@ -738,12 +719,12 @@ BUILTIN(__builtin_ia32_vfmaddsubps256, "V8fV8fV8fV8f", "")
|
||||
BUILTIN(__builtin_ia32_vfmaddsubpd256, "V4dV4dV4dV4d", "")
|
||||
BUILTIN(__builtin_ia32_vfmsubaddps256, "V8fV8fV8fV8f", "")
|
||||
BUILTIN(__builtin_ia32_vfmsubaddpd256, "V4dV4dV4dV4d", "")
|
||||
BUILTIN(__builtin_ia32_vfmaddpd512_mask, "V8dV8dV8dV8dUci", "")
|
||||
BUILTIN(__builtin_ia32_vfmsubpd512_mask, "V8dV8dV8dV8dUci", "")
|
||||
BUILTIN(__builtin_ia32_vfnmaddpd512_mask, "V8dV8dV8dV8dUci", "")
|
||||
BUILTIN(__builtin_ia32_vfmaddps512_mask, "V16fV16fV16fV16fUsi", "")
|
||||
BUILTIN(__builtin_ia32_vfmsubps512_mask, "V16fV16fV16fV16fUsi", "")
|
||||
BUILTIN(__builtin_ia32_vfnmaddps512_mask, "V16fV16fV16fV16fUsi", "")
|
||||
BUILTIN(__builtin_ia32_vfmaddpd512_mask, "V8dV8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_vfmsubpd512_mask, "V8dV8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_vfnmaddpd512_mask, "V8dV8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_vfmaddps512_mask, "V16fV16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_vfmsubps512_mask, "V16fV16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_vfnmaddps512_mask, "V16fV16fV16fV16fUsIi", "")
|
||||
|
||||
// XOP
|
||||
BUILTIN(__builtin_ia32_vpmacssww, "V8sV8sV8sV8s", "")
|
||||
@ -820,29 +801,33 @@ BUILTIN(__builtin_ia32_rdtsc, "ULLi", "")
|
||||
BUILTIN(__builtin_ia32_rdtscp, "ULLiUi*", "")
|
||||
|
||||
// AVX-512
|
||||
BUILTIN(__builtin_ia32_sqrtpd512_mask, "V8dV8dV8dUciC", "")
|
||||
BUILTIN(__builtin_ia32_sqrtps512_mask, "V16fV16fV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_sqrtpd512_mask, "V8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_sqrtps512_mask, "V16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt14sd_mask, "V2dV2dV2dV2dUc", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt14ss_mask, "V4fV4fV4fV4fUc", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt14pd512_mask, "V8dV8dV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt14ps512_mask, "V16fV16fV16fUs", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28sd_mask, "V2dV2dV2dV2dUciC", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28ss_mask, "V4fV4fV4fV4fUciC", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28pd_mask, "V8dV8dV8dUciC", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28ps_mask, "V16fV16fV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28sd_mask, "V2dV2dV2dV2dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28ss_mask, "V4fV4fV4fV4fUcIi", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28pd_mask, "V8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_rsqrt28ps_mask, "V16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_rcp14sd_mask, "V2dV2dV2dV2dUc", "")
|
||||
BUILTIN(__builtin_ia32_rcp14ss_mask, "V4fV4fV4fV4fUc", "")
|
||||
BUILTIN(__builtin_ia32_rcp14pd512_mask, "V8dV8dV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_rcp14ps512_mask, "V16fV16fV16fUs", "")
|
||||
BUILTIN(__builtin_ia32_rcp28sd_mask, "V2dV2dV2dV2dUciC", "")
|
||||
BUILTIN(__builtin_ia32_rcp28ss_mask, "V4fV4fV4fV4fUciC", "")
|
||||
BUILTIN(__builtin_ia32_rcp28pd_mask, "V8dV8dV8dUciC", "")
|
||||
BUILTIN(__builtin_ia32_rcp28ps_mask, "V16fV16fV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2dq512_mask, "V16iV16fV16iUsiC", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2udq512_mask, "V16iV16fV16iUsiC", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2dq512_mask, "V8iV8dV8iUciC", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2udq512_mask, "V8iV8dV8iUciC", "")
|
||||
BUILTIN(__builtin_ia32_cmpps512_mask, "UsV16fV16fiCUsi", "")
|
||||
BUILTIN(__builtin_ia32_rcp28sd_mask, "V2dV2dV2dV2dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_rcp28ss_mask, "V4fV4fV4fV4fUcIi", "")
|
||||
BUILTIN(__builtin_ia32_rcp28pd_mask, "V8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_rcp28ps_mask, "V16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_exp2pd_mask, "V8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_exp2ps_mask, "V16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2dq512_mask, "V16iV16fV16iUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2udq512_mask, "V16iV16fV16iUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2dq512_mask, "V8iV8dV8iUcIi", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2udq512_mask, "V8iV8dV8iUcIi", "")
|
||||
BUILTIN(__builtin_ia32_cmpps512_mask, "UsV16fV16fIiUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cmpps256_mask, "UcV8fV8fIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmpps128_mask, "UcV4fV4fIiUc", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqb512_mask, "LLiV64cV64cLLi", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqd512_mask, "sV16iV16is", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqq512_mask, "cV8LLiV8LLic", "")
|
||||
@ -855,24 +840,44 @@ BUILTIN(__builtin_ia32_pcmpeqb128_mask, "sV16cV16cs", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqd128_mask, "cV4iV4ic", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqq128_mask, "cV2LLiV2LLic", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqw128_mask, "cV8sV8sc", "")
|
||||
BUILTIN(__builtin_ia32_cmppd512_mask, "UcV8dV8diCUci", "")
|
||||
BUILTIN(__builtin_ia32_rndscaleps_mask, "V16fV16fiCV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_rndscalepd_mask, "V8dV8diCV8dUciC", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2dq512_mask, "V16iV16fV16iUsiC", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2dq512_mask, "V8iV8dV8iUciC", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2udq512_mask, "V16iV16fV16iUsiC", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2udq512_mask, "V8iV8dV8iUciC", "")
|
||||
BUILTIN(__builtin_ia32_minps512_mask, "V16fV16fV16fV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_minpd512_mask, "V8dV8dV8dV8dUciC", "")
|
||||
BUILTIN(__builtin_ia32_maxps512_mask, "V16fV16fV16fV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_maxpd512_mask, "V8dV8dV8dV8dUciC", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2ps512_mask, "V16fV16iV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_cvtudq2ps512_mask, "V16fV16iV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb512_mask, "LLiV64cV64cLLi", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd512_mask, "sV16iV16is", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtq512_mask, "cV8LLiV8LLic", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw512_mask, "iV32sV32si", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb256_mask, "iV32cV32ci", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd256_mask, "cV8iV8ic", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtq256_mask, "cV4LLiV4LLic", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw256_mask, "sV16sV16ss", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb128_mask, "sV16cV16cs", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd128_mask, "cV4iV4ic", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtq128_mask, "cV2LLiV2LLic", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw128_mask, "cV8sV8sc", "")
|
||||
BUILTIN(__builtin_ia32_cmppd512_mask, "UcV8dV8dIiUcIi", "")
|
||||
BUILTIN(__builtin_ia32_cmppd256_mask, "UcV4dV4dIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmppd128_mask, "UcV2dV2dIiUc", "")
|
||||
BUILTIN(__builtin_ia32_rndscaleps_mask, "V16fV16fIiV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_rndscalepd_mask, "V8dV8dIiV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2dq512_mask, "V16iV16fV16iUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2dq512_mask, "V8iV8dV8iUcIi", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2udq512_mask, "V16iV16fV16iUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2udq512_mask, "V8iV8dV8iUcIi", "")
|
||||
BUILTIN(__builtin_ia32_minps512_mask, "V16fV16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_minpd512_mask, "V8dV8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_maxps512_mask, "V16fV16fV16fV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_maxpd512_mask, "V8dV8dV8dV8dUcIi", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2ps512_mask, "V16fV16iV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cvtudq2ps512_mask, "V16fV16iV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2pd512_mask, "V8dV8iV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_cvtudq2pd512_mask, "V8dV8iV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2ps512_mask, "V8fV8dV8fUciC", "")
|
||||
BUILTIN(__builtin_ia32_vcvtps2ph512_mask, "V16sV16fiCV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_vcvtph2ps512_mask, "V16fV16sV16fUsiC", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2ps512_mask, "V8fV8dV8fUcIi", "")
|
||||
BUILTIN(__builtin_ia32_vcvtps2ph512_mask, "V16sV16fIiV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_vcvtph2ps512_mask, "V16fV16sV16fUsIi", "")
|
||||
BUILTIN(__builtin_ia32_pandd512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_pandq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pord512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_porq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pxord512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_pxorq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pabsd512_mask, "V16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_pabsq512_mask, "V8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsd512_mask, "V16iV16iV16iV16iUs", "")
|
||||
@ -897,41 +902,152 @@ BUILTIN(__builtin_ia32_pbroadcastq512_mem_mask, "V8LLiLLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_loaddqusi512_mask, "V16ivC*V16iUs", "")
|
||||
BUILTIN(__builtin_ia32_loaddqudi512_mask, "V8LLivC*V8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_loadups512_mask, "V16fvC*V16fUs", "")
|
||||
BUILTIN(__builtin_ia32_loadaps512_mask, "V16fvC*V16fUs", "")
|
||||
BUILTIN(__builtin_ia32_loadupd512_mask, "V8dvC*V8dUc", "")
|
||||
BUILTIN(__builtin_ia32_loadapd512_mask, "V8dvC*V8dUc", "")
|
||||
BUILTIN(__builtin_ia32_storedqudi512_mask, "vv*V8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_storedqusi512_mask, "vv*V16iUs", "")
|
||||
BUILTIN(__builtin_ia32_storeupd512_mask, "vv*V8dUc", "")
|
||||
BUILTIN(__builtin_ia32_storeapd512_mask, "vv*V8dUc", "")
|
||||
BUILTIN(__builtin_ia32_storeups512_mask, "vv*V16fUs", "")
|
||||
BUILTIN(__builtin_ia32_storeaps512_mask, "vv*V16fUs", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2vard512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2varq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2varps512_mask, "V16fV16iV16fV16fUs", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2varpd512_mask, "V8dV8LLiV8dV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_alignq512_mask, "V8LLiV8LLiV8LLiUcV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_alignd512_mask, "V16iV16iV16iUcV16iUc", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv8df, "V8dV8dvC*V8iUciC", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv16sf, "V16fV16fvC*UsiC", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv8df, "V8dV8dvC*V8LLiUciC", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv16sf, "V8fV8fvC*V8LLiUciC", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv8di, "V8LLiV8LLivC*V8iUciC", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv16si, "V16iV16ivC*UsiC", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv8di, "V8LLiV8LLivC*V8LLiUciC", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv16si, "V8iV8ivC*V8LLiUciC", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv8df, "vv*UcV8iV8diC", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv16sf, "vv*UsV16iV16fiC", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv8df, "vv*UcV8LLiV8diC", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv16sf, "vv*UcV8LLiV8fiC", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv8di, "vv*UcV8iV8LLiiC", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv16si, "vv*UsV16iV16iiC", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv8di, "vv*UcV8LLiV8LLiiC", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv16si, "vv*UcV8LLiV8iiC", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfdpd, "vUcV8ivC*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfdps, "vUsV16ivC*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfqpd, "vUcV8LLivC*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfqps, "vUcV8LLivC*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfdpd, "vUcV8iv*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfdps, "vUsV16iv*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfqpd, "vUcV8LLiv*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfqps, "vUcV8LLiv*iCiC", "")
|
||||
BUILTIN(__builtin_ia32_alignq512_mask, "V8LLiV8LLiV8LLiIcV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_alignd512_mask, "V16iV16iV16iIcV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_extractf64x4_mask, "V4dV8dIcV4dUc", "")
|
||||
BUILTIN(__builtin_ia32_extractf32x4_mask, "V4fV16fIcV4fUc", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv8df, "V8dV8dvC*V8iUcIi", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv16sf, "V16fV16fvC*UsIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv8df, "V8dV8dvC*V8LLiUcIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv16sf, "V8fV8fvC*V8LLiUcIi", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv8di, "V8LLiV8LLivC*V8iUcIi", "")
|
||||
BUILTIN(__builtin_ia32_gathersiv16si, "V16iV16ivC*UsIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv8di, "V8LLiV8LLivC*V8LLiUcIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherdiv16si, "V8iV8ivC*V8LLiUcIi", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv8df, "vv*UcV8iV8dIi", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv16sf, "vv*UsV16iV16fIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv8df, "vv*UcV8LLiV8dIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv16sf, "vv*UcV8LLiV8fIi", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv8di, "vv*UcV8iV8LLiIi", "")
|
||||
BUILTIN(__builtin_ia32_scattersiv16si, "vv*UsV16iV16iIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv8di, "vv*UcV8LLiV8LLiIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterdiv16si, "vv*UcV8LLiV8iIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfdpd, "vUcV8ivC*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfdps, "vUsV16ivC*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfqpd, "vUcV8LLivC*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_gatherpfqps, "vUcV8LLivC*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfdpd, "vUcV8iv*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfdps, "vUsV16iv*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfqpd, "vUcV8LLiv*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_scatterpfqps, "vUcV8LLiv*IiIi", "")
|
||||
BUILTIN(__builtin_ia32_knothi, "UsUs", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_cmpb128_mask, "UsV16cV16cIiUs", "")
|
||||
BUILTIN(__builtin_ia32_cmpd128_mask, "UcV4iV4iIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmpq128_mask, "UcV2LLiV2LLiIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmpw128_mask, "UcV8sV8sIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmpb256_mask, "UiV32cV32cIiUi", "")
|
||||
BUILTIN(__builtin_ia32_cmpd256_mask, "UcV8iV8iIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmpq256_mask, "UcV4LLiV4LLiIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmpw256_mask, "UsV16sV16sIiUs", "")
|
||||
BUILTIN(__builtin_ia32_cmpb512_mask, "ULLiV64cV64cIiULLi", "")
|
||||
BUILTIN(__builtin_ia32_cmpd512_mask, "UsV16iV16iIiUs", "")
|
||||
BUILTIN(__builtin_ia32_cmpq512_mask, "UcV8LLiV8LLiIiUc", "")
|
||||
BUILTIN(__builtin_ia32_cmpw512_mask, "UiV32sV32sIiUi", "")
|
||||
BUILTIN(__builtin_ia32_ucmpb128_mask, "UsV16cV16cIiUs", "")
|
||||
BUILTIN(__builtin_ia32_ucmpd128_mask, "UcV4iV4iIiUc", "")
|
||||
BUILTIN(__builtin_ia32_ucmpq128_mask, "UcV2LLiV2LLiIiUc", "")
|
||||
BUILTIN(__builtin_ia32_ucmpw128_mask, "UcV8sV8sIiUc", "")
|
||||
BUILTIN(__builtin_ia32_ucmpb256_mask, "UiV32cV32cIiUi", "")
|
||||
BUILTIN(__builtin_ia32_ucmpd256_mask, "UcV8iV8iIiUc", "")
|
||||
BUILTIN(__builtin_ia32_ucmpq256_mask, "UcV4LLiV4LLiIiUc", "")
|
||||
BUILTIN(__builtin_ia32_ucmpw256_mask, "UsV16sV16sIiUs", "")
|
||||
BUILTIN(__builtin_ia32_ucmpb512_mask, "ULLiV64cV64cIiULLi", "")
|
||||
BUILTIN(__builtin_ia32_ucmpd512_mask, "UsV16iV16iIiUs", "")
|
||||
BUILTIN(__builtin_ia32_ucmpq512_mask, "UcV8LLiV8LLiIiUc", "")
|
||||
BUILTIN(__builtin_ia32_ucmpw512_mask, "UiV32sV32sIiUi", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_paddd256_mask, "V8iV8iV8iV8iUc", "")
|
||||
BUILTIN(__builtin_ia32_paddq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_psubd256_mask, "V8iV8iV8iV8iUc", "")
|
||||
BUILTIN(__builtin_ia32_psubq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_paddd128_mask, "V4iV4iV4iV4iUc", "")
|
||||
BUILTIN(__builtin_ia32_paddq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_psubd128_mask, "V4iV4iV4iV4iUc", "")
|
||||
BUILTIN(__builtin_ia32_psubq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pmuldq256_mask, "V4LLiV8iV8iV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pmuldq128_mask, "V2LLiV4iV4iV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pmuludq256_mask, "V4LLiV8iV8iV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pmuludq128_mask, "V2LLiV4iV4iV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pmulld256_mask, "V8iV8iV8iV8iUc", "")
|
||||
BUILTIN(__builtin_ia32_pmulld128_mask, "V4iV4iV4iV4iUc", "")
|
||||
BUILTIN(__builtin_ia32_pandd256_mask, "V8iV8iV8iV8iUc", "")
|
||||
BUILTIN(__builtin_ia32_pandd128_mask, "V4iV4iV4iV4iUc", "")
|
||||
BUILTIN(__builtin_ia32_pandnd256_mask, "V8iV8iV8iV8iUc", "")
|
||||
BUILTIN(__builtin_ia32_pandnd128_mask, "V4iV4iV4iV4iUc", "")
|
||||
BUILTIN(__builtin_ia32_pord256_mask, "V8iV8iV8iV8iUc", "")
|
||||
BUILTIN(__builtin_ia32_pord128_mask, "V4iV4iV4iV4iUc", "")
|
||||
BUILTIN(__builtin_ia32_pxord256_mask, "V8iV8iV8iV8iUc", "")
|
||||
BUILTIN(__builtin_ia32_pxord128_mask, "V4iV4iV4iV4iUc", "")
|
||||
BUILTIN(__builtin_ia32_pandq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pandq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pandnq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pandnq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_porq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_porq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pxorq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pxorq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_paddb512_mask, "V64cV64cV64cV64cULLi", "")
|
||||
BUILTIN(__builtin_ia32_psubb512_mask, "V64cV64cV64cV64cULLi", "")
|
||||
BUILTIN(__builtin_ia32_paddw512_mask, "V32sV32sV32sV32sUi", "")
|
||||
BUILTIN(__builtin_ia32_psubw512_mask, "V32sV32sV32sV32sUi", "")
|
||||
BUILTIN(__builtin_ia32_pmullw512_mask, "V32sV32sV32sV32sUi", "")
|
||||
BUILTIN(__builtin_ia32_paddb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_paddw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_psubb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_psubw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_paddb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_paddw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_psubb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_psubw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pmullw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pmullw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pandnd512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_pandnq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_paddq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_psubq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_paddd512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_psubd512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_pmulld512_mask, "V16iV16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_pmullq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_xorpd512_mask, "V8dV8dV8dV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_xorps512_mask, "V16fV16fV16fV16fUs", "")
|
||||
BUILTIN(__builtin_ia32_orpd512_mask, "V8dV8dV8dV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_orps512_mask, "V16fV16fV16fV16fUs", "")
|
||||
BUILTIN(__builtin_ia32_andpd512_mask, "V8dV8dV8dV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_andps512_mask, "V16fV16fV16fV16fUs", "")
|
||||
BUILTIN(__builtin_ia32_andnpd512_mask, "V8dV8dV8dV8dUc", "")
|
||||
BUILTIN(__builtin_ia32_andnps512_mask, "V16fV16fV16fV16fUs", "")
|
||||
BUILTIN(__builtin_ia32_pmullq256_mask, "V4LLiV4LLiV4LLiV4LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_pmullq128_mask, "V2LLiV2LLiV2LLiV2LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_andnpd256_mask, "V4dV4dV4dV4dUc", "")
|
||||
BUILTIN(__builtin_ia32_andnpd128_mask, "V2dV2dV2dV2dUc", "")
|
||||
BUILTIN(__builtin_ia32_andnps256_mask, "V8fV8fV8fV8fUc", "")
|
||||
BUILTIN(__builtin_ia32_andnps128_mask, "V4fV4fV4fV4fUc", "")
|
||||
BUILTIN(__builtin_ia32_andpd256_mask, "V4dV4dV4dV4dUc", "")
|
||||
BUILTIN(__builtin_ia32_andpd128_mask, "V2dV2dV2dV2dUc", "")
|
||||
BUILTIN(__builtin_ia32_andps256_mask, "V8fV8fV8fV8fUc", "")
|
||||
BUILTIN(__builtin_ia32_andps128_mask, "V4fV4fV4fV4fUc", "")
|
||||
BUILTIN(__builtin_ia32_xorpd256_mask, "V4dV4dV4dV4dUc", "")
|
||||
BUILTIN(__builtin_ia32_xorpd128_mask, "V2dV2dV2dV2dUc", "")
|
||||
BUILTIN(__builtin_ia32_xorps256_mask, "V8fV8fV8fV8fUc", "")
|
||||
BUILTIN(__builtin_ia32_xorps128_mask, "V4fV4fV4fV4fUc", "")
|
||||
BUILTIN(__builtin_ia32_orpd256_mask, "V4dV4dV4dV4dUc", "")
|
||||
BUILTIN(__builtin_ia32_orpd128_mask, "V2dV2dV2dV2dUc", "")
|
||||
BUILTIN(__builtin_ia32_orps256_mask, "V8fV8fV8fV8fUc", "")
|
||||
BUILTIN(__builtin_ia32_orps128_mask, "V4fV4fV4fV4fUc", "")
|
||||
|
||||
#undef BUILTIN
|
||||
|
@ -11,6 +11,7 @@ class DDecl<Decl base, bit abstract = 0> : Decl<abstract> {
|
||||
class DeclContext { }
|
||||
|
||||
def TranslationUnit : Decl, DeclContext;
|
||||
def ExternCContext : Decl, DeclContext;
|
||||
def Named : Decl<1>;
|
||||
def Namespace : DDecl<Named>, DeclContext;
|
||||
def UsingDirective : DDecl<Named>;
|
||||
|
@ -132,8 +132,8 @@ class FixItHint {
|
||||
/// the user. DiagnosticsEngine is tied to one translation unit and one
|
||||
/// SourceManager.
|
||||
class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
|
||||
DiagnosticsEngine(const DiagnosticsEngine &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const DiagnosticsEngine &) LLVM_DELETED_FUNCTION;
|
||||
DiagnosticsEngine(const DiagnosticsEngine &) = delete;
|
||||
void operator=(const DiagnosticsEngine &) = delete;
|
||||
|
||||
public:
|
||||
/// \brief The level of the diagnostic, after it has been through mapping.
|
||||
@ -877,7 +877,7 @@ class DiagnosticBuilder {
|
||||
/// call to ForceEmit.
|
||||
mutable bool IsForceEmit;
|
||||
|
||||
void operator=(const DiagnosticBuilder &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const DiagnosticBuilder &) = delete;
|
||||
friend class DiagnosticsEngine;
|
||||
|
||||
DiagnosticBuilder()
|
||||
@ -991,7 +991,8 @@ class DiagnosticBuilder {
|
||||
|
||||
void AddFixItHint(const FixItHint &Hint) const {
|
||||
assert(isActive() && "Clients must not add to cleared diagnostic!");
|
||||
DiagObj->DiagFixItHints.push_back(Hint);
|
||||
if (!Hint.isNull())
|
||||
DiagObj->DiagFixItHints.push_back(Hint);
|
||||
}
|
||||
|
||||
void addFlagValue(StringRef V) const { DiagObj->FlagValue = V; }
|
||||
@ -1095,7 +1096,13 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const FixItHint &Hint) {
|
||||
if (!Hint.isNull())
|
||||
DB.AddFixItHint(Hint);
|
||||
return DB;
|
||||
}
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
ArrayRef<FixItHint> Hints) {
|
||||
for (const FixItHint &Hint : Hints)
|
||||
DB.AddFixItHint(Hint);
|
||||
return DB;
|
||||
}
|
||||
@ -1260,7 +1267,7 @@ class StoredDiagnostic {
|
||||
~StoredDiagnostic();
|
||||
|
||||
/// \brief Evaluates true when this object stores a diagnostic.
|
||||
LLVM_EXPLICIT operator bool() const { return Message.size() > 0; }
|
||||
explicit operator bool() const { return Message.size() > 0; }
|
||||
|
||||
unsigned getID() const { return ID; }
|
||||
DiagnosticsEngine::Level getLevel() const { return Level; }
|
||||
@ -1364,7 +1371,7 @@ class ForwardingDiagnosticConsumer : public DiagnosticConsumer {
|
||||
public:
|
||||
ForwardingDiagnosticConsumer(DiagnosticConsumer &Target) : Target(Target) {}
|
||||
|
||||
virtual ~ForwardingDiagnosticConsumer();
|
||||
~ForwardingDiagnosticConsumer() override;
|
||||
|
||||
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
|
||||
const Diagnostic &Info) override;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user