Vendor import of clang trunk r240225:
https://llvm.org/svn/llvm-project/cfe/trunk@240225
This commit is contained in:
parent
798321d8eb
commit
2e645aa569
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=284679 svn path=/vendor/clang/clang-trunk-r240225/; revision=284680; tag=vendor/clang/clang-trunk-r240225
2
.gitignore
vendored
2
.gitignore
vendored
@ -16,7 +16,7 @@
|
||||
# Byte compiled python modules.
|
||||
*.pyc
|
||||
# vim swap files
|
||||
.*.swp
|
||||
.*.sw?
|
||||
.sw?
|
||||
|
||||
#==============================================================================#
|
||||
|
@ -320,6 +320,17 @@ function(clang_tablegen)
|
||||
endif()
|
||||
endfunction(clang_tablegen)
|
||||
|
||||
macro(set_clang_windows_version_resource_properties name)
|
||||
if(DEFINED windows_resource_file)
|
||||
set_windows_version_resource_properties(${name} ${windows_resource_file}
|
||||
VERSION_MAJOR ${CLANG_VERSION_MAJOR}
|
||||
VERSION_MINOR ${CLANG_VERSION_MINOR}
|
||||
VERSION_PATCHLEVEL ${CLANG_VERSION_PATCHLEVEL}
|
||||
VERSION_STRING "${CLANG_VERSION} (${BACKEND_PACKAGE_STRING})"
|
||||
PRODUCT_NAME "clang")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(add_clang_library name)
|
||||
cmake_parse_arguments(ARG
|
||||
""
|
||||
@ -377,11 +388,13 @@ macro(add_clang_library name)
|
||||
endif()
|
||||
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
|
||||
set_clang_windows_version_resource_properties(${name})
|
||||
endmacro(add_clang_library)
|
||||
|
||||
macro(add_clang_executable name)
|
||||
add_llvm_executable( ${name} ${ARGN} )
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Clang executables")
|
||||
set_clang_windows_version_resource_properties(${name})
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
@ -155,23 +155,21 @@ the configuration (without a prefix: ``Auto``).
|
||||
|
||||
This applies to round brackets (parentheses), angle brackets and square
|
||||
brackets. This will result in formattings like
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
\code
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
\endcode
|
||||
|
||||
**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;
|
||||
\code
|
||||
int aaaa = 12;
|
||||
int b = 23;
|
||||
int ccc = 23;
|
||||
\endcode
|
||||
|
||||
**AlignEscapedNewlinesLeft** (``bool``)
|
||||
If ``true``, aligns escaped newlines as far left as possible.
|
||||
@ -204,10 +202,10 @@ the configuration (without a prefix: ``Auto``).
|
||||
|
||||
* ``SFS_None`` (in configuration: ``None``)
|
||||
Never merge functions into a single line.
|
||||
* ``SFS_Inline`` (in configuration: ``Inline``)
|
||||
Only merge functions defined inside a class.
|
||||
* ``SFS_Empty`` (in configuration: ``Empty``)
|
||||
Only merge empty functions.
|
||||
* ``SFS_Inline`` (in configuration: ``Inline``)
|
||||
Only merge functions defined inside a class. Implies "empty".
|
||||
* ``SFS_All`` (in configuration: ``All``)
|
||||
Merge all functions fitting on a single line.
|
||||
|
||||
@ -230,6 +228,11 @@ the configuration (without a prefix: ``Auto``).
|
||||
**AlwaysBreakBeforeMultilineStrings** (``bool``)
|
||||
If ``true``, always break before multiline string literals.
|
||||
|
||||
This flag is mean to make cases where there are multiple multiline strings
|
||||
in a file look more consistent. Thus, it will only take effect if wrapping
|
||||
the string at that point leads to it being indented
|
||||
``ContinuationIndentWidth`` spaces from the start of the line.
|
||||
|
||||
**AlwaysBreakTemplateDeclarations** (``bool``)
|
||||
If ``true``, always break after the ``template<...>`` of a
|
||||
template declaration.
|
||||
@ -343,11 +346,10 @@ the configuration (without a prefix: ``Auto``).
|
||||
instead of as function calls.
|
||||
|
||||
These are expected to be macros of the form:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
FOREACH(<variable-declaration>, ...)
|
||||
<loop-body>
|
||||
\code
|
||||
FOREACH(<variable-declaration>, ...)
|
||||
<loop-body>
|
||||
\endcode
|
||||
|
||||
For example: BOOST_FOREACH.
|
||||
|
||||
|
@ -20,8 +20,8 @@ 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
|
||||
As currently implemented, CFI relies on link-time optimization (LTO); so it is
|
||||
required to specify ``-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
|
||||
|
@ -1845,6 +1845,9 @@ with :doc:`ThreadSanitizer`.
|
||||
Use ``__has_feature(memory_sanitizer)`` to check if the code is being built
|
||||
with :doc:`MemorySanitizer`.
|
||||
|
||||
Use ``__has_feature(safe_stack)`` to check if the code is being built
|
||||
with :doc:`SafeStack`.
|
||||
|
||||
|
||||
Extensions for selectively disabling optimization
|
||||
=================================================
|
||||
|
@ -159,7 +159,7 @@ Module maps are specified as separate files (each named ``module.modulemap``) al
|
||||
|
||||
To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps.
|
||||
|
||||
One can use module maps without modules to check the integrity of the use of header files. To do this, use the ``-fmodule-maps`` option instead of the ``-fmodules`` option.
|
||||
One can use module maps without modules to check the integrity of the use of header files. To do this, use the ``-fimplicit-module-maps`` option instead of the ``-fmodules`` option, or use ``-fmodule-map-file=`` option to explicitly specify the module map files to load.
|
||||
|
||||
Compilation model
|
||||
-----------------
|
||||
@ -174,8 +174,8 @@ Command-line parameters
|
||||
``-fmodules``
|
||||
Enable the modules feature.
|
||||
|
||||
``-fmodule-maps``
|
||||
Enable interpretation of module maps. This option is implied by ``-fmodules``.
|
||||
``-fimplicit-module-maps``
|
||||
Enable implicit search for module map files named ``module.modulemap`` and similar. This option is implied by ``-fmodules``. If this is disabled with ``-fno-implicit-module-maps``, module map files will only be loaded if they are explicitly specified via ``-fmodule-map-file`` or transitively used by another module map file.
|
||||
|
||||
``-fmodules-cache-path=<directory>``
|
||||
Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default.
|
||||
@ -207,9 +207,6 @@ Command-line parameters
|
||||
``-fmodules-search-all``
|
||||
If a symbol is not found, search modules referenced in the current module maps but not imported for symbols, so the error message can reference the module by name. Note that if the global module index has not been built before, this might take some time as it needs to build all the modules. Note that this option doesn't apply in module builds, to avoid the recursion.
|
||||
|
||||
``-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``.
|
||||
|
||||
@ -682,7 +679,7 @@ A *link-declaration* with the ``framework`` specifies that the linker should lin
|
||||
|
||||
Configuration macros declaration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The *config-macros-declaration* specifies the set of configuration macros that have an effect on the the API of the enclosing module.
|
||||
The *config-macros-declaration* specifies the set of configuration macros that have an effect on the API of the enclosing module.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|
163
docs/SafeStack.rst
Normal file
163
docs/SafeStack.rst
Normal file
@ -0,0 +1,163 @@
|
||||
=========
|
||||
SafeStack
|
||||
=========
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
SafeStack is an instrumentation pass that protects programs against attacks
|
||||
based on stack buffer overflows, without introducing any measurable performance
|
||||
overhead. It works by separating the program stack into two distinct regions:
|
||||
the safe stack and the unsafe stack. The safe stack stores return addresses,
|
||||
register spills, and local variables that are always accessed in a safe way,
|
||||
while the unsafe stack stores everything else. This separation ensures that
|
||||
buffer overflows on the unsafe stack cannot be used to overwrite anything
|
||||
on the safe stack, which includes return addresses.
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
||||
The performance overhead of the SafeStack instrumentation is less than 0.1% on
|
||||
average across a variety of benchmarks (see the `Code-Pointer Integrity
|
||||
<http://dslab.epfl.ch/pubs/cpi.pdf>`_ paper for details). This is mainly
|
||||
because most small functions do not have any variables that require the unsafe
|
||||
stack and, hence, do not need unsafe stack frames to be created. The cost of
|
||||
creating unsafe stack frames for large functions is amortized by the cost of
|
||||
executing the function.
|
||||
|
||||
In some cases, SafeStack actually improves the performance. Objects that end up
|
||||
being moved to the unsafe stack are usually large arrays or variables that are
|
||||
used through multiple stack frames. Moving such objects away from the safe
|
||||
stack increases the locality of frequently accessed values on the stack, such
|
||||
as register spills, return addresses, and small local variables.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
SafeStack has not been subjected to a comprehensive security review, and there
|
||||
exist known weaknesses, including but not limited to the following.
|
||||
|
||||
In its current state, the separation of local variables provides protection
|
||||
against stack buffer overflows, but the safe stack itself is not protected
|
||||
from being corrupted through a pointer dereference. The Code-Pointer
|
||||
Integrity paper describes two ways in which we may protect the safe stack:
|
||||
hardware segmentation on the 32-bit x86 architecture or information hiding
|
||||
on other architectures.
|
||||
|
||||
Even with information hiding, the safe stack would merely be hidden
|
||||
from attackers by being somewhere in the address space. Depending on the
|
||||
application, the address could be predictable even on 64-bit address spaces
|
||||
because not all the bits are addressable, multiple threads each have their
|
||||
stack, the application could leak the safe stack address to memory via
|
||||
``__builtin_frame_address``, bugs in the low-level runtime support etc.
|
||||
Safe stack leaks could be mitigated by writing and deploying a static binary
|
||||
analysis or a dynamic binary instrumentation based tool to find leaks.
|
||||
|
||||
This approach doesn't prevent an attacker from "imbalancing" the safe
|
||||
stack by say having just one call, and doing two rets (thereby returning
|
||||
to an address that wasn't meant as a return address). This can be at least
|
||||
partially mitigated by deploying SafeStack alongside a forward control-flow
|
||||
integrity mechanism to ensure that calls are made using the correct calling
|
||||
convention. Clang does not currently implement a comprehensive forward
|
||||
control-flow integrity protection scheme; there exists one that protects
|
||||
:doc:`virtual calls <ControlFlowIntegrity>` but not non-virtual indirect calls.
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
Most programs, static libraries, or individual files can be compiled
|
||||
with SafeStack as is. SafeStack requires basic runtime support, which, on most
|
||||
platforms, is implemented as a compiler-rt library that is automatically linked
|
||||
in when the program is compiled with SafeStack.
|
||||
|
||||
Linking a DSO with SafeStack is not currently supported.
|
||||
|
||||
Known compatibility limitations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Certain code that relies on low-level stack manipulations requires adaption to
|
||||
work with SafeStack. One example is mark-and-sweep garbage collection
|
||||
implementations for C/C++ (e.g., Oilpan in chromium/blink), which must be
|
||||
changed to look for the live pointers on both safe and unsafe stacks.
|
||||
|
||||
SafeStack supports linking together modules that are compiled with and without
|
||||
SafeStack, both statically and dynamically. One corner case that is not
|
||||
supported is using ``dlopen()`` to load a dynamic library that uses SafeStack into
|
||||
a program that is not compiled with SafeStack but uses threads.
|
||||
|
||||
Signal handlers that use ``sigaltstack()`` must not use the unsafe stack (see
|
||||
``__attribute__((no_sanitize("safe-stack")))`` below).
|
||||
|
||||
Programs that use APIs from ``ucontext.h`` are not supported yet.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To enable SafeStack, just pass ``-fsanitize=safe-stack`` flag to both compile and link
|
||||
command lines.
|
||||
|
||||
Supported Platforms
|
||||
-------------------
|
||||
|
||||
SafeStack was tested on Linux, FreeBSD and MacOSX.
|
||||
|
||||
Low-level API
|
||||
-------------
|
||||
|
||||
``__has_feature(safe_stack)``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In some rare cases one may need to execute different code depending on
|
||||
whether SafeStack is enabled. The macro ``__has_feature(safe_stack)`` can
|
||||
be used for this purpose.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if __has_feature(safe_stack)
|
||||
// code that builds only under SafeStack
|
||||
#endif
|
||||
|
||||
``__attribute__((no_sanitize("safe-stack")))``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use ``__attribute__((no_sanitize("safe-stack")))`` on a function declaration
|
||||
to specify that the safe stack instrumentation should not be applied to that
|
||||
function, even if enabled globally (see ``-fsanitize=safe-stack`` flag). This
|
||||
attribute may be required for functions that make assumptions about the
|
||||
exact layout of their stack frames.
|
||||
|
||||
Care should be taken when using this attribute. The return address is not
|
||||
protected against stack buffer overflows, and it is easier to leak the
|
||||
address of the safe stack to memory by taking the address of a local variable.
|
||||
|
||||
|
||||
``__builtin___get_unsafe_stack_ptr()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This builtin function returns current unsafe stack pointer of the current
|
||||
thread.
|
||||
|
||||
``__builtin___get_unsafe_stack_start()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This builtin function returns a pointer to the start of the unsafe stack of the
|
||||
current thread.
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
Please refer to
|
||||
`http://dslab.epfl.ch/proj/cpi/ <http://dslab.epfl.ch/proj/cpi/>`_ for more
|
||||
information about the design of the SafeStack and its related technologies.
|
||||
|
||||
|
||||
Publications
|
||||
------------
|
||||
|
||||
`Code-Pointer Integrity <http://dslab.epfl.ch/pubs/cpi.pdf>`_.
|
||||
Volodymyr Kuznetsov, Laszlo Szekeres, Mathias Payer, George Candea, R. Sekar, Dawn Song.
|
||||
USENIX Symposium on Operating Systems Design and Implementation
|
||||
(`OSDI <https://www.usenix.org/conference/osdi14>`_), Broomfield, CO, October 2014
|
@ -970,16 +970,15 @@ are listed below.
|
||||
includes all of the checks listed below other than
|
||||
``unsigned-integer-overflow``.
|
||||
|
||||
- ``-fsanitize=undefined-trap``: This includes all sanitizers
|
||||
included by ``-fsanitize=undefined``, except those that require
|
||||
runtime support. This group of sanitizers is intended to be
|
||||
used in conjunction with the ``-fsanitize-undefined-trap-on-error``
|
||||
flag. This includes all of the checks listed below other than
|
||||
``unsigned-integer-overflow`` and ``vptr``.
|
||||
- ``-fsanitize=undefined-trap``: This is a deprecated alias for
|
||||
``-fsanitize=undefined``.
|
||||
|
||||
- ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
|
||||
flow analysis.
|
||||
- ``-fsanitize=cfi``: :doc:`control flow integrity <ControlFlowIntegrity>`
|
||||
checks. Implies ``-flto``.
|
||||
checks. Requires ``-flto``.
|
||||
- ``-fsanitize=safe-stack``: :doc:`safe stack <SafeStack>`
|
||||
protection against stack-based memory corruption errors.
|
||||
|
||||
The following more fine-grained checks are also available:
|
||||
|
||||
@ -992,13 +991,13 @@ are listed below.
|
||||
- ``-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``.
|
||||
dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
|
||||
unrelated type to the wrong dynamic type. Implies ``-flto``.
|
||||
unrelated type to the wrong dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
|
||||
the wrong dynamic type. Implies ``-flto``.
|
||||
the wrong dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
|
||||
wrong dynamic type. Implies ``-flto``.
|
||||
wrong dynamic type. Requires ``-flto``.
|
||||
- ``-fsanitize=enum``: Load of a value of an enumerated type which
|
||||
is not in the range of representable values for that enumerated
|
||||
type.
|
||||
@ -1067,15 +1066,6 @@ are listed below.
|
||||
through. This mode may use extra memory in programs that copy
|
||||
uninitialized memory a lot.
|
||||
|
||||
Extra features of UndefinedBehaviorSanitizer:
|
||||
|
||||
- ``-fsanitize-undefined-trap-on-error``: Causes traps to be emitted
|
||||
rather than calls to runtime libraries when a problem is detected.
|
||||
This option is intended for use in cases where the sanitizer runtime
|
||||
cannot be used (for instance, when building libc or a kernel module).
|
||||
This is only compatible with the sanitizers in the ``undefined-trap``
|
||||
group.
|
||||
|
||||
The ``-fsanitize=`` argument must also be provided when linking, in
|
||||
order to link to the appropriate runtime library. When using
|
||||
``-fsanitize=vptr`` (or a group that includes it, such as
|
||||
@ -1099,11 +1089,41 @@ are listed below.
|
||||
sanitizers (e.g. :doc:`AddressSanitizer`) may not support recovery,
|
||||
and always crash the program after the issue is detected.
|
||||
|
||||
Note that the ``-fsanitize-trap`` flag has precedence over this flag.
|
||||
This means that if a check has been configured to trap elsewhere on the
|
||||
command line, or if the check traps by default, this flag will not have
|
||||
any effect unless that sanitizer's trapping behavior is disabled with
|
||||
``-fno-sanitize-trap``.
|
||||
|
||||
For example, if a command line contains the flags ``-fsanitize=undefined
|
||||
-fsanitize-trap=undefined``, the flag ``-fsanitize-recover=alignment``
|
||||
will have no effect on its own; it will need to be accompanied by
|
||||
``-fno-sanitize-trap=alignment``.
|
||||
|
||||
**-f[no-]sanitize-trap=check1,check2,...**
|
||||
|
||||
Controls which checks enabled by the ``-fsanitize=`` flag trap. This
|
||||
option is intended for use in cases where the sanitizer runtime cannot
|
||||
be used (for instance, when building libc or a kernel module), or where
|
||||
the binary size increase caused by the sanitizer runtime is a concern.
|
||||
|
||||
This flag is only compatible with ``local-bounds``,
|
||||
``unsigned-integer-overflow``, sanitizers in the ``cfi`` group and
|
||||
sanitizers in the ``undefined`` group other than ``vptr``. If this flag
|
||||
is supplied together with ``-fsanitize=undefined``, the ``vptr`` sanitizer
|
||||
will be implicitly disabled.
|
||||
|
||||
This flag is enabled by default for sanitizers in the ``cfi`` group.
|
||||
|
||||
**-f[no-]sanitize-coverage=[type,features,...]**
|
||||
|
||||
Enable simple code coverage in addition to certain sanitizers.
|
||||
See :doc:`SanitizerCoverage` for more details.
|
||||
|
||||
.. option:: -fsanitize-undefined-trap-on-error
|
||||
|
||||
Deprecated alias for ``-fsanitize-trap=undefined``.
|
||||
|
||||
.. option:: -fno-assume-sane-operator-new
|
||||
|
||||
Don't assume that the C++'s new operator is sane.
|
||||
|
@ -29,6 +29,7 @@ Using Clang as a Compiler
|
||||
SanitizerCoverage
|
||||
SanitizerSpecialCaseList
|
||||
ControlFlowIntegrity
|
||||
SafeStack
|
||||
Modules
|
||||
MSVCCompatibility
|
||||
FAQ
|
||||
|
@ -39,12 +39,12 @@ the other tools.
|
||||
This stage handles tokenization of the input source file, macro expansion,
|
||||
#include expansion and handling of other preprocessor directives. The output of
|
||||
this stage is typically called a ".i" (for C), ".ii" (for C++), ".mi" (for
|
||||
Objective-C) , or ".mii" (for Objective-C++) file.
|
||||
Objective-C), or ".mii" (for Objective-C++) file.
|
||||
|
||||
=item B<Parsing and Semantic Analysis>
|
||||
|
||||
This stage parses the input file, translating preprocessor tokens into a parse
|
||||
tree. Once in the form of a parser tree, it applies semantic analysis to compute
|
||||
tree. Once in the form of a parse tree, it applies semantic analysis to compute
|
||||
types for expressions as well and determine whether the code is well formed. This
|
||||
stage is responsible for generating most of the compiler warnings as well as
|
||||
parse errors. The output of this stage is an "Abstract Syntax Tree" (AST).
|
||||
@ -330,13 +330,13 @@ all by the program.
|
||||
|
||||
=item B<-fexceptions>
|
||||
|
||||
Enable generation of unwind information, this allows exceptions to be thrown
|
||||
Enable generation of unwind information. This allows exceptions to be thrown
|
||||
through Clang compiled stack frames. This is on by default in x86-64.
|
||||
|
||||
=item B<-ftrapv>
|
||||
|
||||
Generate code to catch integer overflow errors. Signed integer overflow is
|
||||
undefined in C, with this flag, extra code is generated to detect this and abort
|
||||
undefined in C. With this flag, extra code is generated to detect this and abort
|
||||
when it happens.
|
||||
|
||||
|
||||
@ -389,7 +389,7 @@ Display available options.
|
||||
|
||||
=item B<-Qunused-arguments>
|
||||
|
||||
Don't emit warning for unused driver arguments.
|
||||
Do not emit any warnings for unused driver arguments.
|
||||
|
||||
=item B<-Wa,>I<args>
|
||||
|
||||
@ -578,7 +578,7 @@ write temporary files used during the compilation process.
|
||||
|
||||
If this environment variable is present, it is treated as a delimited
|
||||
list of paths to be added to the default system include path list. The
|
||||
delimiter is the platform dependent delimitor, as used in the I<PATH>
|
||||
delimiter is the platform dependent delimiter, as used in the I<PATH>
|
||||
environment variable.
|
||||
|
||||
Empty components in the environment variable are ignored.
|
||||
@ -592,7 +592,7 @@ which are only used when processing the appropriate language.
|
||||
=item B<MACOSX_DEPLOYMENT_TARGET>
|
||||
|
||||
If -mmacosx-version-min is unspecified, the default deployment target
|
||||
is read from this environment variable. This option only affects darwin
|
||||
is read from this environment variable. This option only affects Darwin
|
||||
targets.
|
||||
|
||||
=back
|
||||
|
@ -2225,7 +2225,12 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_OMPTeamsDirective = 253,
|
||||
|
||||
CXCursor_LastStmt = CXCursor_OMPTeamsDirective,
|
||||
/** \brief OpenMP taskwait directive.
|
||||
*/
|
||||
CXCursor_OMPTaskgroupDirective = 254,
|
||||
|
||||
|
||||
CXCursor_LastStmt = CXCursor_OMPTaskgroupDirective,
|
||||
|
||||
/**
|
||||
* \brief Cursor that represents the translation unit itself.
|
||||
@ -5628,7 +5633,7 @@ typedef enum {
|
||||
* reused after indexing is finished. Set to \c NULL if you do not require it.
|
||||
*
|
||||
* \returns 0 on success or if there were errors from which the compiler could
|
||||
* recover. If there is a failure from which the there is no recovery, returns
|
||||
* recover. If there is a failure from which there is no recovery, returns
|
||||
* a non-zero \c CXErrorCode.
|
||||
*
|
||||
* The rest of the parameters are the same as #clang_parseTranslationUnit.
|
||||
@ -5659,7 +5664,7 @@ CINDEX_LINKAGE int clang_indexSourceFile(CXIndexAction,
|
||||
*
|
||||
* The parameters are the same as #clang_indexSourceFile.
|
||||
*
|
||||
* \returns If there is a failure from which the there is no recovery, returns
|
||||
* \returns If there is a failure from which there is no recovery, returns
|
||||
* non-zero, otherwise returns 0.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_indexTranslationUnit(CXIndexAction,
|
||||
|
@ -17,6 +17,7 @@
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class DiagnosticConsumer;
|
||||
class PCHContainerOperations;
|
||||
|
||||
namespace arcmt {
|
||||
class MigrationPass;
|
||||
@ -37,19 +38,22 @@ namespace arcmt {
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool checkForManualIssues(CompilerInvocation &CI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
bool emitPremigrationARCErrors = false,
|
||||
StringRef plistOut = StringRef());
|
||||
bool
|
||||
checkForManualIssues(CompilerInvocation &CI, const FrontendInputFile &Input,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
bool emitPremigrationARCErrors = false,
|
||||
StringRef plistOut = StringRef());
|
||||
|
||||
/// \brief Works similar to checkForManualIssues but instead of checking, it
|
||||
/// applies automatic modifications to source files to conform to ARC.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool applyTransformations(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
bool
|
||||
applyTransformations(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
/// \brief Applies automatic modifications and produces temporary files
|
||||
/// and metadata into the \p outputDir path.
|
||||
@ -62,12 +66,11 @@ bool applyTransformations(CompilerInvocation &origCI,
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
StringRef plistOut);
|
||||
bool migrateWithTemporaryFiles(
|
||||
CompilerInvocation &origCI, const FrontendInputFile &Input,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagClient, StringRef outputDir,
|
||||
bool emitPremigrationARCErrors, StringRef plistOut);
|
||||
|
||||
/// \brief Get the set of file remappings from the \p outputDir path that
|
||||
/// migrateWithTemporaryFiles produced.
|
||||
@ -93,13 +96,16 @@ std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode,
|
||||
|
||||
class MigrationProcess {
|
||||
CompilerInvocation OrigCI;
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
|
||||
DiagnosticConsumer *DiagClient;
|
||||
FileRemapper Remapper;
|
||||
|
||||
public:
|
||||
bool HadARCErrors;
|
||||
|
||||
MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient,
|
||||
MigrationProcess(const CompilerInvocation &CI,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *diagClient,
|
||||
StringRef outputDir = StringRef());
|
||||
|
||||
class RewriteListener {
|
||||
|
@ -1854,6 +1854,36 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
getCanonicalType(T2).getTypePtr();
|
||||
}
|
||||
|
||||
bool hasSameNullabilityTypeQualifier(QualType SubT, QualType SuperT,
|
||||
bool IsParam) const {
|
||||
auto SubTnullability = SubT->getNullability(*this);
|
||||
auto SuperTnullability = SuperT->getNullability(*this);
|
||||
if (SubTnullability.hasValue() == SuperTnullability.hasValue()) {
|
||||
// Neither has nullability; return true
|
||||
if (!SubTnullability)
|
||||
return true;
|
||||
// Both have nullability qualifier.
|
||||
if (*SubTnullability == *SuperTnullability ||
|
||||
*SubTnullability == NullabilityKind::Unspecified ||
|
||||
*SuperTnullability == NullabilityKind::Unspecified)
|
||||
return true;
|
||||
|
||||
if (IsParam) {
|
||||
// Ok for the superclass method parameter to be "nonnull" and the subclass
|
||||
// method parameter to be "nullable"
|
||||
return (*SuperTnullability == NullabilityKind::NonNull &&
|
||||
*SubTnullability == NullabilityKind::Nullable);
|
||||
}
|
||||
else {
|
||||
// For the return type, it's okay for the superclass method to specify
|
||||
// "nullable" and the subclass method specify "nonnull"
|
||||
return (*SuperTnullability == NullabilityKind::Nullable &&
|
||||
*SubTnullability == NullabilityKind::NonNull);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
|
||||
const ObjCMethodDecl *MethodImp);
|
||||
|
||||
|
@ -75,11 +75,7 @@ class Parser {
|
||||
return;
|
||||
|
||||
MoreLATokens.push_back(Tok);
|
||||
for (const Token *I = &Toks.back(),
|
||||
*B = &Toks.front();
|
||||
I != B; --I) {
|
||||
MoreLATokens.push_back(*I);
|
||||
}
|
||||
MoreLATokens.append(Toks.rbegin(), std::prev(Toks.rend()));
|
||||
|
||||
Tok = Toks[0];
|
||||
}
|
||||
|
@ -531,10 +531,7 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
|
||||
}
|
||||
}
|
||||
|
||||
for (SmallVectorImpl<Stmt *>::reverse_iterator RI = StmtsToEnqueue.rbegin(),
|
||||
RE = StmtsToEnqueue.rend();
|
||||
RI != RE; ++RI)
|
||||
Queue.push_back(*RI);
|
||||
Queue.append(StmtsToEnqueue.rbegin(), StmtsToEnqueue.rend());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2204,9 +2201,11 @@ DEF_TRAVERSE_STMT(CXXThisExpr, {})
|
||||
DEF_TRAVERSE_STMT(CXXThrowExpr, {})
|
||||
DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
|
||||
DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
|
||||
DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {})
|
||||
DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
|
||||
DEF_TRAVERSE_STMT(GNUNullExpr, {})
|
||||
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
|
||||
DEF_TRAVERSE_STMT(NoInitExpr, {})
|
||||
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
|
||||
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
|
||||
if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
|
||||
@ -2356,6 +2355,9 @@ DEF_TRAVERSE_STMT(OMPBarrierDirective,
|
||||
DEF_TRAVERSE_STMT(OMPTaskwaitDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPTaskgroupDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPFlushDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
|
@ -178,7 +178,12 @@ class Decl {
|
||||
OBJC_TQ_Out = 0x4,
|
||||
OBJC_TQ_Bycopy = 0x8,
|
||||
OBJC_TQ_Byref = 0x10,
|
||||
OBJC_TQ_Oneway = 0x20
|
||||
OBJC_TQ_Oneway = 0x20,
|
||||
|
||||
/// The nullability qualifier is set when the nullability of the
|
||||
/// result or parameter was expressed via a context-sensitive
|
||||
/// keyword.
|
||||
OBJC_TQ_CSNullability = 0x40
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -1440,7 +1440,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
///
|
||||
/// \returns true if this class is derived from \p Base, false otherwise.
|
||||
///
|
||||
/// \todo add a separate paramaeter to configure IsDerivedFrom, rather than
|
||||
/// \todo add a separate parameter to configure IsDerivedFrom, rather than
|
||||
/// tangling input and output in \p Paths
|
||||
bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const;
|
||||
|
||||
|
@ -141,7 +141,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
|
||||
/// in, inout, etc.
|
||||
unsigned objcDeclQualifier : 6;
|
||||
unsigned objcDeclQualifier : 7;
|
||||
|
||||
/// \brief Indicates whether this method has a related result type.
|
||||
unsigned RelatedResultType : 1;
|
||||
@ -2203,13 +2203,17 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
OBJC_PR_atomic = 0x100,
|
||||
OBJC_PR_weak = 0x200,
|
||||
OBJC_PR_strong = 0x400,
|
||||
OBJC_PR_unsafe_unretained = 0x800
|
||||
OBJC_PR_unsafe_unretained = 0x800,
|
||||
/// Indicates that the nullability of the type was spelled with a
|
||||
/// property attribute rather than a type qualifier.
|
||||
OBJC_PR_nullability = 0x1000,
|
||||
OBJC_PR_null_resettable = 0x2000
|
||||
// Adding a property should change NumPropertyAttrsBits
|
||||
};
|
||||
|
||||
enum {
|
||||
/// \brief Number of bits fitting all the property attributes.
|
||||
NumPropertyAttrsBits = 12
|
||||
NumPropertyAttrsBits = 14
|
||||
};
|
||||
|
||||
enum SetterKind { Assign, Retain, Copy, Weak };
|
||||
@ -2217,7 +2221,8 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
private:
|
||||
SourceLocation AtLoc; // location of \@property
|
||||
SourceLocation LParenLoc; // location of '(' starting attribute list or null.
|
||||
TypeSourceInfo *DeclType;
|
||||
QualType DeclType;
|
||||
TypeSourceInfo *DeclTypeSourceInfo;
|
||||
unsigned PropertyAttributes : NumPropertyAttrsBits;
|
||||
unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits;
|
||||
// \@required/\@optional
|
||||
@ -2232,12 +2237,13 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
|
||||
ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
|
||||
SourceLocation AtLocation, SourceLocation LParenLocation,
|
||||
TypeSourceInfo *T)
|
||||
QualType T, TypeSourceInfo *TSI,
|
||||
PropertyControl propControl)
|
||||
: NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
|
||||
LParenLoc(LParenLocation), DeclType(T),
|
||||
LParenLoc(LParenLocation), DeclType(T), DeclTypeSourceInfo(TSI),
|
||||
PropertyAttributes(OBJC_PR_noattr),
|
||||
PropertyAttributesAsWritten(OBJC_PR_noattr),
|
||||
PropertyImplementation(None),
|
||||
PropertyImplementation(propControl),
|
||||
GetterName(Selector()),
|
||||
SetterName(Selector()),
|
||||
GetterMethodDecl(nullptr), SetterMethodDecl(nullptr),
|
||||
@ -2248,7 +2254,8 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
SourceLocation L,
|
||||
IdentifierInfo *Id, SourceLocation AtLocation,
|
||||
SourceLocation LParenLocation,
|
||||
TypeSourceInfo *T,
|
||||
QualType T,
|
||||
TypeSourceInfo *TSI,
|
||||
PropertyControl propControl = None);
|
||||
|
||||
static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
@ -2259,9 +2266,14 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
SourceLocation getLParenLoc() const { return LParenLoc; }
|
||||
void setLParenLoc(SourceLocation L) { LParenLoc = L; }
|
||||
|
||||
TypeSourceInfo *getTypeSourceInfo() const { return DeclType; }
|
||||
QualType getType() const { return DeclType->getType(); }
|
||||
void setType(TypeSourceInfo *T) { DeclType = T; }
|
||||
TypeSourceInfo *getTypeSourceInfo() const { return DeclTypeSourceInfo; }
|
||||
|
||||
QualType getType() const { return DeclType; }
|
||||
|
||||
void setType(QualType T, TypeSourceInfo *TSI) {
|
||||
DeclType = T;
|
||||
DeclTypeSourceInfo = TSI;
|
||||
}
|
||||
|
||||
PropertyAttributeKind getPropertyAttributes() const {
|
||||
return PropertyAttributeKind(PropertyAttributes);
|
||||
|
@ -217,6 +217,88 @@ class TemplateArgumentList {
|
||||
}
|
||||
};
|
||||
|
||||
void *allocateDefaultArgStorageChain(const ASTContext &C);
|
||||
|
||||
/// Storage for a default argument. This is conceptually either empty, or an
|
||||
/// argument value, or a pointer to a previous declaration that had a default
|
||||
/// argument.
|
||||
///
|
||||
/// However, this is complicated by modules: while we require all the default
|
||||
/// arguments for a template to be equivalent, there may be more than one, and
|
||||
/// we need to track all the originating parameters to determine if the default
|
||||
/// argument is visible.
|
||||
template<typename ParmDecl, typename ArgType>
|
||||
class DefaultArgStorage {
|
||||
/// Storage for both the value *and* another parameter from which we inherit
|
||||
/// the default argument. This is used when multiple default arguments for a
|
||||
/// parameter are merged together from different modules.
|
||||
struct Chain {
|
||||
ParmDecl *PrevDeclWithDefaultArg;
|
||||
ArgType Value;
|
||||
};
|
||||
static_assert(sizeof(Chain) == sizeof(void *) * 2,
|
||||
"non-pointer argument type?");
|
||||
|
||||
llvm::PointerUnion3<ArgType, ParmDecl*, Chain*> ValueOrInherited;
|
||||
|
||||
static ParmDecl *getParmOwningDefaultArg(ParmDecl *Parm) {
|
||||
const DefaultArgStorage &Storage = Parm->getDefaultArgStorage();
|
||||
if (auto *Prev = Storage.ValueOrInherited.template dyn_cast<ParmDecl*>())
|
||||
Parm = Prev;
|
||||
assert(!Parm->getDefaultArgStorage()
|
||||
.ValueOrInherited.template is<ParmDecl *>() &&
|
||||
"should only be one level of indirection");
|
||||
return Parm;
|
||||
}
|
||||
|
||||
public:
|
||||
DefaultArgStorage() : ValueOrInherited(ArgType()) {}
|
||||
|
||||
/// Determine whether there is a default argument for this parameter.
|
||||
bool isSet() const { return !ValueOrInherited.isNull(); }
|
||||
/// Determine whether the default argument for this parameter was inherited
|
||||
/// from a previous declaration of the same entity.
|
||||
bool isInherited() const { return ValueOrInherited.template is<ParmDecl*>(); }
|
||||
/// Get the default argument's value. This does not consider whether the
|
||||
/// default argument is visible.
|
||||
ArgType get() const {
|
||||
const DefaultArgStorage *Storage = this;
|
||||
if (auto *Prev = ValueOrInherited.template dyn_cast<ParmDecl*>())
|
||||
Storage = &Prev->getDefaultArgStorage();
|
||||
if (auto *C = Storage->ValueOrInherited.template dyn_cast<Chain*>())
|
||||
return C->Value;
|
||||
return Storage->ValueOrInherited.template get<ArgType>();
|
||||
}
|
||||
/// Get the parameter from which we inherit the default argument, if any.
|
||||
/// This is the parameter on which the default argument was actually written.
|
||||
const ParmDecl *getInheritedFrom() const {
|
||||
if (auto *D = ValueOrInherited.template dyn_cast<ParmDecl*>())
|
||||
return D;
|
||||
if (auto *C = ValueOrInherited.template dyn_cast<Chain*>())
|
||||
return C->PrevDeclWithDefaultArg;
|
||||
return nullptr;
|
||||
}
|
||||
/// Set the default argument.
|
||||
void set(ArgType Arg) {
|
||||
assert(!isSet() && "default argument already set");
|
||||
ValueOrInherited = Arg;
|
||||
}
|
||||
/// Set that the default argument was inherited from another parameter.
|
||||
void setInherited(const ASTContext &C, ParmDecl *InheritedFrom) {
|
||||
assert(!isInherited() && "default argument already inherited");
|
||||
InheritedFrom = getParmOwningDefaultArg(InheritedFrom);
|
||||
if (!isSet())
|
||||
ValueOrInherited = InheritedFrom;
|
||||
else
|
||||
ValueOrInherited = new (allocateDefaultArgStorageChain(C))
|
||||
Chain{InheritedFrom, ValueOrInherited.template get<ArgType>()};
|
||||
}
|
||||
/// Remove the default argument, even if it was inherited.
|
||||
void clear() {
|
||||
ValueOrInherited = ArgType();
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Kinds of Templates
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -942,18 +1024,16 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// If false, it was declared with the 'class' keyword.
|
||||
bool Typename : 1;
|
||||
|
||||
/// \brief Whether this template type parameter inherited its
|
||||
/// default argument.
|
||||
bool InheritedDefault : 1;
|
||||
|
||||
/// \brief The default template argument, if any.
|
||||
TypeSourceInfo *DefaultArgument;
|
||||
typedef DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *>
|
||||
DefArgStorage;
|
||||
DefArgStorage DefaultArgument;
|
||||
|
||||
TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
bool Typename)
|
||||
: TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename),
|
||||
InheritedDefault(false), DefaultArgument() { }
|
||||
DefaultArgument() { }
|
||||
|
||||
/// Sema creates these on the stack during auto type deduction.
|
||||
friend class Sema;
|
||||
@ -974,35 +1054,45 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// If not, it was declared with the 'class' keyword.
|
||||
bool wasDeclaredWithTypename() const { return Typename; }
|
||||
|
||||
const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const { return DefaultArgument != nullptr; }
|
||||
bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
QualType getDefaultArgument() const { return DefaultArgument->getType(); }
|
||||
QualType getDefaultArgument() const {
|
||||
return DefaultArgument.get()->getType();
|
||||
}
|
||||
|
||||
/// \brief Retrieves the default argument's source information, if any.
|
||||
TypeSourceInfo *getDefaultArgumentInfo() const { return DefaultArgument; }
|
||||
TypeSourceInfo *getDefaultArgumentInfo() const {
|
||||
return DefaultArgument.get();
|
||||
}
|
||||
|
||||
/// \brief Retrieves the location of the default argument declaration.
|
||||
SourceLocation getDefaultArgumentLoc() const;
|
||||
|
||||
/// \brief Determines whether the default argument was inherited
|
||||
/// from a previous declaration of this template.
|
||||
bool defaultArgumentWasInherited() const { return InheritedDefault; }
|
||||
bool defaultArgumentWasInherited() const {
|
||||
return DefaultArgument.isInherited();
|
||||
}
|
||||
|
||||
/// \brief Set the default argument for this template parameter, and
|
||||
/// whether that default argument was inherited from another
|
||||
/// declaration.
|
||||
void setDefaultArgument(TypeSourceInfo *DefArg, bool Inherited) {
|
||||
DefaultArgument = DefArg;
|
||||
InheritedDefault = Inherited;
|
||||
/// \brief Set the default argument for this template parameter.
|
||||
void setDefaultArgument(TypeSourceInfo *DefArg) {
|
||||
DefaultArgument.set(DefArg);
|
||||
}
|
||||
/// \brief Set that this default argument was inherited from another
|
||||
/// parameter.
|
||||
void setInheritedDefaultArgument(const ASTContext &C,
|
||||
TemplateTypeParmDecl *Prev) {
|
||||
DefaultArgument.setInherited(C, Prev);
|
||||
}
|
||||
|
||||
/// \brief Removes the default argument of this template parameter.
|
||||
void removeDefaultArgument() {
|
||||
DefaultArgument = nullptr;
|
||||
InheritedDefault = false;
|
||||
DefaultArgument.clear();
|
||||
}
|
||||
|
||||
/// \brief Set whether this template type parameter was declared with
|
||||
@ -1034,7 +1124,8 @@ class NonTypeTemplateParmDecl
|
||||
: public DeclaratorDecl, protected TemplateParmPosition {
|
||||
/// \brief The default template argument, if any, and whether or not
|
||||
/// it was inherited.
|
||||
llvm::PointerIntPair<Expr*, 1, bool> DefaultArgumentAndInherited;
|
||||
typedef DefaultArgStorage<NonTypeTemplateParmDecl, Expr*> DefArgStorage;
|
||||
DefArgStorage DefaultArgument;
|
||||
|
||||
// FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
|
||||
// down here to save memory.
|
||||
@ -1055,9 +1146,8 @@ class NonTypeTemplateParmDecl
|
||||
IdentifierInfo *Id, QualType T,
|
||||
bool ParameterPack, TypeSourceInfo *TInfo)
|
||||
: DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
|
||||
TemplateParmPosition(D, P), DefaultArgumentAndInherited(nullptr, false),
|
||||
ParameterPack(ParameterPack), ExpandedParameterPack(false),
|
||||
NumExpandedTypes(0)
|
||||
TemplateParmPosition(D, P), ParameterPack(ParameterPack),
|
||||
ExpandedParameterPack(false), NumExpandedTypes(0)
|
||||
{ }
|
||||
|
||||
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
|
||||
@ -1097,16 +1187,14 @@ class NonTypeTemplateParmDecl
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const {
|
||||
return DefaultArgumentAndInherited.getPointer() != nullptr;
|
||||
}
|
||||
bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
Expr *getDefaultArgument() const {
|
||||
return DefaultArgumentAndInherited.getPointer();
|
||||
}
|
||||
Expr *getDefaultArgument() const { return DefaultArgument.get(); }
|
||||
|
||||
/// \brief Retrieve the location of the default argument, if any.
|
||||
SourceLocation getDefaultArgumentLoc() const;
|
||||
@ -1114,22 +1202,20 @@ class NonTypeTemplateParmDecl
|
||||
/// \brief Determines whether the default argument was inherited
|
||||
/// from a previous declaration of this template.
|
||||
bool defaultArgumentWasInherited() const {
|
||||
return DefaultArgumentAndInherited.getInt();
|
||||
return DefaultArgument.isInherited();
|
||||
}
|
||||
|
||||
/// \brief Set the default argument for this template parameter, and
|
||||
/// whether that default argument was inherited from another
|
||||
/// declaration.
|
||||
void setDefaultArgument(Expr *DefArg, bool Inherited) {
|
||||
DefaultArgumentAndInherited.setPointer(DefArg);
|
||||
DefaultArgumentAndInherited.setInt(Inherited);
|
||||
void setDefaultArgument(Expr *DefArg) { DefaultArgument.set(DefArg); }
|
||||
void setInheritedDefaultArgument(const ASTContext &C,
|
||||
NonTypeTemplateParmDecl *Parm) {
|
||||
DefaultArgument.setInherited(C, Parm);
|
||||
}
|
||||
|
||||
/// \brief Removes the default argument of this template parameter.
|
||||
void removeDefaultArgument() {
|
||||
DefaultArgumentAndInherited.setPointer(nullptr);
|
||||
DefaultArgumentAndInherited.setInt(false);
|
||||
}
|
||||
void removeDefaultArgument() { DefaultArgument.clear(); }
|
||||
|
||||
/// \brief Whether this parameter is a non-type template parameter pack.
|
||||
///
|
||||
@ -1217,10 +1303,10 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
{
|
||||
void anchor() override;
|
||||
|
||||
/// DefaultArgument - The default template argument, if any.
|
||||
TemplateArgumentLoc DefaultArgument;
|
||||
/// Whether or not the default argument was inherited.
|
||||
bool DefaultArgumentWasInherited;
|
||||
/// \brief The default template argument, if any.
|
||||
typedef DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *>
|
||||
DefArgStorage;
|
||||
DefArgStorage DefaultArgument;
|
||||
|
||||
/// \brief Whether this parameter is a parameter pack.
|
||||
bool ParameterPack;
|
||||
@ -1237,8 +1323,7 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
unsigned D, unsigned P, bool ParameterPack,
|
||||
IdentifierInfo *Id, TemplateParameterList *Params)
|
||||
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
|
||||
TemplateParmPosition(D, P), DefaultArgument(),
|
||||
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack),
|
||||
TemplateParmPosition(D, P), ParameterPack(ParameterPack),
|
||||
ExpandedParameterPack(false), NumExpandedParams(0)
|
||||
{ }
|
||||
|
||||
@ -1322,15 +1407,16 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
return reinterpret_cast<TemplateParameterList *const *>(this + 1)[I];
|
||||
}
|
||||
|
||||
const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; }
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const {
|
||||
return !DefaultArgument.getArgument().isNull();
|
||||
}
|
||||
bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
|
||||
|
||||
/// \brief Retrieve the default argument, if any.
|
||||
const TemplateArgumentLoc &getDefaultArgument() const {
|
||||
return DefaultArgument;
|
||||
static const TemplateArgumentLoc None;
|
||||
return DefaultArgument.isSet() ? *DefaultArgument.get() : None;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location of the default argument, if any.
|
||||
@ -1339,22 +1425,21 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
/// \brief Determines whether the default argument was inherited
|
||||
/// from a previous declaration of this template.
|
||||
bool defaultArgumentWasInherited() const {
|
||||
return DefaultArgumentWasInherited;
|
||||
return DefaultArgument.isInherited();
|
||||
}
|
||||
|
||||
/// \brief Set the default argument for this template parameter, and
|
||||
/// whether that default argument was inherited from another
|
||||
/// declaration.
|
||||
void setDefaultArgument(const TemplateArgumentLoc &DefArg, bool Inherited) {
|
||||
DefaultArgument = DefArg;
|
||||
DefaultArgumentWasInherited = Inherited;
|
||||
void setDefaultArgument(const ASTContext &C,
|
||||
const TemplateArgumentLoc &DefArg);
|
||||
void setInheritedDefaultArgument(const ASTContext &C,
|
||||
TemplateTemplateParmDecl *Prev) {
|
||||
DefaultArgument.setInherited(C, Prev);
|
||||
}
|
||||
|
||||
/// \brief Removes the default argument of this template parameter.
|
||||
void removeDefaultArgument() {
|
||||
DefaultArgument = TemplateArgumentLoc();
|
||||
DefaultArgumentWasInherited = false;
|
||||
}
|
||||
void removeDefaultArgument() { DefaultArgument.clear(); }
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
SourceLocation End = getLocation();
|
||||
|
@ -26,29 +26,32 @@ class ASTContext;
|
||||
|
||||
/// \brief Given a potentially-evaluated expression, this visitor visits all
|
||||
/// of its potentially-evaluated subexpressions, recursively.
|
||||
template<typename ImplClass>
|
||||
class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
ASTContext &Context;
|
||||
|
||||
template<template <typename> class Ptr, typename ImplClass>
|
||||
class EvaluatedExprVisitorBase : public StmtVisitorBase<Ptr, ImplClass, void> {
|
||||
protected:
|
||||
const ASTContext &Context;
|
||||
|
||||
public:
|
||||
explicit EvaluatedExprVisitor(ASTContext &Context) : Context(Context) { }
|
||||
|
||||
#define PTR(CLASS) typename Ptr<CLASS>::type
|
||||
|
||||
explicit EvaluatedExprVisitorBase(const ASTContext &Context) : Context(Context) { }
|
||||
|
||||
// Expressions that have no potentially-evaluated subexpressions (but may have
|
||||
// other sub-expressions).
|
||||
void VisitDeclRefExpr(DeclRefExpr *E) { }
|
||||
void VisitOffsetOfExpr(OffsetOfExpr *E) { }
|
||||
void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { }
|
||||
void VisitExpressionTraitExpr(ExpressionTraitExpr *E) { }
|
||||
void VisitBlockExpr(BlockExpr *E) { }
|
||||
void VisitCXXUuidofExpr(CXXUuidofExpr *E) { }
|
||||
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { }
|
||||
|
||||
void VisitMemberExpr(MemberExpr *E) {
|
||||
void VisitDeclRefExpr(PTR(DeclRefExpr) E) { }
|
||||
void VisitOffsetOfExpr(PTR(OffsetOfExpr) E) { }
|
||||
void VisitUnaryExprOrTypeTraitExpr(PTR(UnaryExprOrTypeTraitExpr) E) { }
|
||||
void VisitExpressionTraitExpr(PTR(ExpressionTraitExpr) E) { }
|
||||
void VisitBlockExpr(PTR(BlockExpr) E) { }
|
||||
void VisitCXXUuidofExpr(PTR(CXXUuidofExpr) E) { }
|
||||
void VisitCXXNoexceptExpr(PTR(CXXNoexceptExpr) E) { }
|
||||
|
||||
void VisitMemberExpr(PTR(MemberExpr) E) {
|
||||
// Only the base matters.
|
||||
return this->Visit(E->getBase());
|
||||
}
|
||||
|
||||
void VisitChooseExpr(ChooseExpr *E) {
|
||||
|
||||
void VisitChooseExpr(PTR(ChooseExpr) E) {
|
||||
// Don't visit either child expression if the condition is dependent.
|
||||
if (E->getCond()->isValueDependent())
|
||||
return;
|
||||
@ -56,7 +59,7 @@ class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
return this->Visit(E->getChosenSubExpr());
|
||||
}
|
||||
|
||||
void VisitGenericSelectionExpr(GenericSelectionExpr *E) {
|
||||
void VisitGenericSelectionExpr(PTR(GenericSelectionExpr) E) {
|
||||
// The controlling expression of a generic selection is not evaluated.
|
||||
|
||||
// Don't visit either child expression if the condition is type-dependent.
|
||||
@ -67,23 +70,23 @@ class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
return this->Visit(E->getResultExpr());
|
||||
}
|
||||
|
||||
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
|
||||
void VisitDesignatedInitExpr(PTR(DesignatedInitExpr) E) {
|
||||
// Only the actual initializer matters; the designators are all constant
|
||||
// expressions.
|
||||
return this->Visit(E->getInit());
|
||||
}
|
||||
|
||||
void VisitCXXTypeidExpr(CXXTypeidExpr *E) {
|
||||
void VisitCXXTypeidExpr(PTR(CXXTypeidExpr) E) {
|
||||
if (E->isPotentiallyEvaluated())
|
||||
return this->Visit(E->getExprOperand());
|
||||
}
|
||||
|
||||
void VisitCallExpr(CallExpr *CE) {
|
||||
void VisitCallExpr(PTR(CallExpr) CE) {
|
||||
if (!CE->isUnevaluatedBuiltinCall(Context))
|
||||
return static_cast<ImplClass*>(this)->VisitExpr(CE);
|
||||
}
|
||||
|
||||
void VisitLambdaExpr(LambdaExpr *LE) {
|
||||
void VisitLambdaExpr(PTR(LambdaExpr) LE) {
|
||||
// Only visit the capture initializers, and not the body.
|
||||
for (LambdaExpr::capture_init_iterator I = LE->capture_init_begin(),
|
||||
E = LE->capture_init_end();
|
||||
@ -94,11 +97,31 @@ class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
|
||||
/// \brief The basis case walks all of the children of the statement or
|
||||
/// expression, assuming they are all potentially evaluated.
|
||||
void VisitStmt(Stmt *S) {
|
||||
for (Stmt::child_range C = S->children(); C; ++C)
|
||||
void VisitStmt(PTR(Stmt) S) {
|
||||
for (auto C = S->children(); C; ++C)
|
||||
if (*C)
|
||||
this->Visit(*C);
|
||||
}
|
||||
|
||||
#undef PTR
|
||||
};
|
||||
|
||||
/// EvaluatedExprVisitor - This class visits 'Expr *'s
|
||||
template<typename ImplClass>
|
||||
class EvaluatedExprVisitor
|
||||
: public EvaluatedExprVisitorBase<make_ptr, ImplClass> {
|
||||
public:
|
||||
explicit EvaluatedExprVisitor(const ASTContext &Context) :
|
||||
EvaluatedExprVisitorBase<make_ptr, ImplClass>(Context) { }
|
||||
};
|
||||
|
||||
/// ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.
|
||||
template<typename ImplClass>
|
||||
class ConstEvaluatedExprVisitor
|
||||
: public EvaluatedExprVisitorBase<make_const_ptr, ImplClass> {
|
||||
public:
|
||||
explicit ConstEvaluatedExprVisitor(const ASTContext &Context) :
|
||||
EvaluatedExprVisitorBase<make_const_ptr, ImplClass>(Context) { }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -598,7 +598,7 @@ class Expr : public Stmt {
|
||||
|
||||
/// \brief Determine whether this expression involves a call to any function
|
||||
/// that is not trivial.
|
||||
bool hasNonTrivialCall(ASTContext &Ctx);
|
||||
bool hasNonTrivialCall(const ASTContext &Ctx) const;
|
||||
|
||||
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
|
||||
/// integer. This must be called on an expression that constant folds to an
|
||||
@ -2273,7 +2273,7 @@ class CallExpr : public Expr {
|
||||
|
||||
/// \brief Returns \c true if this is a call to a builtin which does not
|
||||
/// evaluate side-effects within its arguments.
|
||||
bool isUnevaluatedBuiltinCall(ASTContext &Ctx) const;
|
||||
bool isUnevaluatedBuiltinCall(const ASTContext &Ctx) const;
|
||||
|
||||
/// 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
|
||||
@ -4267,6 +4267,80 @@ class DesignatedInitExpr : public Expr {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a place-holder for an object not to be initialized by
|
||||
/// anything.
|
||||
///
|
||||
/// This only makes sense when it appears as part of an updater of a
|
||||
/// DesignatedInitUpdateExpr (see below). The base expression of a DIUE
|
||||
/// initializes a big object, and the NoInitExpr's mark the spots within the
|
||||
/// big object not to be overwritten by the updater.
|
||||
///
|
||||
/// \see DesignatedInitUpdateExpr
|
||||
class NoInitExpr : public Expr {
|
||||
public:
|
||||
explicit NoInitExpr(QualType ty)
|
||||
: Expr(NoInitExprClass, ty, VK_RValue, OK_Ordinary,
|
||||
false, false, ty->isInstantiationDependentType(), false) { }
|
||||
|
||||
explicit NoInitExpr(EmptyShell Empty)
|
||||
: Expr(NoInitExprClass, Empty) { }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == NoInitExprClass;
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
// In cases like:
|
||||
// struct Q { int a, b, c; };
|
||||
// Q *getQ();
|
||||
// void foo() {
|
||||
// struct A { Q q; } a = { *getQ(), .q.b = 3 };
|
||||
// }
|
||||
//
|
||||
// We will have an InitListExpr for a, with type A, and then a
|
||||
// DesignatedInitUpdateExpr for "a.q" with type Q. The "base" for this DIUE
|
||||
// is the call expression *getQ(); the "updater" for the DIUE is ".q.b = 3"
|
||||
//
|
||||
class DesignatedInitUpdateExpr : public Expr {
|
||||
// BaseAndUpdaterExprs[0] is the base expression;
|
||||
// BaseAndUpdaterExprs[1] is an InitListExpr overwriting part of the base.
|
||||
Stmt *BaseAndUpdaterExprs[2];
|
||||
|
||||
public:
|
||||
DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lBraceLoc,
|
||||
Expr *baseExprs, SourceLocation rBraceLoc);
|
||||
|
||||
explicit DesignatedInitUpdateExpr(EmptyShell Empty)
|
||||
: Expr(DesignatedInitUpdateExprClass, Empty) { }
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY;
|
||||
SourceLocation getLocEnd() const LLVM_READONLY;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DesignatedInitUpdateExprClass;
|
||||
}
|
||||
|
||||
Expr *getBase() const { return cast<Expr>(BaseAndUpdaterExprs[0]); }
|
||||
void setBase(Expr *Base) { BaseAndUpdaterExprs[0] = Base; }
|
||||
|
||||
InitListExpr *getUpdater() const {
|
||||
return cast<InitListExpr>(BaseAndUpdaterExprs[1]);
|
||||
}
|
||||
void setUpdater(Expr *Updater) { BaseAndUpdaterExprs[1] = Updater; }
|
||||
|
||||
// Iterators
|
||||
// children = the base and the updater
|
||||
child_range children() {
|
||||
return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents an implicitly-generated value initialization of
|
||||
/// an object of a given type.
|
||||
///
|
||||
|
@ -1752,7 +1752,7 @@ class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(getFinals().end() + 2));
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
@ -1837,7 +1837,7 @@ class OMPAlignedClause : public OMPVarListClause<OMPAlignedClause> {
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end() + 1));
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
|
@ -2234,9 +2234,11 @@ DEF_TRAVERSE_STMT(CXXThisExpr, {})
|
||||
DEF_TRAVERSE_STMT(CXXThrowExpr, {})
|
||||
DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
|
||||
DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
|
||||
DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {})
|
||||
DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
|
||||
DEF_TRAVERSE_STMT(GNUNullExpr, {})
|
||||
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
|
||||
DEF_TRAVERSE_STMT(NoInitExpr, {})
|
||||
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
|
||||
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
|
||||
if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
|
||||
@ -2386,6 +2388,9 @@ DEF_TRAVERSE_STMT(OMPBarrierDirective,
|
||||
DEF_TRAVERSE_STMT(OMPTaskwaitDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPTaskgroupDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
DEF_TRAVERSE_STMT(OMPFlushDirective,
|
||||
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
|
||||
|
||||
|
@ -285,24 +285,23 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
CalcLastIterationOffset = 3,
|
||||
PreConditionOffset = 4,
|
||||
CondOffset = 5,
|
||||
SeparatedCondOffset = 6,
|
||||
InitOffset = 7,
|
||||
IncOffset = 8,
|
||||
InitOffset = 6,
|
||||
IncOffset = 7,
|
||||
// The '...End' enumerators do not correspond to child expressions - they
|
||||
// specify the offset to the end (and start of the following counters/
|
||||
// updates/finals arrays).
|
||||
DefaultEnd = 9,
|
||||
DefaultEnd = 8,
|
||||
// The following 7 exprs are used by worksharing loops only.
|
||||
IsLastIterVariableOffset = 9,
|
||||
LowerBoundVariableOffset = 10,
|
||||
UpperBoundVariableOffset = 11,
|
||||
StrideVariableOffset = 12,
|
||||
EnsureUpperBoundOffset = 13,
|
||||
NextLowerBoundOffset = 14,
|
||||
NextUpperBoundOffset = 15,
|
||||
IsLastIterVariableOffset = 8,
|
||||
LowerBoundVariableOffset = 9,
|
||||
UpperBoundVariableOffset = 10,
|
||||
StrideVariableOffset = 11,
|
||||
EnsureUpperBoundOffset = 12,
|
||||
NextLowerBoundOffset = 13,
|
||||
NextUpperBoundOffset = 14,
|
||||
// Offset to the end (and start of the following counters/updates/finals
|
||||
// arrays) for worksharing loop directives.
|
||||
WorksharingEnd = 16,
|
||||
WorksharingEnd = 15,
|
||||
};
|
||||
|
||||
/// \brief Get the counters storage.
|
||||
@ -374,9 +373,8 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
void setPreCond(Expr *PC) {
|
||||
*std::next(child_begin(), PreConditionOffset) = PC;
|
||||
}
|
||||
void setCond(Expr *Cond, Expr *SeparatedCond) {
|
||||
void setCond(Expr *Cond) {
|
||||
*std::next(child_begin(), CondOffset) = Cond;
|
||||
*std::next(child_begin(), SeparatedCondOffset) = SeparatedCond;
|
||||
}
|
||||
void setInit(Expr *Init) { *std::next(child_begin(), InitOffset) = Init; }
|
||||
void setInc(Expr *Inc) { *std::next(child_begin(), IncOffset) = Inc; }
|
||||
@ -435,8 +433,6 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
Expr *PreCond;
|
||||
/// \brief Loop condition.
|
||||
Expr *Cond;
|
||||
/// \brief A condition with 1 iteration separated.
|
||||
Expr *SeparatedCond;
|
||||
/// \brief Loop iteration variable init.
|
||||
Expr *Init;
|
||||
/// \brief Loop increment.
|
||||
@ -467,8 +463,7 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
bool builtAll() {
|
||||
return IterationVarRef != nullptr && LastIteration != nullptr &&
|
||||
NumIterations != nullptr && PreCond != nullptr &&
|
||||
Cond != nullptr && SeparatedCond != nullptr && Init != nullptr &&
|
||||
Inc != nullptr;
|
||||
Cond != nullptr && Init != nullptr && Inc != nullptr;
|
||||
}
|
||||
|
||||
/// \brief Initialize all the fields to null.
|
||||
@ -479,7 +474,6 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
CalcLastIteration = nullptr;
|
||||
PreCond = nullptr;
|
||||
Cond = nullptr;
|
||||
SeparatedCond = nullptr;
|
||||
Init = nullptr;
|
||||
Inc = nullptr;
|
||||
IL = nullptr;
|
||||
@ -519,10 +513,9 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), PreConditionOffset)));
|
||||
}
|
||||
Expr *getCond(bool SeparateIter) const {
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(),
|
||||
(SeparateIter ? SeparatedCondOffset : CondOffset))));
|
||||
Expr *getCond() const {
|
||||
return const_cast<Expr *>(
|
||||
reinterpret_cast<const Expr *>(*std::next(child_begin(), CondOffset)));
|
||||
}
|
||||
Expr *getInit() const {
|
||||
return const_cast<Expr *>(
|
||||
@ -1462,6 +1455,53 @@ class OMPTaskwaitDirective : public OMPExecutableDirective {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This represents '#pragma omp taskgroup' directive.
|
||||
///
|
||||
/// \code
|
||||
/// #pragma omp taskgroup
|
||||
/// \endcode
|
||||
///
|
||||
class OMPTaskgroupDirective : public OMPExecutableDirective {
|
||||
friend class ASTStmtReader;
|
||||
/// \brief Build directive with the given start and end location.
|
||||
///
|
||||
/// \param StartLoc Starting location of the directive kind.
|
||||
/// \param EndLoc Ending location of the directive.
|
||||
///
|
||||
OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc)
|
||||
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
|
||||
StartLoc, EndLoc, 0, 1) {}
|
||||
|
||||
/// \brief Build an empty directive.
|
||||
///
|
||||
explicit OMPTaskgroupDirective()
|
||||
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
|
||||
SourceLocation(), SourceLocation(), 0, 1) {}
|
||||
|
||||
public:
|
||||
/// \brief Creates directive.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param StartLoc Starting location of the directive kind.
|
||||
/// \param EndLoc Ending Location of the directive.
|
||||
/// \param AssociatedStmt Statement, associated with the directive.
|
||||
///
|
||||
static OMPTaskgroupDirective *Create(const ASTContext &C,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation EndLoc,
|
||||
Stmt *AssociatedStmt);
|
||||
|
||||
/// \brief Creates an empty directive.
|
||||
///
|
||||
/// \param C AST context.
|
||||
///
|
||||
static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, EmptyShell);
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == OMPTaskgroupDirectiveClass;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This represents '#pragma omp flush' directive.
|
||||
///
|
||||
/// \code
|
||||
|
@ -1818,6 +1818,19 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
/// checking. Should always return true.
|
||||
bool isLinkageValid() const;
|
||||
|
||||
/// Determine the nullability of the given type.
|
||||
///
|
||||
/// Note that nullability is only captured as sugar within the type
|
||||
/// system, not as part of the canonical type, so nullability will
|
||||
/// be lost by canonicalization and desugaring.
|
||||
Optional<NullabilityKind> getNullability(const ASTContext &context) const;
|
||||
|
||||
/// Determine whether the given type can have a nullability
|
||||
/// specifier applied to it, i.e., if it is any kind of pointer type
|
||||
/// or a dependent type that could instantiate to any kind of
|
||||
/// pointer type.
|
||||
bool canHaveNullability() const;
|
||||
|
||||
const char *getTypeClassName() const;
|
||||
|
||||
QualType getCanonicalTypeInternal() const {
|
||||
@ -3479,7 +3492,10 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||
attr_ptr32,
|
||||
attr_ptr64,
|
||||
attr_sptr,
|
||||
attr_uptr
|
||||
attr_uptr,
|
||||
attr_nonnull,
|
||||
attr_nullable,
|
||||
attr_null_unspecified,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -3513,6 +3529,35 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||
|
||||
bool isCallingConv() const;
|
||||
|
||||
llvm::Optional<NullabilityKind> getImmediateNullability() const;
|
||||
|
||||
/// Retrieve the attribute kind corresponding to the given
|
||||
/// nullability kind.
|
||||
static Kind getNullabilityAttrKind(NullabilityKind kind) {
|
||||
switch (kind) {
|
||||
case NullabilityKind::NonNull:
|
||||
return attr_nonnull;
|
||||
|
||||
case NullabilityKind::Nullable:
|
||||
return attr_nullable;
|
||||
|
||||
case NullabilityKind::Unspecified:
|
||||
return attr_null_unspecified;
|
||||
}
|
||||
llvm_unreachable("Unknown nullability kind.");
|
||||
}
|
||||
|
||||
/// Strip off the top-level nullability annotation on the given
|
||||
/// type, if it's there.
|
||||
///
|
||||
/// \param T The type to strip. If the type is exactly an
|
||||
/// AttributedType specifying nullability (without looking through
|
||||
/// type sugar), the nullability is returned and this type changed
|
||||
/// to the underlying modified type.
|
||||
///
|
||||
/// \returns the top-level nullability, if present.
|
||||
static Optional<NullabilityKind> stripOuterNullability(QualType &T);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getAttrKind(), ModifiedType, EquivalentType);
|
||||
}
|
||||
|
@ -20,17 +20,30 @@
|
||||
// to only have the functions (which is all the user cares about) in the
|
||||
// 'ast_matchers' namespace and hide the boilerplate.
|
||||
//
|
||||
// To define a matcher in user code, always put it into the clang::ast_matchers
|
||||
// namespace and refer to the internal types via the 'internal::':
|
||||
// To define a matcher in user code, put it into your own namespace. This would
|
||||
// help to prevent ODR violations in case a matcher with the same name is
|
||||
// defined in multiple translation units:
|
||||
//
|
||||
// namespace my_matchers {
|
||||
// AST_MATCHER_P(clang::MemberExpr, Member,
|
||||
// clang::ast_matchers::internal::Matcher<clang::ValueDecl>,
|
||||
// InnerMatcher) {
|
||||
// return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
|
||||
// }
|
||||
// } // namespace my_matchers
|
||||
//
|
||||
// Alternatively, an unnamed namespace may be used:
|
||||
//
|
||||
// namespace clang {
|
||||
// namespace ast_matchers {
|
||||
// namespace {
|
||||
// AST_MATCHER_P(MemberExpr, Member,
|
||||
// internal::Matcher<ValueDecl>, InnerMatcher) {
|
||||
// return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
|
||||
// }
|
||||
// } // end namespace ast_matchers
|
||||
// } // end namespace clang
|
||||
// } // namespace
|
||||
// } // namespace ast_matchers
|
||||
// } // namespace clang
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -43,12 +56,13 @@
|
||||
#define AST_MATCHER_FUNCTION(ReturnType, DefineMatcher) \
|
||||
inline ReturnType DefineMatcher##_getInstance(); \
|
||||
inline ReturnType DefineMatcher() { \
|
||||
return internal::MemoizedMatcher< \
|
||||
return ::clang::ast_matchers::internal::MemoizedMatcher< \
|
||||
ReturnType, DefineMatcher##_getInstance>::getInstance(); \
|
||||
} \
|
||||
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.
|
||||
///
|
||||
@ -80,20 +94,24 @@
|
||||
/// The code should return true if 'Node' matches.
|
||||
#define AST_MATCHER(Type, DefineMatcher) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##Matcher : public MatcherInterface<Type> { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public ::clang::ast_matchers::internal::MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher() {} \
|
||||
bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
bool matches(const Type &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder \
|
||||
*Builder) const override; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher() { \
|
||||
return internal::makeMatcher( \
|
||||
inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher() { \
|
||||
return ::clang::ast_matchers::internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##Matcher()); \
|
||||
} \
|
||||
inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
const Type &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that returns a
|
||||
@ -115,27 +133,31 @@
|
||||
OverloadId) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##OverloadId##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
: public ::clang::ast_matchers::internal::MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
|
||||
ParamType const &A##Param) \
|
||||
: Param(A##Param) {} \
|
||||
bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
bool matches(const Type &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder \
|
||||
*Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
ParamType const Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher(ParamType const &Param) { \
|
||||
return internal::makeMatcher( \
|
||||
inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher( \
|
||||
ParamType const &Param) { \
|
||||
return ::clang::ast_matchers::internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param)); \
|
||||
} \
|
||||
typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
|
||||
ParamType const &Param); \
|
||||
typedef ::clang::ast_matchers::internal::Matcher<Type>( \
|
||||
&DefineMatcher##_Type##OverloadId)(ParamType const &Param); \
|
||||
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
const Type &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_MATCHER_P2(
|
||||
/// Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
|
||||
@ -160,30 +182,34 @@
|
||||
ParamType2, Param2, OverloadId) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##OverloadId##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
: public ::clang::ast_matchers::internal::MatcherInterface<Type> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##OverloadId##Matcher(ParamType1 const &A##Param1, \
|
||||
ParamType2 const &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
bool matches(const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
bool matches(const Type &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder \
|
||||
*Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
ParamType1 const Param1; \
|
||||
ParamType2 const Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher(ParamType1 const &Param1, \
|
||||
ParamType2 const &Param2) { \
|
||||
return internal::makeMatcher( \
|
||||
inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher( \
|
||||
ParamType1 const &Param1, ParamType2 const &Param2) { \
|
||||
return ::clang::ast_matchers::internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \
|
||||
Param2)); \
|
||||
} \
|
||||
typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
|
||||
ParamType1 const &Param1, ParamType2 const &Param2); \
|
||||
typedef ::clang::ast_matchers::internal::Matcher<Type>( \
|
||||
&DefineMatcher##_Type##OverloadId)(ParamType1 const &Param1, \
|
||||
ParamType2 const &Param2); \
|
||||
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
const Type &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief Construct a type-list to be passed to the AST_POLYMORPHIC_MATCHER*
|
||||
/// macros.
|
||||
@ -194,7 +220,7 @@
|
||||
/// The \c PolymorphicMatcherWithParam* classes will unpack the function type to
|
||||
/// extract the TypeList object.
|
||||
#define AST_POLYMORPHIC_SUPPORTED_TYPES(...) \
|
||||
void(internal::TypeList<__VA_ARGS__>)
|
||||
void(::clang::ast_matchers::internal::TypeList<__VA_ARGS__>)
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER(DefineMatcher) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that is
|
||||
@ -205,22 +231,26 @@
|
||||
#define AST_POLYMORPHIC_MATCHER(DefineMatcher, ReturnTypesF) \
|
||||
namespace internal { \
|
||||
template <typename NodeType> \
|
||||
class matcher_##DefineMatcher##Matcher : public MatcherInterface<NodeType> { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public ::clang::ast_matchers::internal::MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
bool matches(const NodeType &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder \
|
||||
*Builder) const override; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam0< \
|
||||
inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam0< \
|
||||
internal::matcher_##DefineMatcher##Matcher, ReturnTypesF> \
|
||||
DefineMatcher() { \
|
||||
return internal::PolymorphicMatcherWithParam0< \
|
||||
return ::clang::ast_matchers::internal::PolymorphicMatcherWithParam0< \
|
||||
internal::matcher_##DefineMatcher##Matcher, ReturnTypesF>(); \
|
||||
} \
|
||||
template <typename NodeType> \
|
||||
bool internal::matcher_##DefineMatcher##Matcher<NodeType>::matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
const NodeType &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that is
|
||||
@ -241,33 +271,39 @@
|
||||
namespace internal { \
|
||||
template <typename NodeType, typename ParamT> \
|
||||
class matcher_##DefineMatcher##OverloadId##Matcher \
|
||||
: public MatcherInterface<NodeType> { \
|
||||
: public ::clang::ast_matchers::internal::MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
|
||||
ParamType const &A##Param) \
|
||||
: Param(A##Param) {} \
|
||||
bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
bool matches(const NodeType &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder \
|
||||
*Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
ParamType const Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam1< \
|
||||
inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
|
||||
ReturnTypesF> DefineMatcher(ParamType const &Param) { \
|
||||
return internal::PolymorphicMatcherWithParam1< \
|
||||
ReturnTypesF> \
|
||||
DefineMatcher(ParamType const &Param) { \
|
||||
return ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
|
||||
ReturnTypesF>(Param); \
|
||||
} \
|
||||
typedef internal::PolymorphicMatcherWithParam1< \
|
||||
typedef ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
|
||||
ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
|
||||
ParamType const &Param); \
|
||||
template <typename NodeType, typename ParamT> \
|
||||
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
|
||||
NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
bool internal:: \
|
||||
matcher_##DefineMatcher##OverloadId##Matcher<NodeType, ParamT>::matches( \
|
||||
const NodeType &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) \
|
||||
const
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER_P2(
|
||||
/// DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
|
||||
@ -288,41 +324,46 @@
|
||||
namespace internal { \
|
||||
template <typename NodeType, typename ParamT1, typename ParamT2> \
|
||||
class matcher_##DefineMatcher##OverloadId##Matcher \
|
||||
: public MatcherInterface<NodeType> { \
|
||||
: public ::clang::ast_matchers::internal::MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##OverloadId##Matcher(ParamType1 const &A##Param1, \
|
||||
ParamType2 const &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const override; \
|
||||
bool matches(const NodeType &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder \
|
||||
*Builder) const override; \
|
||||
\
|
||||
private: \
|
||||
ParamType1 const Param1; \
|
||||
ParamType2 const Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam2< \
|
||||
inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
|
||||
ParamType2, ReturnTypesF> DefineMatcher(ParamType1 const &Param1, \
|
||||
ParamType2 const &Param2) { \
|
||||
return internal::PolymorphicMatcherWithParam2< \
|
||||
ParamType2, ReturnTypesF> \
|
||||
DefineMatcher(ParamType1 const &Param1, ParamType2 const &Param2) { \
|
||||
return ::clang::ast_matchers::internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
|
||||
ParamType2, ReturnTypesF>(Param1, Param2); \
|
||||
} \
|
||||
typedef internal::PolymorphicMatcherWithParam2< \
|
||||
typedef ::clang::ast_matchers::internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
|
||||
ParamType2, ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
|
||||
ParamType1 const &Param1, ParamType2 const &Param2); \
|
||||
template <typename NodeType, typename ParamT1, typename ParamT2> \
|
||||
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
|
||||
NodeType, ParamT1, ParamT2>::matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
NodeType, ParamT1, ParamT2>:: \
|
||||
matches(const NodeType &Node, \
|
||||
::clang::ast_matchers::internal::ASTMatchFinder *Finder, \
|
||||
::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) \
|
||||
const
|
||||
|
||||
/// \brief Creates a variadic matcher for both a specific \c Type as well as
|
||||
/// the corresponding \c TypeLoc.
|
||||
#define AST_TYPE_MATCHER(NodeType, MatcherName) \
|
||||
const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName
|
||||
const ::clang::ast_matchers::internal::VariadicDynCastAllOfMatcher< \
|
||||
Type, NodeType> MatcherName
|
||||
// FIXME: add a matcher for TypeLoc derived classes using its custom casting
|
||||
// API (no longer dyn_cast) if/when we need such matching
|
||||
|
||||
@ -330,7 +371,7 @@
|
||||
/// the matcher \c MatcherName that can be used to traverse from one \c Type
|
||||
/// to another.
|
||||
///
|
||||
/// For a specific \c SpecificType, the traversal is done using
|
||||
/// For a specific \c SpecificType, the traversal is done using
|
||||
/// \c SpecificType::FunctionName. The existence of such a function determines
|
||||
/// whether a corresponding matcher can be used on \c SpecificType.
|
||||
#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \
|
||||
@ -339,9 +380,11 @@
|
||||
static QualType (T::*value())() const { return &T::FunctionName; } \
|
||||
}; \
|
||||
} \
|
||||
const internal::TypeTraversePolymorphicMatcher< \
|
||||
QualType, internal::TypeMatcher##MatcherName##Getter, \
|
||||
internal::TypeTraverseMatcher, ReturnTypesF>::Func MatcherName
|
||||
const ::clang::ast_matchers::internal::TypeTraversePolymorphicMatcher< \
|
||||
QualType, \
|
||||
::clang::ast_matchers::internal::TypeMatcher##MatcherName##Getter, \
|
||||
::clang::ast_matchers::internal::TypeTraverseMatcher, \
|
||||
ReturnTypesF>::Func MatcherName
|
||||
|
||||
/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
|
||||
/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
|
||||
@ -351,9 +394,11 @@
|
||||
static TypeLoc (T::*value())() const { return &T::FunctionName##Loc; } \
|
||||
}; \
|
||||
} \
|
||||
const internal::TypeTraversePolymorphicMatcher< \
|
||||
TypeLoc, internal::TypeLocMatcher##MatcherName##Getter, \
|
||||
internal::TypeLocTraverseMatcher, ReturnTypesF>::Func MatcherName##Loc; \
|
||||
const ::clang::ast_matchers::internal::TypeTraversePolymorphicMatcher< \
|
||||
TypeLoc, \
|
||||
::clang::ast_matchers::internal::TypeLocMatcher##MatcherName##Getter, \
|
||||
::clang::ast_matchers::internal::TypeLocTraverseMatcher, \
|
||||
ReturnTypesF>::Func MatcherName##Loc; \
|
||||
AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF)
|
||||
|
||||
#endif
|
||||
|
@ -195,7 +195,8 @@ class CXX11<string namespace, string name, int version = 1>
|
||||
: Spelling<name, "CXX11"> {
|
||||
string Namespace = namespace;
|
||||
int Version = version;
|
||||
} class Keyword<string name> : Spelling<name, "Keyword">;
|
||||
}
|
||||
class Keyword<string name> : Spelling<name, "Keyword">;
|
||||
class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
|
||||
string Namespace = namespace;
|
||||
}
|
||||
@ -959,6 +960,22 @@ def ReturnsNonNull : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
// Nullability type attributes.
|
||||
def TypeNonNull : TypeAttr {
|
||||
let Spellings = [Keyword<"__nonnull">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def TypeNullable : TypeAttr {
|
||||
let Spellings = [Keyword<"__nullable">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def TypeNullUnspecified : TypeAttr {
|
||||
let Spellings = [Keyword<"__null_unspecified">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def AssumeAligned : InheritableAttr {
|
||||
let Spellings = [GCC<"assume_aligned">];
|
||||
let Subjects = SubjectList<[ObjCMethod, Function]>;
|
||||
@ -1250,6 +1267,14 @@ def Pascal : InheritableAttr {
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def Target : InheritableAttr {
|
||||
let Spellings = [GCC<"target">];
|
||||
let Args = [StringArgument<"features">];
|
||||
let Subjects =
|
||||
SubjectList<[Function], ErrorDiag, "ExpectedFunctionMethodOrClass">;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def TransparentUnion : InheritableAttr {
|
||||
let Spellings = [GCC<"transparent_union">];
|
||||
// let Subjects = SubjectList<[Record, TypedefName]>;
|
||||
@ -1935,8 +1960,8 @@ def LoopHint : Attr {
|
||||
["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
|
||||
"Unroll", "UnrollCount"]>,
|
||||
EnumArgument<"State", "LoopHintState",
|
||||
["default", "enable", "disable"],
|
||||
["Default", "Enable", "Disable"]>,
|
||||
["default", "enable", "disable", "assume_safety"],
|
||||
["Default", "Enable", "Disable", "AssumeSafety"]>,
|
||||
ExprArgument<"Value">];
|
||||
|
||||
let AdditionalMembers = [{
|
||||
@ -1982,6 +2007,8 @@ def LoopHint : Attr {
|
||||
return "";
|
||||
else if (state == Enable)
|
||||
OS << (option == Unroll ? "full" : "enable");
|
||||
else if (state == AssumeSafety)
|
||||
OS << "assume_safety";
|
||||
else
|
||||
OS << "disable";
|
||||
OS << ")";
|
||||
|
@ -1240,6 +1240,10 @@ BUILTIN(__builtin_addressof, "v*v&", "nct")
|
||||
BUILTIN(__builtin_operator_new, "v*z", "c")
|
||||
BUILTIN(__builtin_operator_delete, "vv*", "n")
|
||||
|
||||
// Safestack builtins
|
||||
BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn")
|
||||
BUILTIN(__builtin___get_unsafe_stack_ptr, "v*", "Fn")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LIBBUILTIN
|
||||
#undef LANGBUILTIN
|
||||
|
@ -53,4 +53,12 @@ BUILTIN(__builtin_arm_isb, "vUi", "nc")
|
||||
// Prefetch
|
||||
BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc")
|
||||
|
||||
// System Registers
|
||||
BUILTIN(__builtin_arm_rsr, "UicC*", "nc")
|
||||
BUILTIN(__builtin_arm_rsr64, "LUicC*", "nc")
|
||||
BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc")
|
||||
BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc")
|
||||
BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc")
|
||||
BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
|
||||
|
||||
#undef BUILTIN
|
||||
|
@ -1,4 +1,4 @@
|
||||
//==- BuiltinsR600.def - R600 Builtin function database ----------*- C++ -*-==//
|
||||
//==- BuiltinsAMDGPU.def - AMDGPU Builtin function database ------*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
@ -84,6 +84,14 @@ BUILTIN(__builtin_arm_isb, "vUi", "nc")
|
||||
// Prefetch
|
||||
BUILTIN(__builtin_arm_prefetch, "vvC*UiUi", "nc")
|
||||
|
||||
// System registers (ACLE)
|
||||
BUILTIN(__builtin_arm_rsr, "UicC*", "nc")
|
||||
BUILTIN(__builtin_arm_rsr64, "LLUicC*", "nc")
|
||||
BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc")
|
||||
BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc")
|
||||
BUILTIN(__builtin_arm_wsr64, "vcC*LLUi", "nc")
|
||||
BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
|
||||
|
||||
// MSVC
|
||||
LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES)
|
||||
|
||||
|
@ -231,6 +231,9 @@ BUILTIN(__builtin_altivec_vcmpgtsd_p, "iiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtud_p, "iiV2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vgbbd, "V16UcV16Uc", "")
|
||||
BUILTIN(__builtin_altivec_vbpermq, "V2ULLiV16UcV16Uc", "")
|
||||
|
||||
// P8 Crypto built-ins.
|
||||
BUILTIN(__builtin_altivec_crypto_vsbox, "V2ULLiV2ULLi", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpermxor, "V16UcV16UcV16UcV16Uc", "")
|
||||
|
@ -59,6 +59,9 @@ BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "nc")
|
||||
// All MMX instructions will be generated via builtins. Any MMX vector
|
||||
// types (<1 x i64>, <2 x i32>, etc.) that aren't used by these builtins will be
|
||||
// expanded by the back-end.
|
||||
// FIXME: _mm_prefetch must be a built-in because it takes a compile-time constant
|
||||
// argument and our prior approach of using a #define to the current built-in
|
||||
// doesn't work in the presence of re-declaration of _mm_prefetch for windows.
|
||||
BUILTIN(_mm_prefetch, "vcC*i", "nc")
|
||||
BUILTIN(__builtin_ia32_emms, "v", "")
|
||||
BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "")
|
||||
|
@ -99,6 +99,37 @@ def err_enum_template : Error<"enumeration cannot be a template">;
|
||||
|
||||
}
|
||||
|
||||
let CategoryName = "Nullability Issue" in {
|
||||
|
||||
def warn_nullability_duplicate : Warning<
|
||||
"duplicate nullability specifier "
|
||||
"'%select{__|}1%select{nonnull|nullable|null_unspecified}0'">,
|
||||
InGroup<Nullability>;
|
||||
|
||||
def warn_conflicting_nullability_attr_overriding_ret_types : Warning<
|
||||
"conflicting nullability specifier on return types, "
|
||||
"'%select{%select{__|}1nonnull|"
|
||||
"%select{__|}1nullable|%select{__|}1null_unspecified}0' "
|
||||
"conflicts with existing specifier '%select{%select{__|}3nonnull|"
|
||||
"%select{__|}3nullable|%select{__|}3null_unspecified}2'">,
|
||||
InGroup<Nullability>;
|
||||
|
||||
def warn_conflicting_nullability_attr_overriding_param_types : Warning<
|
||||
"conflicting nullability specifier on parameter types, "
|
||||
"'%select{%select{__|}1nonnull|"
|
||||
"%select{__|}1nullable|%select{__|}1null_unspecified}0' "
|
||||
"conflicts with existing specifier '%select{%select{__|}3nonnull|"
|
||||
"%select{__|}3nullable|%select{__|}3null_unspecified}2'">,
|
||||
InGroup<Nullability>;
|
||||
|
||||
def err_nullability_conflicting : Error<
|
||||
"nullability specifier "
|
||||
"'%select{__|}1%select{nonnull|nullable|null_unspecified}0' conflicts with "
|
||||
"existing specifier '%select{__|}3%select{nonnull|nullable|"
|
||||
"null_unspecified}2'">;
|
||||
|
||||
}
|
||||
|
||||
// Sema && Lex
|
||||
def ext_c99_longlong : Extension<
|
||||
"'long long' is an extension when C99 mode is not enabled">,
|
||||
|
@ -248,6 +248,10 @@ def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
|
||||
def ModuleBuild : DiagGroup<"module-build">;
|
||||
def ModuleConflict : DiagGroup<"module-conflict">;
|
||||
def NewlineEOF : DiagGroup<"newline-eof">;
|
||||
def Nullability : DiagGroup<"nullability">;
|
||||
def NullabilityDeclSpec : DiagGroup<"nullability-declspec">;
|
||||
def NullableToNonNullConversion : DiagGroup<"nullable-to-nonnull-conversion">;
|
||||
def NullabilityCompleteness : DiagGroup<"nullability-completeness">;
|
||||
def NullArithmetic : DiagGroup<"null-arithmetic">;
|
||||
def NullCharacter : DiagGroup<"null-character">;
|
||||
def NullDereference : DiagGroup<"null-dereference">;
|
||||
@ -598,6 +602,7 @@ def Most : DiagGroup<"most", [
|
||||
DeleteNonVirtualDtor,
|
||||
Format,
|
||||
Implicit,
|
||||
InfiniteRecursion,
|
||||
MismatchedTags,
|
||||
MissingBraces,
|
||||
Move,
|
||||
|
@ -646,5 +646,20 @@ def warn_header_guard : Warning<
|
||||
"%0 is used as a header guard here, followed by #define of a different macro">,
|
||||
InGroup<DiagGroup<"header-guard">>;
|
||||
def note_header_guard : Note<
|
||||
"%0 is defined here; did you mean %1?">;
|
||||
"%0 is defined here; did you mean %1?">;
|
||||
|
||||
let CategoryName = "Nullability Issue" in {
|
||||
|
||||
def err_pp_assume_nonnull_syntax : Error<"expected 'begin' or 'end'">;
|
||||
def err_pp_double_begin_of_assume_nonnull : Error<
|
||||
"already inside '#pragma clang assume_nonnull'">;
|
||||
def err_pp_unmatched_end_of_assume_nonnull : Error<
|
||||
"not currently inside '#pragma clang assume_nonnull'">;
|
||||
def err_pp_include_in_assume_nonnull : Error<
|
||||
"cannot #include files inside '#pragma clang assume_nonnull'">;
|
||||
def err_pp_eof_in_assume_nonnull : Error<
|
||||
"'#pragma clang assume_nonnull' was not ended within this file">;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,7 +69,10 @@ ENUM_DIAGOPT(ShowOverloads, OverloadsShown, 1,
|
||||
DIAGOPT(VerifyDiagnostics, 1, 0) /// Check that diagnostics match the expected
|
||||
/// diagnostics, indicated by markers in the
|
||||
/// input source file.
|
||||
|
||||
ENUM_DIAGOPT(VerifyIgnoreUnexpected, DiagnosticLevelMask, 4,
|
||||
DiagnosticLevelMask::None) /// Ignore unexpected diagnostics of
|
||||
/// the specified levels when using
|
||||
/// -verify.
|
||||
DIAGOPT(ElideType, 1, 0) /// Elide identical types in template diffing
|
||||
DIAGOPT(ShowTemplateTree, 1, 0) /// Print a template tree when diffing
|
||||
DIAGOPT(CLFallbackMode, 1, 0) /// Format for clang-cl fallback mode
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
@ -24,6 +25,38 @@ enum OverloadsShown : unsigned {
|
||||
Ovl_Best ///< Show just the "best" overload candidates.
|
||||
};
|
||||
|
||||
/// \brief A bitmask representing the diagnostic levels used by
|
||||
/// VerifyDiagnosticConsumer.
|
||||
enum class DiagnosticLevelMask : unsigned {
|
||||
None = 0,
|
||||
Note = 1 << 0,
|
||||
Remark = 1 << 1,
|
||||
Warning = 1 << 2,
|
||||
Error = 1 << 3,
|
||||
All = Note | Remark | Warning | Error
|
||||
};
|
||||
|
||||
inline DiagnosticLevelMask operator~(DiagnosticLevelMask M) {
|
||||
using UT = std::underlying_type<DiagnosticLevelMask>::type;
|
||||
return static_cast<DiagnosticLevelMask>(~static_cast<UT>(M));
|
||||
}
|
||||
|
||||
inline DiagnosticLevelMask operator|(DiagnosticLevelMask LHS,
|
||||
DiagnosticLevelMask RHS) {
|
||||
using UT = std::underlying_type<DiagnosticLevelMask>::type;
|
||||
return static_cast<DiagnosticLevelMask>(
|
||||
static_cast<UT>(LHS) | static_cast<UT>(RHS));
|
||||
}
|
||||
|
||||
inline DiagnosticLevelMask operator&(DiagnosticLevelMask LHS,
|
||||
DiagnosticLevelMask RHS) {
|
||||
using UT = std::underlying_type<DiagnosticLevelMask>::type;
|
||||
return static_cast<DiagnosticLevelMask>(
|
||||
static_cast<UT>(LHS) & static_cast<UT>(RHS));
|
||||
}
|
||||
|
||||
raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M);
|
||||
|
||||
/// \brief Options for controlling the compiler diagnostics engine.
|
||||
class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{
|
||||
public:
|
||||
|
@ -65,6 +65,10 @@ def ext_keyword_as_ident : ExtWarn<
|
||||
"%select{here|for the remainder of the translation unit}1">,
|
||||
InGroup<KeywordCompat>;
|
||||
|
||||
def ext_nullability : Extension<
|
||||
"type nullability specifier %0 is a Clang extension">,
|
||||
InGroup<DiagGroup<"nullability-extension">>;
|
||||
|
||||
def error_empty_enum : Error<"use of empty enum">;
|
||||
def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
|
||||
def err_invalid_short_spec : Error<"'short %0' is invalid">;
|
||||
@ -989,17 +993,21 @@ def err_omp_expected_identifier_for_critical : Error<
|
||||
// Pragma loop support.
|
||||
def err_pragma_loop_missing_argument : Error<
|
||||
"missing argument; expected %select{an integer value|"
|
||||
"'%select{enable|full}1' or 'disable'}0">;
|
||||
"%select{'enable', 'assume_safety'|'full'}1 or 'disable'}0">;
|
||||
def err_pragma_loop_invalid_option : Error<
|
||||
"%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
|
||||
"vectorize_width, interleave, interleave_count, unroll, or unroll_count">;
|
||||
def err_pragma_invalid_keyword : Error<
|
||||
"invalid argument; expected '%select{enable|full}0' or 'disable'">;
|
||||
"invalid argument; expected %select{'enable', 'assume_safety'|'full'}0 or 'disable'">;
|
||||
|
||||
// Pragma unroll support.
|
||||
def warn_pragma_unroll_cuda_value_in_parens : Warning<
|
||||
"argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,
|
||||
InGroup<CudaCompat>;
|
||||
|
||||
def err_empty_attribute_block : Error<
|
||||
"Microsoft attribute block cannot be empty">;
|
||||
|
||||
} // end of Parse Issue category.
|
||||
|
||||
let CategoryName = "Modules Issue" in {
|
||||
|
@ -108,6 +108,7 @@ def err_ice_ambiguous_conversion : Error<
|
||||
def err_ice_too_large : Error<
|
||||
"integer constant expression evaluates to value %0 that cannot be "
|
||||
"represented in a %1-bit %select{signed|unsigned}2 integer type">;
|
||||
def err_expr_not_string_literal : Error<"expression is not a string literal">;
|
||||
|
||||
// Semantic analysis of constant literals.
|
||||
def ext_predef_outside_function : Warning<
|
||||
@ -424,6 +425,7 @@ def warn_redecl_library_builtin : Warning<
|
||||
"incompatible redeclaration of library function %0">,
|
||||
InGroup<DiagGroup<"incompatible-library-redeclaration">>;
|
||||
def err_builtin_definition : Error<"definition of builtin function %0">;
|
||||
def err_arm_invalid_specialreg : Error<"invalid special register for builtin">;
|
||||
def warn_builtin_unknown : Warning<"use of unknown builtin %0">,
|
||||
InGroup<ImplicitFunctionDeclare>, DefaultError;
|
||||
def warn_dyn_class_memaccess : Warning<
|
||||
@ -1974,8 +1976,11 @@ def err_attribute_too_few_arguments : Error<
|
||||
def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">;
|
||||
def err_attribute_bad_neon_vector_size : Error<
|
||||
"Neon vector size must be 64 or 128 bits">;
|
||||
def err_attribute_unsupported : Error<
|
||||
"%0 attribute is not supported for this target">;
|
||||
def warn_unsupported_target_attribute
|
||||
: Warning<"Ignoring unsupported '%0' in the target attribute string">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_attribute_unsupported
|
||||
: Error<"%0 attribute is not supported for this target">;
|
||||
// The err_*_attribute_argument_not_int are seperate because they're used by
|
||||
// VerifyIntegerConstantExpression.
|
||||
def err_aligned_attribute_argument_not_int : Error<
|
||||
@ -2249,7 +2254,7 @@ def warn_attribute_dllimport_static_field_definition : Warning<
|
||||
InGroup<DiagGroup<"dllimport-static-field-def">>;
|
||||
def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
|
||||
"explicit instantiation declaration should not be 'dllexport'">,
|
||||
InGroup<DiagGroup<"dllexport-explicit-instantation-decl">>;
|
||||
InGroup<DiagGroup<"dllexport-explicit-instantiation-decl">>;
|
||||
def warn_invalid_initializer_from_system_header : Warning<
|
||||
"invalid constructor form class in system header, should not be explicit">,
|
||||
InGroup<DiagGroup<"invalid-initializer-from-system-header">>;
|
||||
@ -2680,6 +2685,8 @@ def err_mode_not_primitive : Error<
|
||||
"mode attribute only supported for integer and floating-point types">;
|
||||
def err_mode_wrong_type : Error<
|
||||
"type of machine mode does not match type of base type">;
|
||||
def err_complex_mode_vector_type : Error<
|
||||
"type of machine mode does not support base vector types">;
|
||||
def err_attr_wrong_decl : Error<
|
||||
"%0 attribute invalid on this declaration, requires typedef or value">;
|
||||
def warn_attribute_nonnull_no_pointers : Warning<
|
||||
@ -2744,8 +2751,8 @@ def warn_ns_attribute_wrong_return_type : Warning<
|
||||
"return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_ns_attribute_wrong_parameter_type : Warning<
|
||||
"%0 attribute only applies to %select{Objective-C object|pointer}1 "
|
||||
"parameters">,
|
||||
"%0 attribute only applies to "
|
||||
"%select{Objective-C object|pointer|pointer-to-CF-pointer}1 parameters">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_objc_requires_super_protocol : Warning<
|
||||
"%0 attribute cannot be applied to %select{methods in protocols|dealloc}1">,
|
||||
@ -7631,10 +7638,12 @@ def err_module_private_local : Error<
|
||||
def err_module_private_local_class : Error<
|
||||
"local %select{struct|interface|union|class|enum}0 cannot be declared "
|
||||
"__module_private__">;
|
||||
def err_module_private_declaration : Error<
|
||||
"declaration of %0 must be imported from module '%1' before it is required">;
|
||||
def err_module_private_definition : Error<
|
||||
"definition of %0 must be imported from module '%1' before it is required">;
|
||||
def err_module_unimported_use : Error<
|
||||
"%select{declaration|definition|default argument}0 of %1 must be imported "
|
||||
"from module '%2' before it is required">;
|
||||
def err_module_unimported_use_multiple : Error<
|
||||
"%select{declaration|definition|default argument}0 of %1 must be imported "
|
||||
"from one of the following modules before it is required:%2">;
|
||||
def err_module_import_in_extern_c : Error<
|
||||
"import of C++ module '%0' appears within extern \"C\" language linkage "
|
||||
"specification">;
|
||||
@ -7665,4 +7674,55 @@ def warn_profile_data_unprofiled : Warning<
|
||||
|
||||
} // end of instrumentation issue category
|
||||
|
||||
let CategoryName = "Nullability Issue" in {
|
||||
|
||||
def warn_mismatched_nullability_attr : Warning<
|
||||
"nullability specifier "
|
||||
"'%select{__|}1%select{nonnull|nullable|null_unspecified}0' "
|
||||
"conflicts with existing specifier "
|
||||
"'%select{__|}3%select{nonnull|nullable|null_unspecified}2'">,
|
||||
InGroup<Nullability>;
|
||||
|
||||
def warn_nullability_declspec : Warning<
|
||||
"nullability specifier "
|
||||
"'%select{__nonnull|__nullable|__null_unspecified}0' cannot be applied "
|
||||
"to non-pointer type %1; did you mean to apply the specifier to the "
|
||||
"%select{pointer|block pointer|member pointer|function pointer|"
|
||||
"member function pointer}2?">,
|
||||
InGroup<NullabilityDeclSpec>,
|
||||
DefaultError;
|
||||
|
||||
def note_nullability_here : Note<
|
||||
"'%select{__nonnull|__nullable|__null_unspecified}0' specified here">;
|
||||
|
||||
def err_nullability_nonpointer : Error<
|
||||
"nullability specifier "
|
||||
"'%select{__|}1%select{nonnull|nullable|null_unspecified}0' cannot be applied "
|
||||
"to non-pointer type %2">;
|
||||
|
||||
def warn_nullability_lost : Warning<
|
||||
"implicit conversion from nullable pointer %0 to non-nullable pointer "
|
||||
"type %1">,
|
||||
InGroup<NullableToNonNullConversion>, DefaultIgnore;
|
||||
|
||||
def err_nullability_cs_multilevel : Error<
|
||||
"nullability keyword "
|
||||
"'%select{nonnull|nullable|null_unspecified}0' cannot be applied to "
|
||||
"multi-level pointer type %1">;
|
||||
def note_nullability_type_specifier : Note<
|
||||
"use nullability type specifier "
|
||||
"'%select{__nonnull|__nullable|__null_unspecified}0' to affect the innermost "
|
||||
"pointer type of %1">;
|
||||
|
||||
def warn_null_resettable_setter : Warning<
|
||||
"synthesized setter %0 for null_resettable property %1 does not handle nil">,
|
||||
InGroup<Nullability>;
|
||||
|
||||
def warn_nullability_missing : Warning<
|
||||
"%select{pointer|block pointer|member pointer}0 is missing a nullability "
|
||||
"type specifier (__nonnull, __nullable, or __null_unspecified)">,
|
||||
InGroup<NullabilityCompleteness>;
|
||||
|
||||
}
|
||||
|
||||
} // end of sema component.
|
||||
|
@ -25,16 +25,8 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <memory>
|
||||
// FIXME: Enhance libsystem to support inode and other fields in stat.
|
||||
#include <sys/types.h>
|
||||
#include <map>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned short mode_t;
|
||||
#endif
|
||||
|
||||
struct stat;
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
}
|
||||
|
@ -127,8 +127,7 @@ LANGOPT(Modules , 1, 0, "modules extension to C")
|
||||
COMPATIBLE_LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses")
|
||||
LANGOPT(ModulesSearchAll , 1, 1, "search even non-imported modules to find unresolved references")
|
||||
COMPATIBLE_LANGOPT(ModulesStrictDeclUse, 1, 0, "require declaration of module uses and all headers to be in modules")
|
||||
LANGOPT(ModulesErrorRecovery, 1, 1, "automatically import modules as needed when performing error recovery")
|
||||
BENIGN_LANGOPT(ModulesImplicitMaps, 1, 1, "use files called module.modulemap implicitly as module maps")
|
||||
BENIGN_LANGOPT(ModulesErrorRecovery, 1, 1, "automatically import modules as needed when performing error recovery")
|
||||
BENIGN_LANGOPT(ImplicitModules, 1, 1, "build modules that are not specified via -fmodule-file")
|
||||
COMPATIBLE_LANGOPT(ModulesLocalVisibility, 1, 0, "local submodule visibility")
|
||||
COMPATIBLE_LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
|
||||
|
@ -84,6 +84,7 @@ OPENMP_DIRECTIVE(critical)
|
||||
OPENMP_DIRECTIVE(taskyield)
|
||||
OPENMP_DIRECTIVE(barrier)
|
||||
OPENMP_DIRECTIVE(taskwait)
|
||||
OPENMP_DIRECTIVE(taskgroup)
|
||||
OPENMP_DIRECTIVE(flush)
|
||||
OPENMP_DIRECTIVE(ordered)
|
||||
OPENMP_DIRECTIVE(atomic)
|
||||
|
@ -41,6 +41,9 @@
|
||||
// AddressSanitizer
|
||||
SANITIZER("address", Address)
|
||||
|
||||
// Kernel AddressSanitizer (KASan)
|
||||
SANITIZER("kernel-address", KernelAddress)
|
||||
|
||||
// MemorySanitizer
|
||||
SANITIZER("memory", Memory)
|
||||
|
||||
@ -87,18 +90,20 @@ SANITIZER("cfi-vcall", CFIVCall)
|
||||
SANITIZER_GROUP("cfi", CFI,
|
||||
CFIDerivedCast | CFIUnrelatedCast | CFINVCall | CFIVCall)
|
||||
|
||||
// -fsanitize=undefined-trap includes sanitizers from -fsanitize=undefined
|
||||
// that can be used without runtime support, generally by providing extra
|
||||
// -fsanitize-undefined-trap-on-error flag.
|
||||
SANITIZER_GROUP("undefined-trap", UndefinedTrap,
|
||||
Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
|
||||
FloatDivideByZero | IntegerDivideByZero | NonnullAttribute |
|
||||
Null | ObjectSize | Return | ReturnsNonnullAttribute |
|
||||
Shift | SignedIntegerOverflow | Unreachable | VLABound)
|
||||
// Safe Stack
|
||||
SANITIZER("safe-stack", SafeStack)
|
||||
|
||||
// -fsanitize=undefined includes all the sanitizers which have low overhead, no
|
||||
// ABI or address space layout implications, and only catch undefined behavior.
|
||||
SANITIZER_GROUP("undefined", Undefined, UndefinedTrap | Function | Vptr)
|
||||
SANITIZER_GROUP("undefined", Undefined,
|
||||
Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
|
||||
FloatDivideByZero | IntegerDivideByZero | NonnullAttribute |
|
||||
Null | ObjectSize | Return | ReturnsNonnullAttribute |
|
||||
Shift | SignedIntegerOverflow | Unreachable | VLABound |
|
||||
Function | Vptr)
|
||||
|
||||
// -fsanitize=undefined-trap is an alias for -fsanitize=undefined.
|
||||
SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined)
|
||||
|
||||
SANITIZER_GROUP("integer", Integer,
|
||||
SignedIntegerOverflow | UnsignedIntegerOverflow | Shift |
|
||||
|
@ -52,6 +52,9 @@ struct SanitizerSet {
|
||||
/// \brief Check if a certain (single) sanitizer is enabled.
|
||||
bool has(SanitizerMask K) const;
|
||||
|
||||
/// \brief Check if one or more sanitizers are enabled.
|
||||
bool hasOneOf(SanitizerMask K) const;
|
||||
|
||||
/// \brief Enable or disable a certain (single) sanitizer.
|
||||
void set(SanitizerMask K, bool Value);
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
#ifndef LLVM_CLANG_BASIC_SPECIFIERS_H
|
||||
#define LLVM_CLANG_BASIC_SPECIFIERS_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace clang {
|
||||
/// \brief Specifies the width of a type, e.g., short, long, or long long.
|
||||
enum TypeSpecifierWidth {
|
||||
@ -239,6 +242,22 @@ namespace clang {
|
||||
SD_Static, ///< Static storage duration.
|
||||
SD_Dynamic ///< Dynamic storage duration.
|
||||
};
|
||||
|
||||
/// Describes the nullability of a particular type.
|
||||
enum class NullabilityKind : uint8_t {
|
||||
/// Values of this type can never be null.
|
||||
NonNull = 0,
|
||||
/// Values of this type can be null.
|
||||
Nullable,
|
||||
/// Whether values of this type can be null is (explicitly)
|
||||
/// unspecified. This captures a (fairly rare) case where we
|
||||
/// can't conclude anything about the nullability of the type even
|
||||
/// though it has been considered.
|
||||
Unspecified
|
||||
};
|
||||
|
||||
/// Retrieve the spelling of the given nullability kind.
|
||||
llvm::StringRef getNullabilitySpelling(NullabilityKind kind);
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_BASIC_SPECIFIERS_H
|
||||
|
@ -77,7 +77,9 @@ def CompoundLiteralExpr : DStmt<Expr>;
|
||||
def ExtVectorElementExpr : DStmt<Expr>;
|
||||
def InitListExpr : DStmt<Expr>;
|
||||
def DesignatedInitExpr : DStmt<Expr>;
|
||||
def DesignatedInitUpdateExpr : DStmt<Expr>;
|
||||
def ImplicitValueInitExpr : DStmt<Expr>;
|
||||
def NoInitExpr : DStmt<Expr>;
|
||||
def ParenListExpr : DStmt<Expr>;
|
||||
def VAArgExpr : DStmt<Expr>;
|
||||
def GenericSelectionExpr : DStmt<Expr>;
|
||||
@ -197,6 +199,7 @@ def OMPTaskDirective : DStmt<OMPExecutableDirective>;
|
||||
def OMPTaskyieldDirective : DStmt<OMPExecutableDirective>;
|
||||
def OMPBarrierDirective : DStmt<OMPExecutableDirective>;
|
||||
def OMPTaskwaitDirective : DStmt<OMPExecutableDirective>;
|
||||
def OMPTaskgroupDirective : DStmt<OMPExecutableDirective>;
|
||||
def OMPFlushDirective : DStmt<OMPExecutableDirective>;
|
||||
def OMPOrderedDirective : DStmt<OMPExecutableDirective>;
|
||||
def OMPAtomicDirective : DStmt<OMPExecutableDirective>;
|
||||
|
@ -73,12 +73,12 @@ namespace clang {
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief R600 builtins
|
||||
namespace R600 {
|
||||
/// \brief AMDGPU builtins
|
||||
namespace AMDGPU {
|
||||
enum {
|
||||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "clang/Basic/BuiltinsR600.def"
|
||||
#include "clang/Basic/BuiltinsAMDGPU.def"
|
||||
LastTSBuiltin
|
||||
};
|
||||
}
|
||||
|
@ -363,6 +363,10 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
return *LongDoubleFormat;
|
||||
}
|
||||
|
||||
/// \brief Return true if the 'long double' type should be mangled like
|
||||
/// __float128.
|
||||
virtual bool useFloat128ManglingForLongDouble() const { return false; }
|
||||
|
||||
/// \brief Return the value for the C99 FLT_EVAL_METHOD macro.
|
||||
virtual unsigned getFloatEvalMethod() const { return 0; }
|
||||
|
||||
|
@ -45,6 +45,8 @@ class TargetOptions {
|
||||
/// The list of target specific features to enable or disable -- this should
|
||||
/// be a list of strings starting with by '+' or '-'.
|
||||
std::vector<std::string> Features;
|
||||
|
||||
std::vector<std::string> Reciprocals;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -548,6 +548,11 @@ ALIAS("__typeof__" , typeof , KEYALL)
|
||||
ALIAS("__volatile" , volatile , KEYALL)
|
||||
ALIAS("__volatile__" , volatile , KEYALL)
|
||||
|
||||
// Type nullability.
|
||||
KEYWORD(__nonnull , KEYALL)
|
||||
KEYWORD(__nullable , KEYALL)
|
||||
KEYWORD(__null_unspecified , KEYALL)
|
||||
|
||||
// Microsoft extensions which should be disabled in strict conformance mode
|
||||
KEYWORD(__ptr64 , KEYMS)
|
||||
KEYWORD(__ptr32 , KEYMS)
|
||||
|
@ -802,6 +802,13 @@ def VREINTERPRET
|
||||
|
||||
def VFMA : SInst<"vfma", "dddd", "fQf">;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// fp16 vector operations
|
||||
def SCALAR_HALF_GET_LANE : IOpInst<"vget_lane", "sdi", "h", OP_SCALAR_HALF_GET_LN>;
|
||||
def SCALAR_HALF_SET_LANE : IOpInst<"vset_lane", "dsdi", "h", OP_SCALAR_HALF_SET_LN>;
|
||||
def SCALAR_HALF_GET_LANEQ : IOpInst<"vget_lane", "sdi", "Qh", OP_SCALAR_HALF_GET_LNQ>;
|
||||
def SCALAR_HALF_SET_LANEQ : IOpInst<"vset_lane", "dsdi", "Qh", OP_SCALAR_HALF_SET_LNQ>;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// AArch64 Intrinsics
|
||||
|
||||
@ -1594,10 +1601,4 @@ def SCALAR_SQRDMULH_LANEQ : SOpInst<"vqrdmulh_laneq", "ssji", "SsSi", OP_SCALAR_
|
||||
|
||||
def SCALAR_VDUP_LANE : IInst<"vdup_lane", "sdi", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
|
||||
def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "sji", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
|
||||
|
||||
// FIXME: Rename so it is obvious this only applies to halfs.
|
||||
def SCALAR_HALF_GET_LANE : IOpInst<"vget_lane", "sdi", "h", OP_SCALAR_HALF_GET_LN>;
|
||||
def SCALAR_HALF_SET_LANE : IOpInst<"vset_lane", "dsdi", "h", OP_SCALAR_HALF_SET_LN>;
|
||||
def SCALAR_HALF_GET_LANEQ : IOpInst<"vget_lane", "sdi", "Qh", OP_SCALAR_HALF_GET_LNQ>;
|
||||
def SCALAR_HALF_SET_LANEQ : IOpInst<"vset_lane", "dsdi", "Qh", OP_SCALAR_HALF_SET_LNQ>;
|
||||
}
|
||||
|
@ -301,6 +301,10 @@ def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
|
||||
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
|
||||
def verify : Flag<["-"], "verify">,
|
||||
HelpText<"Verify diagnostic output using comment directives">;
|
||||
def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">,
|
||||
HelpText<"Ignore unexpected diagnostic messages">;
|
||||
def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">,
|
||||
HelpText<"Ignore unexpected diagnostic messages">;
|
||||
def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">,
|
||||
HelpText<"Silence ObjC rewriting warnings">;
|
||||
|
||||
|
@ -139,6 +139,8 @@ def _SLASH_wd4005 : CLFlag<"wd4005">, Alias<W_Joined>,
|
||||
AliasArgs<["no-macro-redefined"]>;
|
||||
def _SLASH_wd4996 : CLFlag<"wd4996">, Alias<W_Joined>,
|
||||
AliasArgs<["no-deprecated-declarations"]>;
|
||||
def _SLASH_wd4910 : CLFlag<"wd4910">, Alias<W_Joined>,
|
||||
AliasArgs<["no-dllexport-explicit-instantiation-decl"]>;
|
||||
def _SLASH_vd : CLJoined<"vd">, HelpText<"Control vtordisp placement">,
|
||||
Alias<vtordisp_mode_EQ>;
|
||||
def _SLASH_Zc_sizedDealloc : CLFlag<"Zc:sizedDealloc">,
|
||||
@ -202,7 +204,6 @@ def _SLASH_Fi : CLCompileJoined<"Fi">,
|
||||
def _SLASH_Fo : CLCompileJoined<"Fo">,
|
||||
HelpText<"Set output object file, or directory (ends in / or \\)">,
|
||||
MetaVarName<"<file or directory>">;
|
||||
def _SLASH_GL : CLFlag<"GL">, Alias<flto>;
|
||||
def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">;
|
||||
def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">;
|
||||
def _SLASH_link : CLRemainingArgs<"link">,
|
||||
@ -287,6 +288,7 @@ def _SLASH_G2 : CLFlag<"G2">;
|
||||
def _SLASH_Ge : CLFlag<"Ge">;
|
||||
def _SLASH_Gh : CLFlag<"Gh">;
|
||||
def _SLASH_GH : CLFlag<"GH">;
|
||||
def _SLASH_GL : CLFlag<"GL">;
|
||||
def _SLASH_GL_ : CLFlag<"GL-">;
|
||||
def _SLASH_Gm : CLFlag<"Gm">;
|
||||
def _SLASH_Gm_ : CLFlag<"Gm-">;
|
||||
|
@ -91,7 +91,7 @@ class Driver {
|
||||
/// The path to the compiler resource directory.
|
||||
std::string ResourceDir;
|
||||
|
||||
/// A prefix directory used to emulated a limited subset of GCC's '-Bprefix'
|
||||
/// A prefix directory used to emulate a limited subset of GCC's '-Bprefix'
|
||||
/// functionality.
|
||||
/// FIXME: This type of customization should be removed in favor of the
|
||||
/// universal driver when it is ready.
|
||||
@ -402,7 +402,7 @@ class Driver {
|
||||
/// handle this action.
|
||||
bool ShouldUseClangCompiler(const JobAction &JA) const;
|
||||
|
||||
bool IsUsingLTO(const ToolChain &TC, const llvm::opt::ArgList &Args) const;
|
||||
bool IsUsingLTO(const llvm::opt::ArgList &Args) const;
|
||||
|
||||
private:
|
||||
/// \brief Retrieves a ToolChain for a particular target triple.
|
||||
|
@ -561,8 +561,13 @@ def fno_sanitize_recover_EQ
|
||||
: CommaJoined<["-"], "fno-sanitize-recover=">,
|
||||
Group<f_clang_Group>,
|
||||
HelpText<"Disable recovery for specified sanitizers">;
|
||||
def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Group>,
|
||||
Flags<[CC1Option, CoreOption]>,
|
||||
HelpText<"Enable trapping for specified sanitizers">;
|
||||
def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
|
||||
HelpText<"Disable trapping for specified sanitizers">;
|
||||
def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>;
|
||||
Group<f_clang_Group>;
|
||||
def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">,
|
||||
Group<f_clang_Group>;
|
||||
def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">,
|
||||
@ -691,9 +696,10 @@ def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-hea
|
||||
def fmodules : Flag <["-"], "fmodules">, Group<f_Group>,
|
||||
Flags<[DriverOption, CC1Option]>,
|
||||
HelpText<"Enable the 'modules' language feature">;
|
||||
def fmodule_maps : Flag <["-"], "fmodule-maps">, Group<f_Group>,
|
||||
Flags<[DriverOption,CC1Option]>,
|
||||
HelpText<"Read module maps to understand the structure of library headers">;
|
||||
def fimplicit_module_maps : Flag <["-"], "fimplicit-module-maps">, Group<f_Group>,
|
||||
Flags<[DriverOption, CC1Option]>,
|
||||
HelpText<"Implicitly search the file system for module map files.">;
|
||||
def fmodule_maps : Flag <["-"], "fmodule-maps">, Alias<fimplicit_module_maps>;
|
||||
def fmodule_name : JoinedOrSeparate<["-"], "fmodule-name=">, Group<f_Group>,
|
||||
Flags<[DriverOption,CC1Option]>, MetaVarName<"<name>">,
|
||||
HelpText<"Specify the name of the module to build">;
|
||||
@ -713,12 +719,6 @@ def fmodules_strict_decluse : Flag <["-"], "fmodules-strict-decluse">, Group<f_G
|
||||
HelpText<"Like -fmodules-decluse but requires all headers to be in modules">;
|
||||
def fno_modules_search_all : Flag <["-"], "fno-modules-search-all">, Group<f_Group>,
|
||||
Flags<[DriverOption, CC1Option]>;
|
||||
def fmodules_implicit_maps :
|
||||
Flag <["-"], "fmodules-implicit-maps">,
|
||||
Group<f_Group>, Flags<[DriverOption, CC1Option]>;
|
||||
def fno_modules_implicit_maps :
|
||||
Flag <["-"], "fno-modules-implicit-maps">,
|
||||
Group<f_Group>, Flags<[DriverOption, CC1Option]>;
|
||||
def fno_implicit_modules :
|
||||
Flag <["-"], "fno-implicit-modules">,
|
||||
Group<f_Group>, Flags<[DriverOption, CC1Option]>;
|
||||
@ -780,8 +780,9 @@ def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Gr
|
||||
Flags<[CC1Option]>, HelpText<"Disallow merging of constants">;
|
||||
def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>,
|
||||
Flags<[DriverOption]>;
|
||||
def fno_module_maps : Flag <["-"], "fno-module-maps">, Group<f_Group>,
|
||||
def fno_implicit_module_maps : Flag <["-"], "fno-implicit-module-maps">, Group<f_Group>,
|
||||
Flags<[DriverOption]>;
|
||||
def fno_module_maps : Flag <["-"], "fno-module-maps">, Alias<fno_implicit_module_maps>;
|
||||
def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group<f_Group>,
|
||||
Flags<[DriverOption]>;
|
||||
def fno_modules_strict_decluse : Flag <["-"], "fno-strict-modules-decluse">, Group<f_Group>,
|
||||
@ -1338,6 +1339,8 @@ def msoft_float : Flag<["-"], "msoft-float">, Group<m_Group>, Flags<[CC1Option]>
|
||||
def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
|
||||
HelpText<"Don't generate implicit floating point instructions">;
|
||||
def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>;
|
||||
def mrecip : Flag<["-"], "mrecip">, Group<m_Group>;
|
||||
def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group<m_Group>, Flags<[CC1Option]>;
|
||||
def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>;
|
||||
def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>;
|
||||
def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>;
|
||||
|
@ -23,13 +23,13 @@ class ToolChain;
|
||||
class SanitizerArgs {
|
||||
SanitizerSet Sanitizers;
|
||||
SanitizerSet RecoverableSanitizers;
|
||||
SanitizerSet TrapSanitizers;
|
||||
|
||||
std::vector<std::string> BlacklistFiles;
|
||||
int CoverageFeatures;
|
||||
int MsanTrackOrigins;
|
||||
int AsanFieldPadding;
|
||||
bool AsanZeroBaseShadow;
|
||||
bool UbsanTrapOnError;
|
||||
bool AsanSharedRuntime;
|
||||
bool LinkCXXRuntimes;
|
||||
|
||||
@ -47,10 +47,12 @@ class SanitizerArgs {
|
||||
}
|
||||
bool needsUbsanRt() const;
|
||||
bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); }
|
||||
bool needsSafeStackRt() const {
|
||||
return Sanitizers.has(SanitizerKind::SafeStack);
|
||||
}
|
||||
|
||||
bool requiresPIE() const;
|
||||
bool needsUnwindTables() const;
|
||||
bool needsLTO() const;
|
||||
bool linkCXXRuntimes() const { return LinkCXXRuntimes; }
|
||||
void addArgs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef LLVM_CLANG_DRIVER_TOOLCHAIN_H
|
||||
#define LLVM_CLANG_DRIVER_TOOLCHAIN_H
|
||||
|
||||
#include "clang/Basic/Sanitizers.h"
|
||||
#include "clang/Driver/Action.h"
|
||||
#include "clang/Driver/Multilib.h"
|
||||
#include "clang/Driver/Types.h"
|
||||
@ -164,7 +165,10 @@ class ToolChain {
|
||||
}
|
||||
|
||||
/// Choose a tool to use to handle the action \p JA.
|
||||
Tool *SelectTool(const JobAction &JA) const;
|
||||
///
|
||||
/// This can be overridden when a particular ToolChain needs to use
|
||||
/// a C compiler other than Clang.
|
||||
virtual Tool *SelectTool(const JobAction &JA) const;
|
||||
|
||||
// Helper methods
|
||||
|
||||
@ -345,6 +349,9 @@ class ToolChain {
|
||||
virtual bool
|
||||
AddFastMathRuntimeIfAvailable(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const;
|
||||
|
||||
/// \brief Return sanitizers which are available in this toolchain.
|
||||
virtual SanitizerMask getSupportedSanitizers() const;
|
||||
};
|
||||
|
||||
} // end namespace driver
|
||||
|
@ -210,10 +210,10 @@ struct FormatStyle {
|
||||
enum ShortFunctionStyle {
|
||||
/// \brief Never merge functions into a single line.
|
||||
SFS_None,
|
||||
/// \brief Only merge functions defined inside a class.
|
||||
SFS_Inline,
|
||||
/// \brief Only merge empty functions.
|
||||
SFS_Empty,
|
||||
/// \brief Only merge functions defined inside a class. Implies "empty".
|
||||
SFS_Inline,
|
||||
/// \brief Merge all functions fitting on a single line.
|
||||
SFS_All,
|
||||
};
|
||||
@ -287,6 +287,11 @@ struct FormatStyle {
|
||||
bool AlwaysBreakTemplateDeclarations;
|
||||
|
||||
/// \brief If \c true, always break before multiline string literals.
|
||||
///
|
||||
/// This flag is mean to make cases where there are multiple multiline strings
|
||||
/// in a file look more consistent. Thus, it will only take effect if wrapping
|
||||
/// the string at that point leads to it being indented
|
||||
/// \c ContinuationIndentWidth spaces from the start of the line.
|
||||
bool AlwaysBreakBeforeMultilineStrings;
|
||||
|
||||
/// \brief Different ways to use tab in formatting.
|
||||
|
@ -56,6 +56,7 @@ class FileEntry;
|
||||
class FileManager;
|
||||
class HeaderSearch;
|
||||
class Preprocessor;
|
||||
class PCHContainerOperations;
|
||||
class SourceManager;
|
||||
class TargetInfo;
|
||||
class ASTFrontendAction;
|
||||
@ -422,7 +423,8 @@ class ASTUnit : public ModuleLoader {
|
||||
explicit ASTUnit(bool MainFileIsAST);
|
||||
|
||||
void CleanTemporaryFiles();
|
||||
bool Parse(std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
|
||||
bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
|
||||
|
||||
struct ComputedPreamble {
|
||||
llvm::MemoryBuffer *Buffer;
|
||||
@ -442,6 +444,7 @@ class ASTUnit : public ModuleLoader {
|
||||
unsigned MaxLines);
|
||||
|
||||
std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true,
|
||||
unsigned MaxLines = 0);
|
||||
void RealizeTopLevelDeclsFromPreamble();
|
||||
@ -715,12 +718,16 @@ class ASTUnit : public ModuleLoader {
|
||||
///
|
||||
/// \param Filename - The AST file to load.
|
||||
///
|
||||
/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
|
||||
/// creating modules.
|
||||
/// \param Diags - The diagnostics engine to use for reporting errors; its
|
||||
/// lifetime is expected to extend past that of the returned ASTUnit.
|
||||
///
|
||||
/// \returns - The initialized ASTUnit or null if the AST failed to load.
|
||||
static std::unique_ptr<ASTUnit> LoadFromASTFile(
|
||||
const std::string &Filename, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
||||
const std::string &Filename,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
||||
const FileSystemOptions &FileSystemOpts, bool OnlyLocalDecls = false,
|
||||
ArrayRef<RemappedFile> RemappedFiles = None,
|
||||
bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false,
|
||||
@ -735,8 +742,10 @@ class ASTUnit : public ModuleLoader {
|
||||
///
|
||||
/// \returns \c true if a catastrophic failure occurred (which means that the
|
||||
/// \c ASTUnit itself is invalid), or \c false otherwise.
|
||||
bool LoadFromCompilerInvocation(bool PrecompilePreamble);
|
||||
|
||||
bool LoadFromCompilerInvocation(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
bool PrecompilePreamble);
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Create an ASTUnit from a source file, via a CompilerInvocation
|
||||
@ -745,6 +754,9 @@ class ASTUnit : public ModuleLoader {
|
||||
/// \param CI - The compiler invocation to use; it must have exactly one input
|
||||
/// source file. The ASTUnit takes ownership of the CompilerInvocation object.
|
||||
///
|
||||
/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
|
||||
/// creating modules.
|
||||
///
|
||||
/// \param Diags - The diagnostics engine to use for reporting errors; its
|
||||
/// lifetime is expected to extend past that of the returned ASTUnit.
|
||||
///
|
||||
@ -765,7 +777,9 @@ class ASTUnit : public ModuleLoader {
|
||||
/// created ASTUnit was passed in \p Unit then the caller can check that.
|
||||
///
|
||||
static ASTUnit *LoadFromCompilerInvocationAction(
|
||||
CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
||||
CompilerInvocation *CI,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
||||
ASTFrontendAction *Action = nullptr, ASTUnit *Unit = nullptr,
|
||||
bool Persistent = true, StringRef ResourceFilesPath = StringRef(),
|
||||
bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
|
||||
@ -780,15 +794,20 @@ class ASTUnit : public ModuleLoader {
|
||||
/// \param CI - The compiler invocation to use; it must have exactly one input
|
||||
/// source file. The ASTUnit takes ownership of the CompilerInvocation object.
|
||||
///
|
||||
/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
|
||||
/// creating modules.
|
||||
///
|
||||
/// \param Diags - The diagnostics engine to use for reporting errors; its
|
||||
/// lifetime is expected to extend past that of the returned ASTUnit.
|
||||
//
|
||||
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
|
||||
// shouldn't need to specify them at construction time.
|
||||
static std::unique_ptr<ASTUnit> LoadFromCompilerInvocation(
|
||||
CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
||||
bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
|
||||
bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete,
|
||||
CompilerInvocation *CI,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, bool OnlyLocalDecls = false,
|
||||
bool CaptureDiagnostics = false, bool PrecompilePreamble = false,
|
||||
TranslationUnitKind TUKind = TU_Complete,
|
||||
bool CacheCodeCompletionResults = false,
|
||||
bool IncludeBriefCommentsInCodeCompletion = false,
|
||||
bool UserFilesAreVolatile = false);
|
||||
@ -800,6 +819,9 @@ class ASTUnit : public ModuleLoader {
|
||||
///
|
||||
/// \param ArgEnd - The end of the argument vector.
|
||||
///
|
||||
/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
|
||||
/// creating modules.
|
||||
///
|
||||
/// \param Diags - The diagnostics engine to use for reporting errors; its
|
||||
/// lifetime is expected to extend past that of the returned ASTUnit.
|
||||
///
|
||||
@ -813,6 +835,7 @@ class ASTUnit : public ModuleLoader {
|
||||
// shouldn't need to specify them at construction time.
|
||||
static ASTUnit *LoadFromCommandLine(
|
||||
const char **ArgBegin, const char **ArgEnd,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
|
||||
bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
|
||||
ArrayRef<RemappedFile> RemappedFiles = None,
|
||||
@ -828,8 +851,9 @@ class ASTUnit : public ModuleLoader {
|
||||
/// were originally used to produce this translation unit.
|
||||
///
|
||||
/// \returns True if a failure occurred that causes the ASTUnit not to
|
||||
/// contain any translation-unit information, false otherwise.
|
||||
bool Reparse(ArrayRef<RemappedFile> RemappedFiles = None);
|
||||
/// contain any translation-unit information, false otherwise.
|
||||
bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
ArrayRef<RemappedFile> RemappedFiles = None);
|
||||
|
||||
/// \brief Perform code completion at the given file, line, and
|
||||
/// column within this translation unit.
|
||||
@ -852,14 +876,14 @@ class ASTUnit : public ModuleLoader {
|
||||
/// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and
|
||||
/// OwnedBuffers parameters are all disgusting hacks. They will go away.
|
||||
void CodeComplete(StringRef File, unsigned Line, unsigned Column,
|
||||
ArrayRef<RemappedFile> RemappedFiles,
|
||||
bool IncludeMacros, bool IncludeCodePatterns,
|
||||
bool IncludeBriefComments,
|
||||
ArrayRef<RemappedFile> RemappedFiles, bool IncludeMacros,
|
||||
bool IncludeCodePatterns, bool IncludeBriefComments,
|
||||
CodeCompleteConsumer &Consumer,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticsEngine &Diag, LangOptions &LangOpts,
|
||||
SourceManager &SourceMgr, FileManager &FileMgr,
|
||||
SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
|
||||
SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers);
|
||||
SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers);
|
||||
|
||||
/// \brief Save this translation unit to a file with the given name.
|
||||
///
|
||||
|
@ -120,8 +120,6 @@ CODEGENOPT(SanitizeCoverageTraceCmp, 1, 0) ///< Enable cmp instruction tracing
|
||||
///< in sanitizer coverage.
|
||||
CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters
|
||||
///< in sanitizer coverage.
|
||||
CODEGENOPT(SanitizeUndefinedTrapOnError, 1, 0) ///< Set on
|
||||
/// -fsanitize-undefined-trap-on-error
|
||||
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
|
||||
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
|
||||
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
|
||||
|
@ -197,6 +197,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
|
||||
/// continued when possible).
|
||||
SanitizerSet SanitizeRecover;
|
||||
|
||||
/// Set of sanitizer checks that trap rather than diagnose.
|
||||
SanitizerSet SanitizeTrap;
|
||||
|
||||
public:
|
||||
// Define accessors/mutators for code generation options of enumeration type.
|
||||
#define CODEGENOPT(Name, Bits, Default)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Frontend/PCHContainerOperations.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
@ -109,6 +110,9 @@ class CompilerInstance : public ModuleLoader {
|
||||
/// \brief The module dependency collector for crashdumps
|
||||
std::shared_ptr<ModuleDependencyCollector> ModuleDepCollector;
|
||||
|
||||
/// \brief The module provider.
|
||||
std::shared_ptr<PCHContainerOperations> ThePCHContainerOperations;
|
||||
|
||||
/// \brief The dependency file generator.
|
||||
std::unique_ptr<DependencyFileGenerator> TheDependencyFileGenerator;
|
||||
|
||||
@ -172,7 +176,10 @@ class CompilerInstance : public ModuleLoader {
|
||||
CompilerInstance(const CompilerInstance &) = delete;
|
||||
void operator=(const CompilerInstance &) = delete;
|
||||
public:
|
||||
explicit CompilerInstance(bool BuildingModule = false);
|
||||
explicit CompilerInstance(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>(),
|
||||
bool BuildingModule = false);
|
||||
~CompilerInstance() override;
|
||||
|
||||
/// @name High-Level Operations
|
||||
@ -492,6 +499,10 @@ class CompilerInstance : public ModuleLoader {
|
||||
void setModuleDepCollector(
|
||||
std::shared_ptr<ModuleDependencyCollector> Collector);
|
||||
|
||||
std::shared_ptr<PCHContainerOperations> getPCHContainerOperations() const {
|
||||
return ThePCHContainerOperations;
|
||||
}
|
||||
|
||||
/// }
|
||||
/// @name Code Completion
|
||||
/// {
|
||||
@ -605,6 +616,7 @@ class CompilerInstance : public ModuleLoader {
|
||||
static IntrusiveRefCntPtr<ASTReader> createPCHExternalASTSource(
|
||||
StringRef Path, const std::string &Sysroot, bool DisablePCHValidation,
|
||||
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
void *DeserializationListener, bool OwnDeserializationListener,
|
||||
bool Preamble, bool UseGlobalModuleIndex);
|
||||
|
||||
|
@ -85,10 +85,9 @@ class GeneratePCHAction : public ASTFrontendAction {
|
||||
/// create the PCHGenerator instance returned by CreateASTConsumer.
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
static raw_ostream *ComputeASTConsumerArguments(CompilerInstance &CI,
|
||||
StringRef InFile,
|
||||
std::string &Sysroot,
|
||||
std::string &OutputFile);
|
||||
static raw_pwrite_stream *
|
||||
ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile,
|
||||
std::string &Sysroot, std::string &OutputFile);
|
||||
};
|
||||
|
||||
class GenerateModuleAction : public ASTFrontendAction {
|
||||
@ -118,10 +117,10 @@ class GenerateModuleAction : public ASTFrontendAction {
|
||||
/// create the PCHGenerator instance returned by CreateASTConsumer.
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
raw_ostream *ComputeASTConsumerArguments(CompilerInstance &CI,
|
||||
StringRef InFile,
|
||||
std::string &Sysroot,
|
||||
std::string &OutputFile);
|
||||
raw_pwrite_stream *ComputeASTConsumerArguments(CompilerInstance &CI,
|
||||
StringRef InFile,
|
||||
std::string &Sysroot,
|
||||
std::string &OutputFile);
|
||||
};
|
||||
|
||||
class SyntaxOnlyAction : public ASTFrontendAction {
|
||||
|
76
include/clang/Frontend/PCHContainerOperations.h
Normal file
76
include/clang/Frontend/PCHContainerOperations.h
Normal file
@ -0,0 +1,76 @@
|
||||
//===--- Frontend/PCHContainerOperations.h - PCH Containers -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_PCH_CONTAINER_OPERATIONS_H
|
||||
#define LLVM_CLANG_PCH_CONTAINER_OPERATIONS_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
class raw_pwrite_stream;
|
||||
class BitstreamReader;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTConsumer;
|
||||
class CodeGenOptions;
|
||||
class DiagnosticsEngine;
|
||||
class HeaderSearchOptions;
|
||||
class LangOptions;
|
||||
class PreprocessorOptions;
|
||||
class TargetOptions;
|
||||
|
||||
struct PCHBuffer {
|
||||
bool IsComplete;
|
||||
llvm::SmallVector<char, 0> Data;
|
||||
};
|
||||
|
||||
/// \brief This abstract interface provides operations for creating
|
||||
/// and unwrapping containers for serialized ASTs (precompiled headers
|
||||
/// and clang modules).
|
||||
class PCHContainerOperations {
|
||||
public:
|
||||
virtual ~PCHContainerOperations();
|
||||
/// \brief Return an ASTConsumer that can be chained with a
|
||||
/// PCHGenerator that produces a wrapper file format containing a
|
||||
/// serialized AST bitstream.
|
||||
virtual std::unique_ptr<ASTConsumer> CreatePCHContainerGenerator(
|
||||
DiagnosticsEngine &Diags, const HeaderSearchOptions &HSO,
|
||||
const PreprocessorOptions &PPO, const TargetOptions &TO,
|
||||
const LangOptions &LO, const std::string &MainFileName,
|
||||
const std::string &OutputFileName, llvm::raw_pwrite_stream *OS,
|
||||
std::shared_ptr<PCHBuffer> Buffer) const = 0;
|
||||
|
||||
/// \brief Initialize an llvm::BitstreamReader with the serialized AST inside
|
||||
/// the PCH container Buffer.
|
||||
virtual void ExtractPCH(llvm::MemoryBufferRef Buffer,
|
||||
llvm::BitstreamReader &StreamFile) const = 0;
|
||||
};
|
||||
|
||||
/// \brief Implements a raw pass-through PCH container.
|
||||
class RawPCHContainerOperations : public PCHContainerOperations {
|
||||
/// \brief Return an ASTConsumer that can be chained with a
|
||||
/// PCHGenerator that writes the module to a flat file.
|
||||
std::unique_ptr<ASTConsumer> CreatePCHContainerGenerator(
|
||||
DiagnosticsEngine &Diags, const HeaderSearchOptions &HSO,
|
||||
const PreprocessorOptions &PPO, const TargetOptions &TO,
|
||||
const LangOptions &LO, const std::string &MainFileName,
|
||||
const std::string &OutputFileName, llvm::raw_pwrite_stream *OS,
|
||||
std::shared_ptr<PCHBuffer> Buffer) const override;
|
||||
|
||||
/// \brief Initialize an llvm::BitstreamReader with Buffer.
|
||||
void ExtractPCH(llvm::MemoryBufferRef Buffer,
|
||||
llvm::BitstreamReader &StreamFile) const override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -45,6 +45,7 @@ class HeaderSearch;
|
||||
class HeaderSearchOptions;
|
||||
class IdentifierTable;
|
||||
class LangOptions;
|
||||
class PCHContainerOperations;
|
||||
class Preprocessor;
|
||||
class PreprocessorOptions;
|
||||
class PreprocessorOutputOptions;
|
||||
@ -61,8 +62,8 @@ void ApplyHeaderSearchOptions(HeaderSearch &HS,
|
||||
|
||||
/// InitializePreprocessor - Initialize the preprocessor getting it and the
|
||||
/// environment ready to process a single file.
|
||||
void InitializePreprocessor(Preprocessor &PP,
|
||||
const PreprocessorOptions &PPOpts,
|
||||
void InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &PPOpts,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
const FrontendOptions &FEOpts);
|
||||
|
||||
/// DoPrintPreprocessedInput - Implement -E mode.
|
||||
|
@ -98,8 +98,9 @@ class HeaderSearchOptions : public RefCountedBase<HeaderSearchOptions> {
|
||||
/// Note: Only used for testing!
|
||||
unsigned DisableModuleHash : 1;
|
||||
|
||||
/// \brief Interpret module maps. This option is implied by full modules.
|
||||
unsigned ModuleMaps : 1;
|
||||
/// \brief Implicit module maps. This option is enabld by default when
|
||||
/// modules is enabled.
|
||||
unsigned ImplicitModuleMaps : 1;
|
||||
|
||||
/// \brief Set the 'home directory' of a module map file to the current
|
||||
/// working directory (or the home directory of the module map file that
|
||||
@ -166,7 +167,7 @@ class HeaderSearchOptions : public RefCountedBase<HeaderSearchOptions> {
|
||||
|
||||
public:
|
||||
HeaderSearchOptions(StringRef _Sysroot = "/")
|
||||
: Sysroot(_Sysroot), DisableModuleHash(0), ModuleMaps(0),
|
||||
: Sysroot(_Sysroot), DisableModuleHash(0), ImplicitModuleMaps(0),
|
||||
ModuleMapFileHomeIsCwd(0),
|
||||
ModuleCachePruneInterval(7*24*60*60),
|
||||
ModuleCachePruneAfter(31*24*60*60),
|
||||
|
@ -268,15 +268,10 @@ class ModuleMap {
|
||||
///
|
||||
/// \param File The header file that is likely to be included.
|
||||
///
|
||||
/// \param RequestingModule Specifies the module the header is intended to be
|
||||
/// used from. Used to disambiguate if a header is present in multiple
|
||||
/// modules.
|
||||
///
|
||||
/// \returns The module KnownHeader, which provides the module that owns the
|
||||
/// given header file. The KnownHeader is default constructed to indicate
|
||||
/// that no module owns this header file.
|
||||
KnownHeader findModuleForHeader(const FileEntry *File,
|
||||
Module *RequestingModule = nullptr);
|
||||
KnownHeader findModuleForHeader(const FileEntry *File);
|
||||
|
||||
/// \brief Reports errors if a module must not include a specific file.
|
||||
///
|
||||
|
@ -256,6 +256,10 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
|
||||
/// \#pragma clang arc_cf_code_audited begin.
|
||||
SourceLocation PragmaARCCFCodeAuditedLoc;
|
||||
|
||||
/// \brief The source location of the currently-active
|
||||
/// \#pragma clang assume_nonnull begin.
|
||||
SourceLocation PragmaAssumeNonNullLoc;
|
||||
|
||||
/// \brief True if we hit the code-completion point.
|
||||
bool CodeCompletionReached;
|
||||
|
||||
@ -455,8 +459,9 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
|
||||
|
||||
void overrideActiveModuleMacros(Preprocessor &PP, IdentifierInfo *II) {
|
||||
if (auto *Info = getModuleInfo(PP, II)) {
|
||||
for (auto *Active : Info->ActiveModuleMacros)
|
||||
Info->OverriddenMacros.push_back(Active);
|
||||
Info->OverriddenMacros.insert(Info->OverriddenMacros.end(),
|
||||
Info->ActiveModuleMacros.begin(),
|
||||
Info->ActiveModuleMacros.end());
|
||||
Info->ActiveModuleMacros.clear();
|
||||
Info->IsAmbiguous = false;
|
||||
}
|
||||
@ -1249,6 +1254,20 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
|
||||
PragmaARCCFCodeAuditedLoc = Loc;
|
||||
}
|
||||
|
||||
/// \brief The location of the currently-active \#pragma clang
|
||||
/// assume_nonnull begin.
|
||||
///
|
||||
/// Returns an invalid location if there is no such pragma active.
|
||||
SourceLocation getPragmaAssumeNonNullLoc() const {
|
||||
return PragmaAssumeNonNullLoc;
|
||||
}
|
||||
|
||||
/// \brief Set the location of the currently-active \#pragma clang
|
||||
/// assume_nonnull begin. An invalid location ends the pragma.
|
||||
void setPragmaAssumeNonNullLoc(SourceLocation Loc) {
|
||||
PragmaAssumeNonNullLoc = Loc;
|
||||
}
|
||||
|
||||
/// \brief Set the directory in which the main file should be considered
|
||||
/// to have been found, if it is not a real file.
|
||||
void setMainFileDir(const DirectoryEntry *Dir) {
|
||||
|
@ -94,6 +94,13 @@ class Token {
|
||||
/// "if (Tok.is(tok::l_brace)) {...}".
|
||||
bool is(tok::TokenKind K) const { return Kind == K; }
|
||||
bool isNot(tok::TokenKind K) const { return Kind != K; }
|
||||
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
|
||||
return is(K1) || is(K2);
|
||||
}
|
||||
template <typename... Ts>
|
||||
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, Ts... Ks) const {
|
||||
return is(K1) || isOneOf(K2, Ks...);
|
||||
}
|
||||
|
||||
/// \brief Return true if this is a raw identifier (when lexing
|
||||
/// in raw mode) or a non-keyword identifier (when lexing in non-raw mode).
|
||||
|
@ -303,6 +303,12 @@ class Parser : public CodeCompletionHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Retrieve the underscored keyword (__nonnull, __nullable) that corresponds
|
||||
/// to the given nullability kind.
|
||||
IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability) {
|
||||
return Actions.getNullabilityKeyword(nullability);
|
||||
}
|
||||
|
||||
private:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Low-Level token peeking and consumption methods.
|
||||
@ -620,6 +626,16 @@ class Parser : public CodeCompletionHandler {
|
||||
const char *&PrevSpec, unsigned &DiagID,
|
||||
bool &isInvalid);
|
||||
|
||||
/// Returns true if the current token is the identifier 'instancetype'.
|
||||
///
|
||||
/// Should only be used in Objective-C language modes.
|
||||
bool isObjCInstancetype() {
|
||||
assert(getLangOpts().ObjC1);
|
||||
if (!Ident_instancetype)
|
||||
Ident_instancetype = PP.getIdentifierInfo("instancetype");
|
||||
return Tok.getIdentifierInfo() == Ident_instancetype;
|
||||
}
|
||||
|
||||
/// TryKeywordIdentFallback - For compatibility with system headers using
|
||||
/// keywords as identifiers, attempt to convert the current token to an
|
||||
/// identifier and optionally disable the keyword for the remainder of the
|
||||
@ -1282,6 +1298,7 @@ class Parser : public CodeCompletionHandler {
|
||||
// Definitions for Objective-c context sensitive keywords recognition.
|
||||
enum ObjCTypeQual {
|
||||
objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref,
|
||||
objc_nonnull, objc_nullable, objc_null_unspecified,
|
||||
objc_NumQuals
|
||||
};
|
||||
IdentifierInfo *ObjCTypeQuals[objc_NumQuals];
|
||||
@ -1685,7 +1702,8 @@ class Parser : public CodeCompletionHandler {
|
||||
DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
|
||||
DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
|
||||
DSC_top_level, // top-level/namespace declaration context
|
||||
DSC_template_type_arg // template type argument context
|
||||
DSC_template_type_arg, // template type argument context
|
||||
DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
|
||||
};
|
||||
|
||||
/// Is this a context in which we are parsing just a type-specifier (or
|
||||
@ -1695,6 +1713,7 @@ class Parser : public CodeCompletionHandler {
|
||||
case DSC_normal:
|
||||
case DSC_class:
|
||||
case DSC_top_level:
|
||||
case DSC_objc_method_result:
|
||||
return false;
|
||||
|
||||
case DSC_template_type_arg:
|
||||
@ -2106,6 +2125,7 @@ class Parser : public CodeCompletionHandler {
|
||||
void ParseBorlandTypeAttributes(ParsedAttributes &attrs);
|
||||
void ParseOpenCLAttributes(ParsedAttributes &attrs);
|
||||
void ParseOpenCLQualifiers(ParsedAttributes &Attrs);
|
||||
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
|
||||
|
||||
VersionTuple ParseVersionTuple(SourceRange &Range);
|
||||
void ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
||||
|
@ -27,7 +27,7 @@ class FileEntry;
|
||||
|
||||
class FixItOptions {
|
||||
public:
|
||||
FixItOptions() : FixWhatYouCan(false),
|
||||
FixItOptions() : InPlace(false), FixWhatYouCan(false),
|
||||
FixOnlyWarnings(false), Silent(false) { }
|
||||
|
||||
virtual ~FixItOptions();
|
||||
@ -41,6 +41,10 @@ class FixItOptions {
|
||||
///
|
||||
virtual std::string RewriteFilename(const std::string &Filename, int &fd) = 0;
|
||||
|
||||
/// True if files should be updated in place. RewriteFilename is only called
|
||||
/// if this is false.
|
||||
bool InPlace;
|
||||
|
||||
/// \brief Whether to abort fixing a file when not all errors could be fixed.
|
||||
bool FixWhatYouCan;
|
||||
|
||||
|
@ -81,6 +81,8 @@ class AttributeList { // TODO: This should really be called ParsedAttribute
|
||||
AS_Declspec,
|
||||
/// __ptr16, alignas(...), etc.
|
||||
AS_Keyword,
|
||||
/// Context-sensitive version of a keyword attribute.
|
||||
AS_ContextSensitiveKeyword,
|
||||
/// #pragma ...
|
||||
AS_Pragma
|
||||
};
|
||||
@ -343,14 +345,20 @@ class AttributeList { // TODO: This should really be called ParsedAttribute
|
||||
|
||||
bool isAlignasAttribute() const {
|
||||
// FIXME: Use a better mechanism to determine this.
|
||||
return getKind() == AT_Aligned && SyntaxUsed == AS_Keyword;
|
||||
return getKind() == AT_Aligned && isKeywordAttribute();
|
||||
}
|
||||
|
||||
bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
|
||||
bool isCXX11Attribute() const {
|
||||
return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
|
||||
}
|
||||
bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword; }
|
||||
bool isKeywordAttribute() const {
|
||||
return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
|
||||
}
|
||||
|
||||
bool isContextSensitiveKeywordAttribute() const {
|
||||
return SyntaxUsed == AS_ContextSensitiveKeyword;
|
||||
}
|
||||
|
||||
bool isInvalid() const { return Invalid; }
|
||||
void setInvalid(bool b = true) const { Invalid = b; }
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "clang/Sema/AttributeList.h"
|
||||
#include "clang/Sema/Ownership.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@ -785,7 +786,8 @@ class ObjCDeclSpec {
|
||||
DQ_Out = 0x4,
|
||||
DQ_Bycopy = 0x8,
|
||||
DQ_Byref = 0x10,
|
||||
DQ_Oneway = 0x20
|
||||
DQ_Oneway = 0x20,
|
||||
DQ_CSNullability = 0x40
|
||||
};
|
||||
|
||||
/// PropertyAttributeKind - list of property attributes.
|
||||
@ -802,17 +804,22 @@ class ObjCDeclSpec {
|
||||
DQ_PR_atomic = 0x100,
|
||||
DQ_PR_weak = 0x200,
|
||||
DQ_PR_strong = 0x400,
|
||||
DQ_PR_unsafe_unretained = 0x800
|
||||
DQ_PR_unsafe_unretained = 0x800,
|
||||
DQ_PR_nullability = 0x1000,
|
||||
DQ_PR_null_resettable = 0x2000
|
||||
};
|
||||
|
||||
|
||||
ObjCDeclSpec()
|
||||
: objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr),
|
||||
GetterName(nullptr), SetterName(nullptr) { }
|
||||
Nullability(0), GetterName(nullptr), SetterName(nullptr) { }
|
||||
|
||||
ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; }
|
||||
void setObjCDeclQualifier(ObjCDeclQualifier DQVal) {
|
||||
objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal);
|
||||
}
|
||||
void clearObjCDeclQualifier(ObjCDeclQualifier DQVal) {
|
||||
objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier & ~DQVal);
|
||||
}
|
||||
|
||||
ObjCPropertyAttributeKind getPropertyAttributes() const {
|
||||
return ObjCPropertyAttributeKind(PropertyAttributes);
|
||||
@ -822,6 +829,28 @@ class ObjCDeclSpec {
|
||||
(ObjCPropertyAttributeKind)(PropertyAttributes | PRVal);
|
||||
}
|
||||
|
||||
NullabilityKind getNullability() const {
|
||||
assert(((getObjCDeclQualifier() & DQ_CSNullability) ||
|
||||
(getPropertyAttributes() & DQ_PR_nullability)) &&
|
||||
"Objective-C declspec doesn't have nullability");
|
||||
return static_cast<NullabilityKind>(Nullability);
|
||||
}
|
||||
|
||||
SourceLocation getNullabilityLoc() const {
|
||||
assert(((getObjCDeclQualifier() & DQ_CSNullability) ||
|
||||
(getPropertyAttributes() & DQ_PR_nullability)) &&
|
||||
"Objective-C declspec doesn't have nullability");
|
||||
return NullabilityLoc;
|
||||
}
|
||||
|
||||
void setNullability(SourceLocation loc, NullabilityKind kind) {
|
||||
assert(((getObjCDeclQualifier() & DQ_CSNullability) ||
|
||||
(getPropertyAttributes() & DQ_PR_nullability)) &&
|
||||
"Set the nullability declspec or property attribute first");
|
||||
Nullability = static_cast<unsigned>(kind);
|
||||
NullabilityLoc = loc;
|
||||
}
|
||||
|
||||
const IdentifierInfo *getGetterName() const { return GetterName; }
|
||||
IdentifierInfo *getGetterName() { return GetterName; }
|
||||
void setGetterName(IdentifierInfo *name) { GetterName = name; }
|
||||
@ -834,10 +863,15 @@ class ObjCDeclSpec {
|
||||
// FIXME: These two are unrelated and mutually exclusive. So perhaps
|
||||
// we can put them in a union to reflect their mutual exclusivity
|
||||
// (space saving is negligible).
|
||||
ObjCDeclQualifier objcDeclQualifier : 6;
|
||||
ObjCDeclQualifier objcDeclQualifier : 7;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
|
||||
unsigned PropertyAttributes : 12;
|
||||
unsigned PropertyAttributes : 14;
|
||||
|
||||
unsigned Nullability : 2;
|
||||
|
||||
SourceLocation NullabilityLoc;
|
||||
|
||||
IdentifierInfo *GetterName; // getter name or NULL if no getter
|
||||
IdentifierInfo *SetterName; // setter name or NULL if no setter
|
||||
};
|
||||
@ -1616,7 +1650,13 @@ class Declarator {
|
||||
bool InlineParamsUsed;
|
||||
|
||||
/// \brief true if the declaration is preceded by \c __extension__.
|
||||
bool Extension : 1;
|
||||
unsigned Extension : 1;
|
||||
|
||||
/// Indicates whether this is an Objective-C instance variable.
|
||||
unsigned ObjCIvar : 1;
|
||||
|
||||
/// Indicates whether this is an Objective-C 'weak' property.
|
||||
unsigned ObjCWeakProperty : 1;
|
||||
|
||||
/// \brief If this is the second or subsequent declarator in this declaration,
|
||||
/// the location of the comma before this declarator.
|
||||
@ -1635,7 +1675,8 @@ class Declarator {
|
||||
GroupingParens(false), FunctionDefinition(FDK_Declaration),
|
||||
Redeclaration(false),
|
||||
Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
|
||||
InlineParamsUsed(false), Extension(false) {
|
||||
InlineParamsUsed(false), Extension(false), ObjCIvar(false),
|
||||
ObjCWeakProperty(false) {
|
||||
}
|
||||
|
||||
~Declarator() {
|
||||
@ -1713,6 +1754,8 @@ class Declarator {
|
||||
Attrs.clear();
|
||||
AsmLabel = nullptr;
|
||||
InlineParamsUsed = false;
|
||||
ObjCIvar = false;
|
||||
ObjCWeakProperty = false;
|
||||
CommaLoc = SourceLocation();
|
||||
EllipsisLoc = SourceLocation();
|
||||
}
|
||||
@ -2121,6 +2164,12 @@ class Declarator {
|
||||
void setExtension(bool Val = true) { Extension = Val; }
|
||||
bool getExtension() const { return Extension; }
|
||||
|
||||
void setObjCIvar(bool Val = true) { ObjCIvar = Val; }
|
||||
bool isObjCIvar() const { return ObjCIvar; }
|
||||
|
||||
void setObjCWeakProperty(bool Val = true) { ObjCWeakProperty = Val; }
|
||||
bool isObjCWeakProperty() const { return ObjCWeakProperty; }
|
||||
|
||||
void setInvalidType(bool Val = true) { InvalidType = Val; }
|
||||
bool isInvalidType() const {
|
||||
return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error;
|
||||
|
@ -302,14 +302,10 @@ class LookupResult {
|
||||
if (!D->isInIdentifierNamespace(IDNS))
|
||||
return nullptr;
|
||||
|
||||
if (isVisible(getSema(), D))
|
||||
if (isHiddenDeclarationVisible() || isVisible(getSema(), D))
|
||||
return D;
|
||||
|
||||
if (auto *Visible = getAcceptableDeclSlow(D))
|
||||
return Visible;
|
||||
|
||||
// Even if hidden declarations are visible, prefer a visible declaration.
|
||||
return isHiddenDeclarationVisible() ? D : nullptr;
|
||||
return getAcceptableDeclSlow(D);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -210,6 +210,50 @@ namespace threadSafety {
|
||||
typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
|
||||
SourceLocation> UnexpandedParameterPack;
|
||||
|
||||
/// Describes whether we've seen any nullability information for the given
|
||||
/// file.
|
||||
struct FileNullability {
|
||||
/// The first pointer declarator (of any pointer kind) in the file that does
|
||||
/// not have a corresponding nullability annotation.
|
||||
SourceLocation PointerLoc;
|
||||
|
||||
/// Which kind of pointer declarator we saw.
|
||||
uint8_t PointerKind;
|
||||
|
||||
/// Whether we saw any type nullability annotations in the given file.
|
||||
bool SawTypeNullability = false;
|
||||
};
|
||||
|
||||
/// A mapping from file IDs to a record of whether we've seen nullability
|
||||
/// information in that file.
|
||||
class FileNullabilityMap {
|
||||
/// A mapping from file IDs to the nullability information for each file ID.
|
||||
llvm::DenseMap<FileID, FileNullability> Map;
|
||||
|
||||
/// A single-element cache based on the file ID.
|
||||
struct {
|
||||
FileID File;
|
||||
FileNullability Nullability;
|
||||
} Cache;
|
||||
|
||||
public:
|
||||
FileNullability &operator[](FileID file) {
|
||||
// Check the single-element cache.
|
||||
if (file == Cache.File)
|
||||
return Cache.Nullability;
|
||||
|
||||
// It's not in the single-element cache; flush the cache if we have one.
|
||||
if (!Cache.File.isInvalid()) {
|
||||
Map[Cache.File] = Cache.Nullability;
|
||||
}
|
||||
|
||||
// Pull this entry into the cache.
|
||||
Cache.File = file;
|
||||
Cache.Nullability = Map[file];
|
||||
return Cache.Nullability;
|
||||
}
|
||||
};
|
||||
|
||||
/// Sema - This implements semantic analysis and AST building for C.
|
||||
class Sema {
|
||||
Sema(const Sema &) = delete;
|
||||
@ -341,6 +385,9 @@ class Sema {
|
||||
PragmaStack<StringLiteral *> ConstSegStack;
|
||||
PragmaStack<StringLiteral *> CodeSegStack;
|
||||
|
||||
/// A mapping that describes the nullability we've seen in each header file.
|
||||
FileNullabilityMap NullabilityMap;
|
||||
|
||||
/// Last section used with #pragma init_seg.
|
||||
StringLiteral *CurInitSeg;
|
||||
SourceLocation CurInitSegLoc;
|
||||
@ -1157,6 +1204,16 @@ class Sema {
|
||||
|
||||
bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
|
||||
|
||||
unsigned deduceWeakPropertyFromType(QualType T) {
|
||||
if ((getLangOpts().getGC() != LangOptions::NonGC &&
|
||||
T.isObjCGCWeak()) ||
|
||||
(getLangOpts().ObjCAutoRefCount &&
|
||||
T.getObjCLifetime() == Qualifiers::OCL_Weak))
|
||||
return ObjCDeclSpec::DQ_PR_weak;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Build a function type.
|
||||
///
|
||||
/// This routine checks the function type according to C++ rules and
|
||||
@ -1325,6 +1382,11 @@ class Sema {
|
||||
return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden);
|
||||
}
|
||||
|
||||
/// Determine if the template parameter \p D has a visible default argument.
|
||||
bool
|
||||
hasVisibleDefaultArgument(const NamedDecl *D,
|
||||
llvm::SmallVectorImpl<Module *> *Modules = nullptr);
|
||||
|
||||
bool RequireCompleteType(SourceLocation Loc, QualType T,
|
||||
TypeDiagnoser &Diagnoser);
|
||||
bool RequireCompleteType(SourceLocation Loc, QualType T,
|
||||
@ -1727,6 +1789,22 @@ class Sema {
|
||||
void createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
|
||||
Module *Mod);
|
||||
|
||||
/// Kinds of missing import. Note, the values of these enumerators correspond
|
||||
/// to %select values in diagnostics.
|
||||
enum class MissingImportKind {
|
||||
Declaration,
|
||||
Definition,
|
||||
DefaultArgument
|
||||
};
|
||||
|
||||
/// \brief Diagnose that the specified declaration needs to be visible but
|
||||
/// isn't, and suggest a module import that would resolve the problem.
|
||||
void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
|
||||
bool NeedDefinition, bool Recover = true);
|
||||
void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
|
||||
SourceLocation DeclLoc, ArrayRef<Module *> Modules,
|
||||
MissingImportKind MIK, bool Recover);
|
||||
|
||||
/// \brief Retrieve a suitable printing policy.
|
||||
PrintingPolicy getPrintingPolicy() const {
|
||||
return getPrintingPolicy(Context, PP);
|
||||
@ -1847,10 +1925,10 @@ class Sema {
|
||||
/// struct, or union).
|
||||
void ActOnTagStartDefinition(Scope *S, Decl *TagDecl);
|
||||
|
||||
typedef void *SkippedDefinitionContext;
|
||||
|
||||
/// \brief Invoked when we enter a tag definition that we're skipping.
|
||||
void ActOnTagStartSkippedDefinition(Scope *S, Decl *TD) {
|
||||
PushDeclContext(S, cast<DeclContext>(TD));
|
||||
}
|
||||
SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD);
|
||||
|
||||
Decl *ActOnObjCContainerStartDefinition(Decl *IDecl);
|
||||
|
||||
@ -1867,9 +1945,7 @@ class Sema {
|
||||
void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl,
|
||||
SourceLocation RBraceLoc);
|
||||
|
||||
void ActOnTagFinishSkippedDefinition() {
|
||||
PopDeclContext();
|
||||
}
|
||||
void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context);
|
||||
|
||||
void ActOnObjCContainerFinishDefinition();
|
||||
|
||||
@ -2819,6 +2895,7 @@ class Sema {
|
||||
unsigned ArgNum, StringRef &Str,
|
||||
SourceLocation *ArgLocation = nullptr);
|
||||
bool checkSectionName(SourceLocation LiteralLoc, StringRef Str);
|
||||
void checkTargetAttr(SourceLocation LiteralLoc, StringRef Str);
|
||||
bool checkMSInheritanceAttrOnDefinition(
|
||||
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
|
||||
MSInheritanceAttr::Spelling SemanticSpelling);
|
||||
@ -2839,6 +2916,26 @@ class Sema {
|
||||
/// Valid types should not have multiple attributes with different CCs.
|
||||
const AttributedType *getCallingConvAttributedType(QualType T) const;
|
||||
|
||||
/// Check whether a nullability type specifier can be added to the given
|
||||
/// type.
|
||||
///
|
||||
/// \param type The type to which the nullability specifier will be
|
||||
/// added. On success, this type will be updated appropriately.
|
||||
///
|
||||
/// \param nullability The nullability specifier to add.
|
||||
///
|
||||
/// \param nullabilityLoc The location of the nullability specifier.
|
||||
///
|
||||
/// \param isContextSensitive Whether this nullability specifier was
|
||||
/// written as a context-sensitive keyword (in an Objective-C
|
||||
/// method) or an Objective-C property attribute, rather than as an
|
||||
/// underscored type specifier.
|
||||
///
|
||||
/// \returns true if nullability cannot be applied, false otherwise.
|
||||
bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability,
|
||||
SourceLocation nullabilityLoc,
|
||||
bool isContextSensitive);
|
||||
|
||||
/// \brief Stmt attributes - this routine is the top level dispatcher.
|
||||
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
|
||||
SourceRange Range);
|
||||
@ -2878,6 +2975,9 @@ class Sema {
|
||||
ObjCContainerDecl *CDecl,
|
||||
bool SynthesizeProperties);
|
||||
|
||||
/// Diagnose any null-resettable synthesized setters.
|
||||
void diagnoseNullResettableSynthesizedSetters(ObjCImplDecl *impDecl);
|
||||
|
||||
/// DefaultSynthesizeProperties - This routine default synthesizes all
|
||||
/// properties which must be synthesized in the class's \@implementation.
|
||||
void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
|
||||
@ -2914,7 +3014,8 @@ class Sema {
|
||||
const unsigned Attributes,
|
||||
const unsigned AttributesAsWritten,
|
||||
bool *isOverridingProperty,
|
||||
TypeSourceInfo *T,
|
||||
QualType T,
|
||||
TypeSourceInfo *TSI,
|
||||
tok::ObjCKeywordKind MethodImplKind);
|
||||
|
||||
/// Called by ActOnProperty and HandlePropertyInClassExtension to
|
||||
@ -2930,7 +3031,8 @@ class Sema {
|
||||
const bool isReadWrite,
|
||||
const unsigned Attributes,
|
||||
const unsigned AttributesAsWritten,
|
||||
TypeSourceInfo *T,
|
||||
QualType T,
|
||||
TypeSourceInfo *TSI,
|
||||
tok::ObjCKeywordKind MethodImplKind,
|
||||
DeclContext *lexicalDC = nullptr);
|
||||
|
||||
@ -7629,6 +7731,9 @@ class Sema {
|
||||
/// \brief Called on well-formed '\#pragma omp taskwait'.
|
||||
StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc,
|
||||
SourceLocation EndLoc);
|
||||
/// \brief Called on well-formed '\#pragma omp taskgroup'.
|
||||
StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc,
|
||||
SourceLocation EndLoc);
|
||||
/// \brief Called on well-formed '\#pragma omp flush'.
|
||||
StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
|
||||
SourceLocation StartLoc,
|
||||
@ -8557,9 +8662,10 @@ class Sema {
|
||||
const FunctionProtoType *Proto,
|
||||
SourceLocation Loc);
|
||||
|
||||
void checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args,
|
||||
unsigned NumParams, bool IsMemberFunction, SourceLocation Loc,
|
||||
SourceRange Range, VariadicCallType CallType);
|
||||
void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
|
||||
ArrayRef<const Expr *> Args, bool IsMemberFunction,
|
||||
SourceLocation Loc, SourceRange Range,
|
||||
VariadicCallType CallType);
|
||||
|
||||
bool CheckObjCString(Expr *Arg);
|
||||
|
||||
@ -8602,7 +8708,9 @@ class Sema {
|
||||
llvm::APSInt &Result);
|
||||
bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum,
|
||||
int Low, int High);
|
||||
|
||||
bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
|
||||
int ArgNum, unsigned ExpectedFieldNum,
|
||||
bool AllowName);
|
||||
public:
|
||||
enum FormatStringType {
|
||||
FST_Scanf,
|
||||
@ -8731,6 +8839,13 @@ class Sema {
|
||||
mutable IdentifierInfo *Ident_super;
|
||||
mutable IdentifierInfo *Ident___float128;
|
||||
|
||||
/// Nullability type specifiers.
|
||||
IdentifierInfo *Ident___nonnull = nullptr;
|
||||
IdentifierInfo *Ident___nullable = nullptr;
|
||||
IdentifierInfo *Ident___null_unspecified = nullptr;
|
||||
|
||||
IdentifierInfo *Ident_NSError = nullptr;
|
||||
|
||||
protected:
|
||||
friend class Parser;
|
||||
friend class InitializationSequence;
|
||||
@ -8739,6 +8854,15 @@ class Sema {
|
||||
friend class ASTWriter;
|
||||
|
||||
public:
|
||||
/// Retrieve the keyword associated
|
||||
IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability);
|
||||
|
||||
/// The struct behind the CFErrorRef pointer.
|
||||
RecordDecl *CFError = nullptr;
|
||||
|
||||
/// Retrieve the identifier "NSError".
|
||||
IdentifierInfo *getNSErrorIdent();
|
||||
|
||||
/// \brief Retrieve the parser's current scope.
|
||||
///
|
||||
/// This routine must only be used when it is certain that semantic analysis
|
||||
|
@ -1211,8 +1211,12 @@ namespace clang {
|
||||
EXPR_INIT_LIST,
|
||||
/// \brief A DesignatedInitExpr record.
|
||||
EXPR_DESIGNATED_INIT,
|
||||
/// \brief A DesignatedInitUpdateExpr record.
|
||||
EXPR_DESIGNATED_INIT_UPDATE,
|
||||
/// \brief An ImplicitValueInitExpr record.
|
||||
EXPR_IMPLICIT_VALUE_INIT,
|
||||
/// \brief An NoInitExpr record.
|
||||
EXPR_NO_INIT,
|
||||
/// \brief A VAArgExpr record.
|
||||
EXPR_VA_ARG,
|
||||
/// \brief An AddrLabelExpr record.
|
||||
@ -1392,6 +1396,7 @@ namespace clang {
|
||||
STMT_OMP_ATOMIC_DIRECTIVE,
|
||||
STMT_OMP_TARGET_DIRECTIVE,
|
||||
STMT_OMP_TEAMS_DIRECTIVE,
|
||||
STMT_OMP_TASKGROUP_DIRECTIVE,
|
||||
|
||||
// ARC
|
||||
EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
|
||||
|
@ -362,6 +362,7 @@ class ASTReader
|
||||
|
||||
SourceManager &SourceMgr;
|
||||
FileManager &FileMgr;
|
||||
const PCHContainerOperations &PCHContainerOps;
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
/// \brief The semantic analysis object that will be processing the
|
||||
@ -1237,6 +1238,9 @@ class ASTReader
|
||||
/// \param Context the AST context that this precompiled header will be
|
||||
/// loaded into.
|
||||
///
|
||||
/// \param PCHContainerOps the PCHContainerOperations to use for loading and
|
||||
/// creating modules.
|
||||
///
|
||||
/// \param isysroot If non-NULL, the system include path specified by the
|
||||
/// user. This is only used with relocatable PCH files. If non-NULL,
|
||||
/// a relocatable PCH file will use the default path "/".
|
||||
@ -1258,12 +1262,12 @@ class ASTReader
|
||||
///
|
||||
/// \param UseGlobalIndex If true, the AST reader will try to load and use
|
||||
/// the global module index.
|
||||
ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "",
|
||||
bool DisableValidation = false,
|
||||
ASTReader(Preprocessor &PP, ASTContext &Context,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
StringRef isysroot = "", bool DisableValidation = false,
|
||||
bool AllowASTWithCompilerErrors = false,
|
||||
bool AllowConfigurationMismatch = false,
|
||||
bool ValidateSystemInputs = false,
|
||||
bool UseGlobalIndex = true);
|
||||
bool ValidateSystemInputs = false, bool UseGlobalIndex = true);
|
||||
|
||||
~ASTReader() override;
|
||||
|
||||
@ -1425,21 +1429,23 @@ class ASTReader
|
||||
|
||||
/// \brief Retrieve the name of the original source file name directly from
|
||||
/// the AST file, without actually loading the AST file.
|
||||
static std::string getOriginalSourceFile(const std::string &ASTFileName,
|
||||
FileManager &FileMgr,
|
||||
DiagnosticsEngine &Diags);
|
||||
static std::string
|
||||
getOriginalSourceFile(const std::string &ASTFileName, FileManager &FileMgr,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
DiagnosticsEngine &Diags);
|
||||
|
||||
/// \brief Read the control block for the named AST file.
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
static bool readASTFileControlBlock(StringRef Filename,
|
||||
FileManager &FileMgr,
|
||||
ASTReaderListener &Listener);
|
||||
static bool
|
||||
readASTFileControlBlock(StringRef Filename, FileManager &FileMgr,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
ASTReaderListener &Listener);
|
||||
|
||||
/// \brief Determine whether the given AST file is acceptable to load into a
|
||||
/// translation unit with the given language and target options.
|
||||
static bool isAcceptableASTFile(StringRef Filename,
|
||||
FileManager &FileMgr,
|
||||
static bool isAcceptableASTFile(StringRef Filename, FileManager &FileMgr,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
const LangOptions &LangOpts,
|
||||
const TargetOptions &TargetOpts,
|
||||
const PreprocessorOptions &PPOpts,
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/AST/ASTMutationListener.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/Frontend/PCHContainerOperations.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/Sema/SemaConsumer.h"
|
||||
#include "clang/Serialization/ASTBitCodes.h"
|
||||
@ -868,30 +869,28 @@ class PCHGenerator : public SemaConsumer {
|
||||
std::string OutputFile;
|
||||
clang::Module *Module;
|
||||
std::string isysroot;
|
||||
raw_ostream *Out;
|
||||
Sema *SemaPtr;
|
||||
SmallVector<char, 128> Buffer;
|
||||
std::shared_ptr<PCHBuffer> Buffer;
|
||||
llvm::BitstreamWriter Stream;
|
||||
ASTWriter Writer;
|
||||
bool AllowASTWithErrors;
|
||||
bool HasEmittedPCH;
|
||||
|
||||
protected:
|
||||
ASTWriter &getWriter() { return Writer; }
|
||||
const ASTWriter &getWriter() const { return Writer; }
|
||||
SmallVectorImpl<char> &getPCH() const { return Buffer->Data; }
|
||||
|
||||
public:
|
||||
PCHGenerator(const Preprocessor &PP, StringRef OutputFile,
|
||||
clang::Module *Module,
|
||||
StringRef isysroot, raw_ostream *Out,
|
||||
clang::Module *Module, StringRef isysroot,
|
||||
std::shared_ptr<PCHBuffer> Buffer,
|
||||
bool AllowASTWithErrors = false);
|
||||
~PCHGenerator() override;
|
||||
void InitializeSema(Sema &S) override { SemaPtr = &S; }
|
||||
void HandleTranslationUnit(ASTContext &Ctx) override;
|
||||
ASTMutationListener *GetASTMutationListener() override;
|
||||
ASTDeserializationListener *GetASTDeserializationListener() override;
|
||||
|
||||
bool hasEmittedPCH() const { return HasEmittedPCH; }
|
||||
bool hasEmittedPCH() const { return Buffer->IsComplete; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -35,6 +35,7 @@ class DirectoryEntry;
|
||||
class FileEntry;
|
||||
class FileManager;
|
||||
class IdentifierIterator;
|
||||
class PCHContainerOperations;
|
||||
|
||||
namespace serialization {
|
||||
class ModuleFile;
|
||||
@ -192,10 +193,13 @@ class GlobalModuleIndex {
|
||||
/// \brief Write a global index into the given
|
||||
///
|
||||
/// \param FileMgr The file manager to use to load module files.
|
||||
///
|
||||
/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
|
||||
/// creating modules.
|
||||
/// \param Path The path to the directory containing module files, into
|
||||
/// which the global index will be written.
|
||||
static ErrorCode writeIndex(FileManager &FileMgr, StringRef Path);
|
||||
static ErrorCode writeIndex(FileManager &FileMgr,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
StringRef Path);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ namespace clang {
|
||||
|
||||
class GlobalModuleIndex;
|
||||
class ModuleMap;
|
||||
class PCHContainerOperations;
|
||||
|
||||
namespace serialization {
|
||||
|
||||
@ -49,7 +50,10 @@ class ModuleManager {
|
||||
/// \brief FileManager that handles translating between filenames and
|
||||
/// FileEntry *.
|
||||
FileManager &FileMgr;
|
||||
|
||||
|
||||
/// \brief Knows how to unwrap module containers.
|
||||
const PCHContainerOperations &PCHContainerOps;
|
||||
|
||||
/// \brief A lookup of in-memory (virtual file) buffers
|
||||
llvm::DenseMap<const FileEntry *, std::unique_ptr<llvm::MemoryBuffer>>
|
||||
InMemoryBuffers;
|
||||
@ -112,8 +116,9 @@ class ModuleManager {
|
||||
typedef SmallVectorImpl<ModuleFile*>::const_iterator ModuleConstIterator;
|
||||
typedef SmallVectorImpl<ModuleFile*>::reverse_iterator ModuleReverseIterator;
|
||||
typedef std::pair<uint32_t, StringRef> ModuleOffset;
|
||||
|
||||
explicit ModuleManager(FileManager &FileMgr);
|
||||
|
||||
explicit ModuleManager(FileManager &FileMgr,
|
||||
const PCHContainerOperations &PCHContainerOps);
|
||||
~ModuleManager();
|
||||
|
||||
/// \brief Forward iterator to traverse all loaded modules. This is reverse
|
||||
|
@ -69,6 +69,14 @@ enum ArgEffect {
|
||||
/// transfers the object to the Garbage Collector under GC.
|
||||
MakeCollectable,
|
||||
|
||||
/// The argument is a pointer to a retain-counted object; on exit, the new
|
||||
/// value of the pointer is a +0 value or NULL.
|
||||
UnretainedOutParameter,
|
||||
|
||||
/// The argument is a pointer to a retain-counted object; on exit, the new
|
||||
/// value of the pointer is a +1 value or NULL.
|
||||
RetainedOutParameter,
|
||||
|
||||
/// The argument is treated as potentially escaping, meaning that
|
||||
/// even when its reference count hits 0 it should be treated as still
|
||||
/// possibly being alive as someone else *may* be holding onto the object.
|
||||
|
@ -38,7 +38,9 @@ class RefactoringTool : public ClangTool {
|
||||
public:
|
||||
/// \see ClangTool::ClangTool.
|
||||
RefactoringTool(const CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> SourcePaths);
|
||||
ArrayRef<std::string> SourcePaths,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>());
|
||||
|
||||
/// \brief Returns the set of replacements to which replacements should
|
||||
/// be added during the run of the tool.
|
||||
|
@ -31,11 +31,13 @@
|
||||
#define LLVM_CLANG_TOOLING_TOOLING_H
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Frontend/PCHContainerOperations.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Driver/Util.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Lex/ModuleLoader.h"
|
||||
#include "clang/Tooling/ArgumentsAdjusters.h"
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
@ -66,9 +68,10 @@ class ToolAction {
|
||||
virtual ~ToolAction();
|
||||
|
||||
/// \brief Perform an action for an invocation.
|
||||
virtual bool runInvocation(clang::CompilerInvocation *Invocation,
|
||||
FileManager *Files,
|
||||
DiagnosticConsumer *DiagConsumer) = 0;
|
||||
virtual bool
|
||||
runInvocation(clang::CompilerInvocation *Invocation, FileManager *Files,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagConsumer) = 0;
|
||||
};
|
||||
|
||||
/// \brief Interface to generate clang::FrontendActions.
|
||||
@ -83,6 +86,7 @@ class FrontendActionFactory : public ToolAction {
|
||||
|
||||
/// \brief Invokes the compiler with a FrontendAction created by create().
|
||||
bool runInvocation(clang::CompilerInvocation *Invocation, FileManager *Files,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagConsumer) override;
|
||||
|
||||
/// \brief Returns a new clang::FrontendAction.
|
||||
@ -139,10 +143,14 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
|
||||
/// \param ToolAction The action to run over the code.
|
||||
/// \param Code C++ code.
|
||||
/// \param FileName The file name which 'Code' will be mapped as.
|
||||
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
|
||||
/// clang modules.
|
||||
///
|
||||
/// \return - True if 'ToolAction' was successfully executed.
|
||||
bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
|
||||
const Twine &FileName = "input.cc");
|
||||
const Twine &FileName = "input.cc",
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>());
|
||||
|
||||
/// The first part of the pair is the filename, the second part the
|
||||
/// file-content.
|
||||
@ -155,37 +163,48 @@ typedef std::vector<std::pair<std::string, std::string>> FileContentMappings;
|
||||
/// \param Code C++ code.
|
||||
/// \param Args Additional flags to pass on.
|
||||
/// \param FileName The file name which 'Code' will be mapped as.
|
||||
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
|
||||
/// clang modules.
|
||||
///
|
||||
/// \return - True if 'ToolAction' was successfully executed.
|
||||
bool runToolOnCodeWithArgs(
|
||||
clang::FrontendAction *ToolAction, const Twine &Code,
|
||||
const std::vector<std::string> &Args, const Twine &FileName = "input.cc",
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>(),
|
||||
const FileContentMappings &VirtualMappedFiles = FileContentMappings());
|
||||
|
||||
/// \brief Builds an AST for 'Code'.
|
||||
///
|
||||
/// \param Code C++ code.
|
||||
/// \param FileName The file name which 'Code' will be mapped as.
|
||||
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
|
||||
/// clang modules.
|
||||
///
|
||||
/// \return The resulting AST or null if an error occurred.
|
||||
std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code,
|
||||
const Twine &FileName = "input.cc");
|
||||
std::unique_ptr<ASTUnit>
|
||||
buildASTFromCode(const Twine &Code, const Twine &FileName = "input.cc",
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>());
|
||||
|
||||
/// \brief Builds an AST for 'Code' with additional flags.
|
||||
///
|
||||
/// \param Code C++ code.
|
||||
/// \param Args Additional flags to pass on.
|
||||
/// \param FileName The file name which 'Code' will be mapped as.
|
||||
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
|
||||
/// clang modules.
|
||||
///
|
||||
/// \return The resulting AST or null if an error occurred.
|
||||
std::unique_ptr<ASTUnit>
|
||||
buildASTFromCodeWithArgs(const Twine &Code,
|
||||
const std::vector<std::string> &Args,
|
||||
const Twine &FileName = "input.cc");
|
||||
std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
|
||||
const Twine &Code, const std::vector<std::string> &Args,
|
||||
const Twine &FileName = "input.cc",
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>());
|
||||
|
||||
/// \brief Utility to run a FrontendAction in a single clang invocation.
|
||||
class ToolInvocation {
|
||||
public:
|
||||
public:
|
||||
/// \brief Create a tool invocation.
|
||||
///
|
||||
/// \param CommandLine The command line arguments to clang. Note that clang
|
||||
@ -195,16 +214,23 @@ class ToolInvocation {
|
||||
/// \param FAction The action to be executed. Class takes ownership.
|
||||
/// \param Files The FileManager used for the execution. Class does not take
|
||||
/// ownership.
|
||||
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
|
||||
/// clang modules.
|
||||
ToolInvocation(std::vector<std::string> CommandLine, FrontendAction *FAction,
|
||||
FileManager *Files);
|
||||
FileManager *Files,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>());
|
||||
|
||||
/// \brief Create a tool invocation.
|
||||
///
|
||||
/// \param CommandLine The command line arguments to clang.
|
||||
/// \param Action The action to be executed.
|
||||
/// \param Files The FileManager used for the execution.
|
||||
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
|
||||
/// clang modules.
|
||||
ToolInvocation(std::vector<std::string> CommandLine, ToolAction *Action,
|
||||
FileManager *Files);
|
||||
FileManager *Files,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps);
|
||||
|
||||
~ToolInvocation();
|
||||
|
||||
@ -229,12 +255,14 @@ class ToolInvocation {
|
||||
|
||||
bool runInvocation(const char *BinaryName,
|
||||
clang::driver::Compilation *Compilation,
|
||||
clang::CompilerInvocation *Invocation);
|
||||
clang::CompilerInvocation *Invocation,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps);
|
||||
|
||||
std::vector<std::string> CommandLine;
|
||||
ToolAction *Action;
|
||||
bool OwnsAction;
|
||||
FileManager *Files;
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
|
||||
// Maps <file name> -> <file content>.
|
||||
llvm::StringMap<StringRef> MappedFileContents;
|
||||
DiagnosticConsumer *DiagConsumer;
|
||||
@ -255,8 +283,12 @@ class ClangTool {
|
||||
/// command lines for the given source paths.
|
||||
/// \param SourcePaths The source files to run over. If a source files is
|
||||
/// not found in Compilations, it is skipped.
|
||||
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
|
||||
/// clang modules.
|
||||
ClangTool(const CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> SourcePaths);
|
||||
ArrayRef<std::string> SourcePaths,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
|
||||
std::make_shared<RawPCHContainerOperations>());
|
||||
|
||||
~ClangTool();
|
||||
|
||||
@ -297,6 +329,7 @@ class ClangTool {
|
||||
private:
|
||||
const CompilationDatabase &Compilations;
|
||||
std::vector<std::string> SourcePaths;
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
|
||||
|
||||
llvm::IntrusiveRefCntPtr<FileManager> Files;
|
||||
// Contains a list of pairs (<file name>, <file content>).
|
||||
|
@ -166,7 +166,8 @@ static bool HasARCRuntime(CompilerInvocation &origCI) {
|
||||
}
|
||||
|
||||
static CompilerInvocation *
|
||||
createInvocationForMigration(CompilerInvocation &origCI) {
|
||||
createInvocationForMigration(CompilerInvocation &origCI,
|
||||
const PCHContainerOperations &PCHContainerOps) {
|
||||
std::unique_ptr<CompilerInvocation> CInvok;
|
||||
CInvok.reset(new CompilerInvocation(origCI));
|
||||
PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
|
||||
@ -178,9 +179,8 @@ createInvocationForMigration(CompilerInvocation &origCI) {
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
|
||||
new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
|
||||
new IgnoringDiagConsumer()));
|
||||
std::string OriginalFile =
|
||||
ASTReader::getOriginalSourceFile(PPOpts.ImplicitPCHInclude,
|
||||
FileMgr, *Diags);
|
||||
std::string OriginalFile = ASTReader::getOriginalSourceFile(
|
||||
PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerOps, *Diags);
|
||||
if (!OriginalFile.empty())
|
||||
PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
|
||||
PPOpts.ImplicitPCHInclude.clear();
|
||||
@ -230,11 +230,11 @@ static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
|
||||
// checkForManualIssues.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
bool emitPremigrationARCErrors,
|
||||
StringRef plistOut) {
|
||||
bool arcmt::checkForManualIssues(
|
||||
CompilerInvocation &origCI, const FrontendInputFile &Input,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors,
|
||||
StringRef plistOut) {
|
||||
if (!origCI.getLangOpts()->ObjC1)
|
||||
return false;
|
||||
|
||||
@ -247,7 +247,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
|
||||
assert(!transforms.empty());
|
||||
|
||||
std::unique_ptr<CompilerInvocation> CInvok;
|
||||
CInvok.reset(createInvocationForMigration(origCI));
|
||||
CInvok.reset(createInvocationForMigration(origCI, *PCHContainerOps));
|
||||
CInvok->getFrontendOpts().Inputs.clear();
|
||||
CInvok->getFrontendOpts().Inputs.push_back(Input);
|
||||
|
||||
@ -263,8 +263,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
|
||||
CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
|
||||
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
|
||||
|
||||
std::unique_ptr<ASTUnit> Unit(
|
||||
ASTUnit::LoadFromCompilerInvocationAction(CInvok.release(), Diags));
|
||||
std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
|
||||
CInvok.release(), PCHContainerOps, Diags));
|
||||
if (!Unit) {
|
||||
errRec.FinishCapture();
|
||||
return true;
|
||||
@ -330,12 +330,11 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
|
||||
// applyTransformations.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static bool applyTransforms(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
StringRef plistOut) {
|
||||
static bool
|
||||
applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagClient, StringRef outputDir,
|
||||
bool emitPremigrationARCErrors, StringRef plistOut) {
|
||||
if (!origCI.getLangOpts()->ObjC1)
|
||||
return false;
|
||||
|
||||
@ -343,15 +342,16 @@ static bool applyTransforms(CompilerInvocation &origCI,
|
||||
|
||||
// Make sure checking is successful first.
|
||||
CompilerInvocation CInvokForCheck(origCI);
|
||||
if (arcmt::checkForManualIssues(CInvokForCheck, Input, DiagClient,
|
||||
emitPremigrationARCErrors, plistOut))
|
||||
if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps,
|
||||
DiagClient, emitPremigrationARCErrors,
|
||||
plistOut))
|
||||
return true;
|
||||
|
||||
CompilerInvocation CInvok(origCI);
|
||||
CInvok.getFrontendOpts().Inputs.clear();
|
||||
CInvok.getFrontendOpts().Inputs.push_back(Input);
|
||||
|
||||
MigrationProcess migration(CInvok, DiagClient, outputDir);
|
||||
|
||||
MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
|
||||
bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
|
||||
|
||||
std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
|
||||
@ -376,22 +376,22 @@ static bool applyTransforms(CompilerInvocation &origCI,
|
||||
}
|
||||
}
|
||||
|
||||
bool arcmt::applyTransformations(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient) {
|
||||
return applyTransforms(origCI, Input, DiagClient,
|
||||
bool arcmt::applyTransformations(
|
||||
CompilerInvocation &origCI, const FrontendInputFile &Input,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagClient) {
|
||||
return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
|
||||
StringRef(), false, StringRef());
|
||||
}
|
||||
|
||||
bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
const FrontendInputFile &Input,
|
||||
DiagnosticConsumer *DiagClient,
|
||||
StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
StringRef plistOut) {
|
||||
bool arcmt::migrateWithTemporaryFiles(
|
||||
CompilerInvocation &origCI, const FrontendInputFile &Input,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *DiagClient, StringRef outputDir,
|
||||
bool emitPremigrationARCErrors, StringRef plistOut) {
|
||||
assert(!outputDir.empty() && "Expected output directory path");
|
||||
return applyTransforms(origCI, Input, DiagClient,
|
||||
outputDir, emitPremigrationARCErrors, plistOut);
|
||||
return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
|
||||
emitPremigrationARCErrors, plistOut);
|
||||
}
|
||||
|
||||
bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
|
||||
@ -499,10 +499,12 @@ class RewritesApplicator : public TransformActions::RewriteReceiver {
|
||||
/// \brief Anchor for VTable.
|
||||
MigrationProcess::RewriteListener::~RewriteListener() { }
|
||||
|
||||
MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
|
||||
DiagnosticConsumer *diagClient,
|
||||
StringRef outputDir)
|
||||
: OrigCI(CI), DiagClient(diagClient), HadARCErrors(false) {
|
||||
MigrationProcess::MigrationProcess(
|
||||
const CompilerInvocation &CI,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
DiagnosticConsumer *diagClient, StringRef outputDir)
|
||||
: OrigCI(CI), PCHContainerOps(PCHContainerOps), DiagClient(diagClient),
|
||||
HadARCErrors(false) {
|
||||
if (!outputDir.empty()) {
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
|
||||
@ -515,7 +517,7 @@ MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
|
||||
bool MigrationProcess::applyTransform(TransformFn trans,
|
||||
RewriteListener *listener) {
|
||||
std::unique_ptr<CompilerInvocation> CInvok;
|
||||
CInvok.reset(createInvocationForMigration(OrigCI));
|
||||
CInvok.reset(createInvocationForMigration(OrigCI, *PCHContainerOps));
|
||||
CInvok->getDiagnosticOpts().IgnoreWarnings = true;
|
||||
|
||||
Remapper.applyMappings(CInvok->getPreprocessorOpts());
|
||||
@ -537,7 +539,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
|
||||
ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
|
||||
|
||||
std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
|
||||
CInvok.release(), Diags, ASTAction.get()));
|
||||
CInvok.release(), PCHContainerOps, Diags, ASTAction.get()));
|
||||
if (!Unit) {
|
||||
errRec.FinishCapture();
|
||||
return true;
|
||||
|
@ -16,6 +16,7 @@ using namespace arcmt;
|
||||
|
||||
bool CheckAction::BeginInvocation(CompilerInstance &CI) {
|
||||
if (arcmt::checkForManualIssues(CI.getInvocation(), getCurrentInput(),
|
||||
CI.getPCHContainerOperations(),
|
||||
CI.getDiagnostics().getClient()))
|
||||
return false; // errors, stop the action.
|
||||
|
||||
@ -29,6 +30,7 @@ CheckAction::CheckAction(FrontendAction *WrappedAction)
|
||||
|
||||
bool ModifyAction::BeginInvocation(CompilerInstance &CI) {
|
||||
return !arcmt::applyTransformations(CI.getInvocation(), getCurrentInput(),
|
||||
CI.getPCHContainerOperations(),
|
||||
CI.getDiagnostics().getClient());
|
||||
}
|
||||
|
||||
@ -36,12 +38,10 @@ ModifyAction::ModifyAction(FrontendAction *WrappedAction)
|
||||
: WrapperFrontendAction(WrappedAction) {}
|
||||
|
||||
bool MigrateAction::BeginInvocation(CompilerInstance &CI) {
|
||||
if (arcmt::migrateWithTemporaryFiles(CI.getInvocation(),
|
||||
getCurrentInput(),
|
||||
CI.getDiagnostics().getClient(),
|
||||
MigrateDir,
|
||||
EmitPremigrationARCErros,
|
||||
PlistOut))
|
||||
if (arcmt::migrateWithTemporaryFiles(
|
||||
CI.getInvocation(), getCurrentInput(), CI.getPCHContainerOperations(),
|
||||
CI.getDiagnostics().getClient(), MigrateDir, EmitPremigrationARCErros,
|
||||
PlistOut))
|
||||
return false; // errors, stop the action.
|
||||
|
||||
// We only want to see diagnostics emitted by migrateWithTemporaryFiles.
|
||||
|
@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "llvm/Bitcode/BitstreamReader.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
using namespace clang;
|
||||
|
@ -5610,8 +5610,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||
// @encode(class_name)
|
||||
ObjCInterfaceDecl *OI = OIT->getDecl();
|
||||
S += '{';
|
||||
const IdentifierInfo *II = OI->getIdentifier();
|
||||
S += II->getName();
|
||||
S += OI->getObjCRuntimeNameAsString();
|
||||
S += '=';
|
||||
SmallVector<const ObjCIvarDecl*, 32> Ivars;
|
||||
DeepCollectObjCIvars(OI, true, Ivars);
|
||||
@ -5654,7 +5653,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||
S += '"';
|
||||
for (const auto *I : OPT->quals()) {
|
||||
S += '<';
|
||||
S += I->getNameAsString();
|
||||
S += I->getObjCRuntimeNameAsString();
|
||||
S += '>';
|
||||
}
|
||||
S += '"';
|
||||
@ -5678,7 +5677,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||
for (unsigned i = 0, e = Ivars.size(); i != e; ++i) {
|
||||
if (cast<FieldDecl>(Ivars[i]) == FD) {
|
||||
S += '{';
|
||||
S += OI->getIdentifier()->getName();
|
||||
S += OI->getObjCRuntimeNameAsString();
|
||||
S += '}';
|
||||
return;
|
||||
}
|
||||
@ -5696,10 +5695,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||
if (OPT->getInterfaceDecl() &&
|
||||
(FD || EncodingProperty || EncodeClassNames)) {
|
||||
S += '"';
|
||||
S += OPT->getInterfaceDecl()->getIdentifier()->getName();
|
||||
S += OPT->getInterfaceDecl()->getObjCRuntimeNameAsString();
|
||||
for (const auto *I : OPT->quals()) {
|
||||
S += '<';
|
||||
S += I->getNameAsString();
|
||||
S += I->getObjCRuntimeNameAsString();
|
||||
S += '>';
|
||||
}
|
||||
S += '"';
|
||||
|
@ -3922,8 +3922,8 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
|
||||
}
|
||||
|
||||
// Import the type.
|
||||
TypeSourceInfo *T = Importer.Import(D->getTypeSourceInfo());
|
||||
if (!T)
|
||||
TypeSourceInfo *TSI = Importer.Import(D->getTypeSourceInfo());
|
||||
if (!TSI)
|
||||
return nullptr;
|
||||
|
||||
// Create the new property.
|
||||
@ -3932,7 +3932,8 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
|
||||
Name.getAsIdentifierInfo(),
|
||||
Importer.Import(D->getAtLoc()),
|
||||
Importer.Import(D->getLParenLoc()),
|
||||
T,
|
||||
Importer.Import(D->getType()),
|
||||
TSI,
|
||||
D->getPropertyImplementation());
|
||||
Importer.Imported(D, ToProperty);
|
||||
ToProperty->setLexicalDeclContext(LexicalDC);
|
||||
|
@ -3681,7 +3681,8 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
|
||||
|
||||
bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
|
||||
ASTContext &Context = getASTContext();
|
||||
if (!Context.getLangOpts().Sanitize.has(SanitizerKind::Address) ||
|
||||
if (!Context.getLangOpts().Sanitize.hasOneOf(
|
||||
SanitizerKind::Address | SanitizerKind::KernelAddress) ||
|
||||
!Context.getLangOpts().SanitizeAddressFieldPadding)
|
||||
return false;
|
||||
const auto &Blacklist = Context.getSanitizerBlacklist();
|
||||
|
@ -1862,16 +1862,18 @@ ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
IdentifierInfo *Id,
|
||||
SourceLocation AtLoc,
|
||||
SourceLocation LParenLoc,
|
||||
TypeSourceInfo *T,
|
||||
QualType T,
|
||||
TypeSourceInfo *TSI,
|
||||
PropertyControl propControl) {
|
||||
return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T);
|
||||
return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T, TSI,
|
||||
propControl);
|
||||
}
|
||||
|
||||
ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
|
||||
unsigned ID) {
|
||||
return new (C, ID) ObjCPropertyDecl(nullptr, SourceLocation(), nullptr,
|
||||
SourceLocation(), SourceLocation(),
|
||||
nullptr);
|
||||
QualType(), nullptr, None);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -37,6 +37,13 @@ namespace {
|
||||
|
||||
void Print(AccessSpecifier AS);
|
||||
|
||||
/// Print an Objective-C method type in parentheses.
|
||||
///
|
||||
/// \param Quals The Objective-C declaration qualifiers.
|
||||
/// \param T The type to print.
|
||||
void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
|
||||
QualType T);
|
||||
|
||||
public:
|
||||
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0, bool PrintInstantiation = false)
|
||||
@ -930,24 +937,52 @@ void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||
// Objective-C declarations
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
|
||||
Decl::ObjCDeclQualifier Quals,
|
||||
QualType T) {
|
||||
Out << '(';
|
||||
if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_In)
|
||||
Out << "in ";
|
||||
if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Inout)
|
||||
Out << "inout ";
|
||||
if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Out)
|
||||
Out << "out ";
|
||||
if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Bycopy)
|
||||
Out << "bycopy ";
|
||||
if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Byref)
|
||||
Out << "byref ";
|
||||
if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Oneway)
|
||||
Out << "oneway ";
|
||||
if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_CSNullability) {
|
||||
if (auto nullability = AttributedType::stripOuterNullability(T)) {
|
||||
Out << getNullabilitySpelling(*nullability).substr(2) << ' ';
|
||||
}
|
||||
}
|
||||
|
||||
Out << Ctx.getUnqualifiedObjCPointerType(T).getAsString(Policy);
|
||||
Out << ')';
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
|
||||
if (OMD->isInstanceMethod())
|
||||
Out << "- ";
|
||||
else
|
||||
Out << "+ ";
|
||||
if (!OMD->getReturnType().isNull())
|
||||
Out << '(' << OMD->getASTContext()
|
||||
.getUnqualifiedObjCPointerType(OMD->getReturnType())
|
||||
.getAsString(Policy) << ")";
|
||||
if (!OMD->getReturnType().isNull()) {
|
||||
PrintObjCMethodType(OMD->getASTContext(), OMD->getObjCDeclQualifier(),
|
||||
OMD->getReturnType());
|
||||
}
|
||||
|
||||
std::string name = OMD->getSelector().getAsString();
|
||||
std::string::size_type pos, lastPos = 0;
|
||||
for (const auto *PI : OMD->params()) {
|
||||
// FIXME: selector is missing here!
|
||||
pos = name.find_first_of(':', lastPos);
|
||||
Out << " " << name.substr(lastPos, pos - lastPos);
|
||||
Out << ":(" << PI->getASTContext().getUnqualifiedObjCPointerType(PI->getType()).
|
||||
getAsString(Policy) << ')' << *PI;
|
||||
Out << " " << name.substr(lastPos, pos - lastPos) << ':';
|
||||
PrintObjCMethodType(OMD->getASTContext(),
|
||||
PI->getObjCDeclQualifier(),
|
||||
PI->getType());
|
||||
Out << *PI;
|
||||
lastPos = pos + 1;
|
||||
}
|
||||
|
||||
@ -1103,6 +1138,8 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
|
||||
else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
|
||||
Out << "@optional\n";
|
||||
|
||||
QualType T = PDecl->getType();
|
||||
|
||||
Out << "@property";
|
||||
if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
|
||||
bool first = true;
|
||||
@ -1161,10 +1198,25 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_nullability) {
|
||||
if (auto nullability = AttributedType::stripOuterNullability(T)) {
|
||||
if (*nullability == NullabilityKind::Unspecified &&
|
||||
(PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_null_resettable)) {
|
||||
Out << (first ? ' ' : ',') << "null_resettable";
|
||||
} else {
|
||||
Out << (first ? ' ' : ',')
|
||||
<< getNullabilitySpelling(*nullability).substr(2);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
(void) first; // Silence dead store warning due to idiomatic code.
|
||||
Out << " )";
|
||||
}
|
||||
Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(PDecl->getType()).
|
||||
Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(T).
|
||||
getAsString(Policy) << ' ' << *PDecl;
|
||||
if (Policy.PolishForDeclaration)
|
||||
Out << ';';
|
||||
|
@ -124,6 +124,12 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
|
||||
}
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
void *allocateDefaultArgStorageChain(const ASTContext &C) {
|
||||
return new (C) char[sizeof(void*) * 2];
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// RedeclarableTemplateDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -504,14 +510,14 @@ TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
|
||||
|
||||
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
|
||||
return hasDefaultArgument()
|
||||
? DefaultArgument->getTypeLoc().getBeginLoc()
|
||||
: SourceLocation();
|
||||
? getDefaultArgumentInfo()->getTypeLoc().getBeginLoc()
|
||||
: SourceLocation();
|
||||
}
|
||||
|
||||
SourceRange TemplateTypeParmDecl::getSourceRange() const {
|
||||
if (hasDefaultArgument() && !defaultArgumentWasInherited())
|
||||
return SourceRange(getLocStart(),
|
||||
DefaultArgument->getTypeLoc().getEndLoc());
|
||||
getDefaultArgumentInfo()->getTypeLoc().getEndLoc());
|
||||
else
|
||||
return TypeDecl::getSourceRange();
|
||||
}
|
||||
@ -543,10 +549,8 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC,
|
||||
unsigned NumExpandedTypes,
|
||||
TypeSourceInfo **ExpandedTInfos)
|
||||
: DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
|
||||
TemplateParmPosition(D, P), DefaultArgumentAndInherited(nullptr, false),
|
||||
ParameterPack(true), ExpandedParameterPack(true),
|
||||
NumExpandedTypes(NumExpandedTypes)
|
||||
{
|
||||
TemplateParmPosition(D, P), ParameterPack(true),
|
||||
ExpandedParameterPack(true), NumExpandedTypes(NumExpandedTypes) {
|
||||
if (ExpandedTypes && ExpandedTInfos) {
|
||||
void **TypesAndInfos = reinterpret_cast<void **>(this + 1);
|
||||
for (unsigned I = 0; I != NumExpandedTypes; ++I) {
|
||||
@ -621,8 +625,7 @@ TemplateTemplateParmDecl::TemplateTemplateParmDecl(
|
||||
IdentifierInfo *Id, TemplateParameterList *Params,
|
||||
unsigned NumExpansions, TemplateParameterList * const *Expansions)
|
||||
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
|
||||
TemplateParmPosition(D, P), DefaultArgument(),
|
||||
DefaultArgumentWasInherited(false), ParameterPack(true),
|
||||
TemplateParmPosition(D, P), ParameterPack(true),
|
||||
ExpandedParameterPack(true), NumExpandedParams(NumExpansions) {
|
||||
if (Expansions)
|
||||
std::memcpy(reinterpret_cast<void*>(this + 1), Expansions,
|
||||
@ -663,6 +666,19 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
|
||||
nullptr, NumExpansions, nullptr);
|
||||
}
|
||||
|
||||
SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
|
||||
return hasDefaultArgument() ? getDefaultArgument().getLocation()
|
||||
: SourceLocation();
|
||||
}
|
||||
|
||||
void TemplateTemplateParmDecl::setDefaultArgument(
|
||||
const ASTContext &C, const TemplateArgumentLoc &DefArg) {
|
||||
if (DefArg.getArgument().isNull())
|
||||
DefaultArgument.set(nullptr);
|
||||
else
|
||||
DefaultArgument.set(new (C) TemplateArgumentLoc(DefArg));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TemplateArgumentList Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1238,7 +1238,7 @@ unsigned CallExpr::getBuiltinCallee() const {
|
||||
return FDecl->getBuiltinID();
|
||||
}
|
||||
|
||||
bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const {
|
||||
bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const {
|
||||
if (unsigned BI = getBuiltinCallee())
|
||||
return Ctx.BuiltinInfo.isUnevaluated(BI);
|
||||
return false;
|
||||
@ -2772,6 +2772,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
|
||||
const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
|
||||
return Exp->isConstantInitializer(Ctx, false, Culprit);
|
||||
}
|
||||
case DesignatedInitUpdateExprClass: {
|
||||
const DesignatedInitUpdateExpr *DIUE = cast<DesignatedInitUpdateExpr>(this);
|
||||
return DIUE->getBase()->isConstantInitializer(Ctx, false, Culprit) &&
|
||||
DIUE->getUpdater()->isConstantInitializer(Ctx, false, Culprit);
|
||||
}
|
||||
case InitListExprClass: {
|
||||
const InitListExpr *ILE = cast<InitListExpr>(this);
|
||||
if (ILE->getType()->isArrayType()) {
|
||||
@ -2818,6 +2823,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
|
||||
break;
|
||||
}
|
||||
case ImplicitValueInitExprClass:
|
||||
case NoInitExprClass:
|
||||
return true;
|
||||
case ParenExprClass:
|
||||
return cast<ParenExpr>(this)->getSubExpr()
|
||||
@ -2881,6 +2887,28 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// \brief Look for any side effects within a Stmt.
|
||||
class SideEffectFinder : public ConstEvaluatedExprVisitor<SideEffectFinder> {
|
||||
typedef ConstEvaluatedExprVisitor<SideEffectFinder> Inherited;
|
||||
const bool IncludePossibleEffects;
|
||||
bool HasSideEffects;
|
||||
|
||||
public:
|
||||
explicit SideEffectFinder(const ASTContext &Context, bool IncludePossible)
|
||||
: Inherited(Context),
|
||||
IncludePossibleEffects(IncludePossible), HasSideEffects(false) { }
|
||||
|
||||
bool hasSideEffects() const { return HasSideEffects; }
|
||||
|
||||
void VisitExpr(const Expr *E) {
|
||||
if (!HasSideEffects &&
|
||||
E->HasSideEffects(Context, IncludePossibleEffects))
|
||||
HasSideEffects = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
bool IncludePossibleEffects) const {
|
||||
// In circumstances where we care about definite side effects instead of
|
||||
@ -2925,6 +2953,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
case UnaryExprOrTypeTraitExprClass:
|
||||
case AddrLabelExprClass:
|
||||
case GNUNullExprClass:
|
||||
case NoInitExprClass:
|
||||
case CXXBoolLiteralExprClass:
|
||||
case CXXNullPtrLiteralExprClass:
|
||||
case CXXThisExprClass:
|
||||
@ -2967,7 +2996,6 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
case CompoundAssignOperatorClass:
|
||||
case VAArgExprClass:
|
||||
case AtomicExprClass:
|
||||
case StmtExprClass:
|
||||
case CXXThrowExprClass:
|
||||
case CXXNewExprClass:
|
||||
case CXXDeleteExprClass:
|
||||
@ -2975,6 +3003,13 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
// These always have a side-effect.
|
||||
return true;
|
||||
|
||||
case StmtExprClass: {
|
||||
// StmtExprs have a side-effect if any substatement does.
|
||||
SideEffectFinder Finder(Ctx, IncludePossibleEffects);
|
||||
Finder.Visit(cast<StmtExpr>(this)->getSubStmt());
|
||||
return Finder.hasSideEffects();
|
||||
}
|
||||
|
||||
case ParenExprClass:
|
||||
case ArraySubscriptExprClass:
|
||||
case MemberExprClass:
|
||||
@ -2983,6 +3018,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
case CompoundLiteralExprClass:
|
||||
case ExtVectorElementExprClass:
|
||||
case DesignatedInitExprClass:
|
||||
case DesignatedInitUpdateExprClass:
|
||||
case ParenListExprClass:
|
||||
case CXXPseudoDestructorExprClass:
|
||||
case CXXStdInitializerListExprClass:
|
||||
@ -3128,21 +3164,21 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
|
||||
namespace {
|
||||
/// \brief Look for a call to a non-trivial function within an expression.
|
||||
class NonTrivialCallFinder : public EvaluatedExprVisitor<NonTrivialCallFinder>
|
||||
class NonTrivialCallFinder : public ConstEvaluatedExprVisitor<NonTrivialCallFinder>
|
||||
{
|
||||
typedef EvaluatedExprVisitor<NonTrivialCallFinder> Inherited;
|
||||
|
||||
typedef ConstEvaluatedExprVisitor<NonTrivialCallFinder> Inherited;
|
||||
|
||||
bool NonTrivial;
|
||||
|
||||
public:
|
||||
explicit NonTrivialCallFinder(ASTContext &Context)
|
||||
explicit NonTrivialCallFinder(const ASTContext &Context)
|
||||
: Inherited(Context), NonTrivial(false) { }
|
||||
|
||||
bool hasNonTrivialCall() const { return NonTrivial; }
|
||||
|
||||
void VisitCallExpr(CallExpr *E) {
|
||||
if (CXXMethodDecl *Method
|
||||
= dyn_cast_or_null<CXXMethodDecl>(E->getCalleeDecl())) {
|
||||
|
||||
void VisitCallExpr(const CallExpr *E) {
|
||||
if (const CXXMethodDecl *Method
|
||||
= dyn_cast_or_null<const CXXMethodDecl>(E->getCalleeDecl())) {
|
||||
if (Method->isTrivial()) {
|
||||
// Recurse to children of the call.
|
||||
Inherited::VisitStmt(E);
|
||||
@ -3152,8 +3188,8 @@ namespace {
|
||||
|
||||
NonTrivial = true;
|
||||
}
|
||||
|
||||
void VisitCXXConstructExpr(CXXConstructExpr *E) {
|
||||
|
||||
void VisitCXXConstructExpr(const CXXConstructExpr *E) {
|
||||
if (E->getConstructor()->isTrivial()) {
|
||||
// Recurse to children of the call.
|
||||
Inherited::VisitStmt(E);
|
||||
@ -3162,8 +3198,8 @@ namespace {
|
||||
|
||||
NonTrivial = true;
|
||||
}
|
||||
|
||||
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
|
||||
|
||||
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) {
|
||||
if (E->getTemporary()->getDestructor()->isTrivial()) {
|
||||
Inherited::VisitStmt(E);
|
||||
return;
|
||||
@ -3174,7 +3210,7 @@ namespace {
|
||||
};
|
||||
}
|
||||
|
||||
bool Expr::hasNonTrivialCall(ASTContext &Ctx) {
|
||||
bool Expr::hasNonTrivialCall(const ASTContext &Ctx) const {
|
||||
NonTrivialCallFinder Finder(Ctx);
|
||||
Finder.Visit(this);
|
||||
return Finder.hasNonTrivialCall();
|
||||
@ -3989,6 +4025,25 @@ void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx,
|
||||
NumDesignators = NumDesignators - 1 + NumNewDesignators;
|
||||
}
|
||||
|
||||
DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C,
|
||||
SourceLocation lBraceLoc, Expr *baseExpr, SourceLocation rBraceLoc)
|
||||
: Expr(DesignatedInitUpdateExprClass, baseExpr->getType(), VK_RValue,
|
||||
OK_Ordinary, false, false, false, false) {
|
||||
BaseAndUpdaterExprs[0] = baseExpr;
|
||||
|
||||
InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, None, rBraceLoc);
|
||||
ILE->setType(baseExpr->getType());
|
||||
BaseAndUpdaterExprs[1] = ILE;
|
||||
}
|
||||
|
||||
SourceLocation DesignatedInitUpdateExpr::getLocStart() const {
|
||||
return getBase()->getLocStart();
|
||||
}
|
||||
|
||||
SourceLocation DesignatedInitUpdateExpr::getLocEnd() const {
|
||||
return getBase()->getLocEnd();
|
||||
}
|
||||
|
||||
ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
|
||||
ArrayRef<Expr*> exprs,
|
||||
SourceLocation rparenloc)
|
||||
|
@ -183,6 +183,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
||||
case Expr::ObjCIndirectCopyRestoreExprClass:
|
||||
case Expr::AtomicExprClass:
|
||||
case Expr::CXXFoldExprClass:
|
||||
case Expr::NoInitExprClass:
|
||||
case Expr::DesignatedInitUpdateExprClass:
|
||||
return Cl::CL_PRValue;
|
||||
|
||||
// Next come the complicated cases.
|
||||
|
@ -8675,6 +8675,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
|
||||
case Expr::CompoundLiteralExprClass:
|
||||
case Expr::ExtVectorElementExprClass:
|
||||
case Expr::DesignatedInitExprClass:
|
||||
case Expr::NoInitExprClass:
|
||||
case Expr::DesignatedInitUpdateExprClass:
|
||||
case Expr::ImplicitValueInitExprClass:
|
||||
case Expr::ParenListExprClass:
|
||||
case Expr::VAArgExprClass:
|
||||
|
@ -2010,7 +2010,11 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
|
||||
case BuiltinType::Half: Out << "Dh"; break;
|
||||
case BuiltinType::Float: Out << 'f'; break;
|
||||
case BuiltinType::Double: Out << 'd'; break;
|
||||
case BuiltinType::LongDouble: Out << 'e'; break;
|
||||
case BuiltinType::LongDouble:
|
||||
Out << (getASTContext().getTargetInfo().useFloat128ManglingForLongDouble()
|
||||
? 'g'
|
||||
: 'e');
|
||||
break;
|
||||
case BuiltinType::NullPtr: Out << "Dn"; break;
|
||||
|
||||
#define BUILTIN_TYPE(Id, SingletonId)
|
||||
@ -2676,7 +2680,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
|
||||
// These all can only appear in local or variable-initialization
|
||||
// contexts and so should never appear in a mangling.
|
||||
case Expr::AddrLabelExprClass:
|
||||
case Expr::DesignatedInitUpdateExprClass:
|
||||
case Expr::ImplicitValueInitExprClass:
|
||||
case Expr::NoInitExprClass:
|
||||
case Expr::ParenListExprClass:
|
||||
case Expr::LambdaExprClass:
|
||||
case Expr::MSPropertyRefExprClass:
|
||||
@ -4060,8 +4066,7 @@ void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
|
||||
|
||||
void ItaniumMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD,
|
||||
raw_ostream &Out) {
|
||||
Linkage L = RD->getLinkageInternal();
|
||||
if (L == InternalLinkage || L == UniqueExternalLinkage) {
|
||||
if (!RD->isExternallyVisible()) {
|
||||
// This part of the identifier needs to be unique across all translation
|
||||
// units in the linked program. The scheme fails if multiple translation
|
||||
// units are compiled using the same relative source file path, or if
|
||||
|
@ -179,8 +179,9 @@ MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const {
|
||||
// // slot.
|
||||
// void *FunctionPointerOrVirtualThunk;
|
||||
//
|
||||
// // An offset to add to the address of the vbtable pointer after (possibly)
|
||||
// // selecting the virtual base but before resolving and calling the function.
|
||||
// // An offset to add to the address of the vbtable pointer after
|
||||
// // (possibly) selecting the virtual base but before resolving and calling
|
||||
// // the function.
|
||||
// // Only needed if the class has any virtual bases or bases at a non-zero
|
||||
// // offset.
|
||||
// int NonVirtualBaseAdjustment;
|
||||
|
@ -2761,7 +2761,17 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
|
||||
|
||||
void MicrosoftMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD,
|
||||
raw_ostream &Out) {
|
||||
llvm::report_fatal_error("Cannot mangle bitsets yet");
|
||||
if (!RD->isExternallyVisible()) {
|
||||
// This part of the identifier needs to be unique across all translation
|
||||
// units in the linked program. The scheme fails if multiple translation
|
||||
// units are compiled using the same relative source file path, or if
|
||||
// multiple translation units are built from the same source file.
|
||||
SourceManager &SM = getASTContext().getSourceManager();
|
||||
Out << "[" << SM.getFileEntryForID(SM.getMainFileID())->getName() << "]";
|
||||
}
|
||||
|
||||
MicrosoftCXXNameMangler mangler(*this, Out);
|
||||
mangler.mangleName(RD);
|
||||
}
|
||||
|
||||
MicrosoftMangleContext *
|
||||
|
@ -1467,7 +1467,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
|
||||
// ms_struct basically requests a complete replacement of the
|
||||
// platform ABI's struct-layout algorithm, with the high-level goal
|
||||
// of duplicating MSVC's layout. For non-bitfields, this follows
|
||||
// the the standard algorithm. The basic bitfield layout rule is to
|
||||
// the standard algorithm. The basic bitfield layout rule is to
|
||||
// allocate an entire unit of the bitfield's declared type
|
||||
// (e.g. 'unsigned long'), then parcel it up among successive
|
||||
// bitfields whose declared types have the same size, making a new
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user